Skip to content

Commit f3404cf

Browse files
authored
Merge pull request #1149 from oliver-sanders/view-toolbar-tests
View toolbar: tests
2 parents ab19155 + 58d7a41 commit f3404cf

File tree

8 files changed

+338
-10
lines changed

8 files changed

+338
-10
lines changed

.eslintrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ module.exports = {
2323
extends: [
2424
'standard',
2525
'eslint:recommended',
26-
'plugin:vue/essential'
26+
'plugin:vue/essential',
27+
'plugin:cypress/recommended'
2728
],
2829
rules: {
2930
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',

.github/workflows/main.yml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,16 @@ jobs:
5858
include:
5959
- os: ubuntu-20.04
6060
browser: firefox
61+
type: 'e2e'
62+
- os: ubuntu-20.04
63+
browser: firefox
64+
type: 'component'
6165
- os: ubuntu-latest
6266
browser: chrome
67+
type: 'e2e'
68+
- os: ubuntu-latest
69+
browser: chrome
70+
type: 'component'
6371
# TODO: re-enable once macos build is stable #590
6472
# - os: macos-latest
6573
# browser: edge
@@ -72,13 +80,17 @@ jobs:
7280
with:
7381
node-version: '16'
7482

75-
- name: e2e
83+
- name: Test
7684
uses: cypress-io/github-action@v4
7785
with:
7886
start: yarn run serve --hide=CLIENT # turn off build output because it's absurdly long
7987
wait-on: http://localhost:8080/
8088
config-file: cypress.config.js
81-
spec: "tests/e2e/**/*"
89+
component: ${{ matrix.type == 'component' }}
90+
spec: |
91+
tests/e2e/**/*
92+
cypress/component/*
93+
cypress/component/**/*
8294
browser: ${{ matrix.browser }}
8395
env:
8496
CYPRESS_baseUrl: http://localhost:8080/
@@ -94,6 +106,6 @@ jobs:
94106
with:
95107
token: ${{ secrets.CODECOV_TOKEN }}
96108
file: ./coverage/lcov.info
97-
name: '${{ github.job }} ${{ matrix.os }} ${{ matrix.browser }}'
98-
flags: e2e
109+
name: '${{ github.job }} ${{ matrix.os }} ${{ matrix.browser }} ${{ matrix.type }}'
110+
flags: ${{ matrix.type }}
99111
fail_ci_if_error: false
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/**
2+
* Copyright (C) NIWA & British Crown (Met Office) & Contributors.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
import {
19+
mdiCog,
20+
mdiGestureTap,
21+
mdiToggleSwitch
22+
} from '@mdi/js'
23+
import ViewToolbar from '@/components/cylc/ViewToolbar'
24+
25+
describe('View Toolbar Component', () => {
26+
const mountToolbar = (groups) => {
27+
// configure a listener for toggle events
28+
const setOption = cy.spy().as('setOptionSpy')
29+
30+
// mount 'em
31+
cy.vmount(
32+
ViewToolbar,
33+
{
34+
propsData: { groups },
35+
listeners: { setOption }
36+
}
37+
)
38+
// add the classes Vuetify requires
39+
cy.addVuetifyStyles(cy)
40+
41+
return setOption
42+
}
43+
44+
it('loads, toggles and runs callbacks ', () => {
45+
// set up a handler for callback events
46+
const callbacks = []
47+
function myCallback () {
48+
callbacks.push(true)
49+
}
50+
51+
// mount the toolbar with a couple of controls
52+
mountToolbar([
53+
{
54+
title: 'Group 1',
55+
controls: [
56+
{
57+
title: 'Toggle',
58+
icon: mdiToggleSwitch,
59+
action: 'toggle',
60+
value: true,
61+
key: 'toggle'
62+
},
63+
{
64+
title: 'Callback',
65+
icon: mdiGestureTap,
66+
action: 'callback',
67+
callback: myCallback,
68+
key: 'callback'
69+
}
70+
]
71+
}
72+
])
73+
74+
// test all controls rendered
75+
cy
76+
.get('.group')
77+
.should('have.length', 1)
78+
.get('.control')
79+
.should('have.length', 2)
80+
.should('be.visible')
81+
82+
// test action=toggle
83+
cy
84+
// the toggle should be blue because it's active (default true)
85+
.get('.control.toggle .v-icon')
86+
.should('have.class', 'blue--text')
87+
// clicking the toggle should emit a "setOption" event with the
88+
// controls key (toggle) and new value (false)
89+
.click({ force: true })
90+
.get('@setOptionSpy')
91+
.should('have.been.calledWith', 'toggle', false)
92+
// it should not be grey because it's inactive (false)
93+
.get('.control.toggle .v-icon')
94+
.not('.blue--text')
95+
// click it again and it should become active again
96+
.click({ force: true })
97+
.get('@setOptionSpy')
98+
.should('have.been.calledWith', 'toggle', true)
99+
.get('.control.toggle .v-icon')
100+
.should('have.class', 'blue--text')
101+
102+
// test action=callback
103+
expect(callbacks).to.have.length(0)
104+
cy
105+
.get('.control.callback .v-icon')
106+
// clicking the icon should fire the callback
107+
.click({ force: true })
108+
.then(() => {
109+
expect(callbacks).to.have.length(1)
110+
})
111+
112+
// TODO: visual regression test
113+
// https://github.com/cylc/cylc-ui/issues/178
114+
})
115+
116+
it('enables and disables if', () => {
117+
// mount the toolbar with a couple of controls
118+
mountToolbar([
119+
{
120+
title: 'Group 1',
121+
controls: [
122+
{
123+
title: 'Foo',
124+
icon: mdiCog,
125+
action: 'toggle',
126+
value: true,
127+
key: 'foo',
128+
enableIf: ['bar'],
129+
disableIf: ['baz']
130+
},
131+
{
132+
title: 'Bar',
133+
icon: mdiCog,
134+
action: 'toggle',
135+
value: true,
136+
key: 'bar'
137+
},
138+
{
139+
title: 'Baz',
140+
icon: mdiCog,
141+
action: 'toggle',
142+
value: false,
143+
key: 'baz'
144+
}
145+
]
146+
}
147+
])
148+
149+
cy
150+
// foo should start enabled (bar=true, baz=false)
151+
.get('.control.foo .v-icon')
152+
.not('.v-icon--disabled')
153+
154+
// toggle bar
155+
.get('.control.bar .v-icon')
156+
.click({ force: true })
157+
158+
// foo should be disabled (bar=false, baz=false)
159+
.get('.control.foo .v-icon')
160+
.should('have.class', 'v-icon--disabled')
161+
162+
// toggle bar & baz
163+
.get('.control.bar .v-icon')
164+
.click({ force: true })
165+
.get('.control.baz .v-icon')
166+
.click({ force: true })
167+
168+
// foo should be disabled (bar=true, baz=true)
169+
.get('.control.foo .v-icon')
170+
.should('have.class', 'v-icon--disabled')
171+
172+
// toggle baz
173+
.get('.control.baz .v-icon')
174+
.click({ force: true })
175+
176+
// foo should be enabled (bar=true, baz=false)
177+
.get('.control.foo .v-icon')
178+
.not('.v-icon--disabled')
179+
})
180+
181+
it('groups', () => {
182+
mountToolbar([
183+
{
184+
title: 'Group 1',
185+
controls: [
186+
{
187+
title: 'Foo',
188+
icon: mdiCog,
189+
action: 'toggle',
190+
value: true,
191+
key: 'foo'
192+
},
193+
{
194+
title: 'Bar',
195+
icon: mdiCog,
196+
action: 'toggle',
197+
value: false,
198+
key: 'bar'
199+
}
200+
]
201+
},
202+
{
203+
title: 'Group 2',
204+
controls: [
205+
{
206+
title: 'Baz',
207+
icon: mdiCog,
208+
action: 'toggle',
209+
value: true,
210+
key: 'baz'
211+
},
212+
{
213+
title: 'Pub',
214+
icon: mdiCog,
215+
action: 'toggle',
216+
value: false,
217+
key: 'pub'
218+
}
219+
]
220+
}
221+
])
222+
// TODO: visual regression test
223+
// https://github.com/cylc/cylc-ui/issues/178
224+
})
225+
})

cypress/support/component.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,46 @@ import '@/styles/index.scss'
2222
// Alternatively you can use CommonJS syntax:
2323
// require('./commands')
2424

25+
import Vue from 'vue'
26+
import Vuetify from 'vuetify'
27+
2528
import { mount } from 'cypress/vue2'
2629

30+
// vanilla mount function
31+
// e.g. cy.mount(MyComponent)
2732
Cypress.Commands.add('mount', mount)
2833

29-
// Example use:
30-
// cy.mount(MyComponent)
34+
// mount function with Vuetify installed
35+
// e.g. cy.mount(MyVuetifyComponent)
36+
// see also addVuetifyStyles
37+
Vue.use(Vuetify)
38+
Cypress.Commands.add('vmount', (component, options = {}) => {
39+
const vuetify = new Vuetify()
40+
return mount(
41+
component,
42+
{
43+
vuetify,
44+
...options
45+
}
46+
)
47+
})
48+
49+
// add required classes to the Cypress root element
50+
// e.g. cy.addVuetifyStyles(cy)
51+
// use this if you need Vuetify styles to be applied
52+
Cypress.Commands.add('addVuetifyStyles', (cy) => {
53+
cy
54+
.document()
55+
.then((foo) => {
56+
const classList = foo.children[0].classList
57+
if (!classList.contains('v-application')) {
58+
foo.children[0].classList.add(
59+
'v-application',
60+
'v-application--is-ltr',
61+
'theme--light',
62+
'job_theme--default'
63+
)
64+
}
65+
})
66+
})
67+

0 commit comments

Comments
 (0)