Skip to content

Commit 48a5821

Browse files
author
Guillaume Chau
committed
test: migrate to cypress
1 parent 97068c8 commit 48a5821

21 files changed

+1064
-835
lines changed

.circleci/config.yml

+5
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ jobs:
2727

2828
# run tests!
2929
- run: yarn test
30+
31+
- store_artifacts:
32+
path: packages/@vue/cli-ui/tests/e2e/videos
33+
- store_artifacts:
34+
path: packages/@vue/cli-ui/tests/e2e/screenshots

.eslintrc

-15
This file was deleted.

.eslintrc.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
'root': true,
3+
'env': {
4+
'browser': true
5+
},
6+
'extends': [
7+
'plugin:vue-libs/recommended'
8+
],
9+
'globals': {
10+
'bridge': true,
11+
'chrome': true,
12+
'localStorage': true,
13+
'HTMLDocument': true
14+
}
15+
}

cypress.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"viewportWidth": 1280,
3+
"viewportHeight": 800,
4+
"chromeWebSecurity": false
5+
}

cypress/.eslintrc.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
'plugins': [
3+
'cypress'
4+
],
5+
'env': {
6+
'mocha': true,
7+
'cypress/globals': true
8+
},
9+
'rules': {
10+
'strict': 'off'
11+
}
12+
}

cypress/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/screenshots
2+
/videos

cypress/fixtures/example.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "Using fixtures to represent data",
3+
"email": "[email protected]",
4+
"body": "Fixtures are a great way to mock data for responses to routes"
5+
}

cypress/integration/components-tab.js

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { suite } from '../utils/suite'
2+
3+
const baseInstanceCount = 8
4+
5+
suite('components tab', () => {
6+
it('should detect instances inside shadow DOM', () => {
7+
cy.get('.tree > .instance:last-child').contains('Shadow')
8+
})
9+
10+
it('should select instance', () => {
11+
cy.get('.instance .self').eq(0).click().then(el => {
12+
expect(el).to.have.class('selected')
13+
})
14+
cy.get('.tree').should('be.visible')
15+
cy.get('.action-header .title').contains('Root')
16+
cy.get('.data-field').contains('$route')
17+
})
18+
19+
it('should expand root by default', () => {
20+
cy.get('.instance').should('have.length', baseInstanceCount)
21+
})
22+
23+
it('should select child instance', () => {
24+
cy.get('.instance .instance:nth-child(1) .self').eq(0).click()
25+
cy.get('.action-header .title').contains('Counter')
26+
cy.get('.data-el.vuex-bindings .data-field').contains('count:0')
27+
cy.get('.data-el.computed .data-field').contains('test:1')
28+
cy.get('.data-el.firebase-bindings .data-field').contains('hello:undefined')
29+
})
30+
31+
it('should display prop of different types', () => {
32+
cy.get('.instance .instance:nth-child(2) .self').eq(0).click()
33+
cy.get('.action-header .title').contains('Target')
34+
cy.get('.data-el.props .data-field:nth-child(1)').contains('ins:Object')
35+
cy.get('.data-el.props .data-field:nth-child(2)').contains('msg:"hi"')
36+
cy.get('.data-el.props .data-field:nth-child(3)').contains('obj:undefined')
37+
// Regexp
38+
cy.get('.data-el.data .data-field:nth-child(8)').then(el => {
39+
expect(el.text()).to.include('regex:/(a\\w+b)/g')
40+
})
41+
// Literals
42+
cy.get('.data-el.data .data-field:nth-child(5)').contains('NaN')
43+
cy.get('.data-el.data .data-field:nth-child(2)').contains('Infinity')
44+
cy.get('.data-el.data .data-field:nth-child(6)').contains('-Infinity')
45+
46+
// Classify names
47+
cy.get('.instance .instance:nth-child(3)').contains('OtherWithMine')
48+
cy.get('.button.classify-names').click()
49+
cy.get('.instance .instance:nth-child(3)').contains('other-with-mine')
50+
cy.get('.button.classify-names').click()
51+
cy.get('.instance .instance:nth-child(3)').contains('OtherWithMine')
52+
})
53+
54+
it('should expand child instance', () => {
55+
cy.get('.instance .instance:nth-child(2) .arrow-wrapper').click()
56+
cy.get('.instance').should('have.length', baseInstanceCount + 2)
57+
})
58+
59+
it('should add/remove component from app side', () => {
60+
cy.get('#target').iframe().then(({ get }) => {
61+
get('.add').click({ force: true })
62+
})
63+
cy.get('.instance').should('have.length', baseInstanceCount + 5)
64+
cy.get('#target').iframe().then(({ get }) => {
65+
get('.remove').click({ force: true })
66+
})
67+
cy.get('.instance').should('have.length', baseInstanceCount + 4)
68+
})
69+
70+
it('should filter components', () => {
71+
cy.get('.left .search input').clear().type('counter')
72+
cy.get('.instance').should('have.length', 1)
73+
cy.get('.left .search input').clear().type('target')
74+
cy.get('.instance').should('have.length', 5)
75+
cy.get('.left .search input').clear()
76+
})
77+
78+
it('should select component', () => {
79+
cy.get('.select-component').click()
80+
cy.get('#target').iframe().then(({ get }) => {
81+
get('.mine').eq(0)
82+
.trigger('mouseover', { force: true })
83+
.click({ force: true })
84+
})
85+
cy.get('.action-header .title').contains('Mine')
86+
cy.get('.tree').then(el => {
87+
expect(el.text()).to.include('<Mine>')
88+
})
89+
})
90+
91+
it('should display render key', () => {
92+
cy.get('.instance .self .attr-title').contains('key')
93+
cy.get('.instance .self .attr-value').contains('1')
94+
})
95+
})

cypress/integration/events.tab.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { suite } from '../utils/suite'
2+
3+
suite('events tab', () => {
4+
it('should display new events counter', () => {
5+
cy.get('#target').iframe().then(({ get }) => {
6+
get('.btn-emit-event').click({ force: true })
7+
get('.btn-emit-event1').click({ force: true })
8+
get('.btn-emit-event2').click({ force: true })
9+
})
10+
cy.get('.events-tab .tag').contains(3)
11+
cy.get('.events-tab').click()
12+
cy.get('.events-tab .tag').should('not.be.visible')
13+
})
14+
15+
it('should display events', () => {
16+
cy.get('.history .entry').should('have.length', 3)
17+
})
18+
19+
it('should add event', () => {
20+
cy.get('#target').iframe().then(({ get }) => {
21+
get('.btn-emit-log-event').click({ force: true })
22+
})
23+
cy.get('.history .entry').should('have.length', 4)
24+
})
25+
26+
it('should search events', () => {
27+
cy.get('.left .search input').clear().type('event')
28+
cy.get('.history .entry').should('have.length', 3)
29+
cy.get('.left .search input').clear().type('<eventchild1>')
30+
cy.get('.history .entry').should('have.length', 1)
31+
cy.get('.left .search input').clear()
32+
cy.get('.button.reset').click()
33+
cy.get('.history .entry').should('have.length', 0)
34+
})
35+
})

cypress/integration/vuex.tab.js

+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import { suite } from '../utils/suite'
2+
3+
suite('vuex tab', () => {
4+
it('should display mutations history', () => {
5+
cy.get('#target').iframe().then(({ get }) => {
6+
get('.increment')
7+
.click({ force: true })
8+
.click({ force: true })
9+
get('.decrement').click({ force: true })
10+
get('#counter p').contains('1')
11+
})
12+
cy.get('.vuex-tab').click()
13+
cy.get('.history .entry').should('have.length', 4)
14+
cy.get('.vuex-state-inspector').then(el => {
15+
expect(el.text()).to.include('type:"DECREMENT"')
16+
expect(el.text()).to.include('count:1')
17+
})
18+
cy.get('.history .entry:nth-child(4)').should('have.class', 'inspected').should('have.class', 'active')
19+
})
20+
21+
it('should filter state & getters', () => {
22+
cy.get('.right .search input').clear().type('cou')
23+
cy.get('.data-field').should('have.length', 1)
24+
cy.get('.right .search input').clear().type('no value')
25+
cy.get('.data-field').should('have.length', 0)
26+
cy.get('.right .search input').clear()
27+
})
28+
29+
it('should filter history', () => {
30+
cy.get('.left .search input').clear().type('inc')
31+
cy.get('.history .entry').should('have.length', 3)
32+
cy.get('.history .entry.inspected').should('have.length', 0)
33+
cy.get('.history .entry.active').should('have.length', 0)
34+
35+
cy.get('.left .search input').clear().type('/dec/i')
36+
cy.get('.history .entry').should('have.length', 2)
37+
cy.get('.history .entry.inspected.active').should('have.length', 1)
38+
39+
cy.get('.left .search input').clear().type('/dec)/i')
40+
cy.get('.history .entry').should('have.length', 4)
41+
cy.get('.history .entry.inspected.active').should('have.length', 1)
42+
43+
cy.get('.left .search input').clear()
44+
})
45+
46+
it('should inspect state', () => {
47+
cy.get('.history .entry:nth-child(3) .mutation-type').click()
48+
cy.get('.history .entry:nth-child(3)')
49+
.should('have.class', 'inspected')
50+
.should('not.have.class', 'active')
51+
cy.get('.vuex-state-inspector').then(el => {
52+
expect(el.text()).to.include('type:"INCREMENT"')
53+
expect(el.text()).to.include('count:2')
54+
})
55+
cy.get('#target').iframe().then(({ get }) => {
56+
get('#counter p').contains('1')
57+
})
58+
})
59+
60+
it('should time-travel', () => {
61+
cy.get('.history .entry:nth-child(3) .entry-actions .action:nth-child(3)').click({ force: true })
62+
cy.get('.history .entry:nth-child(3)')
63+
.should('have.class', 'inspected')
64+
.should('have.class', 'active')
65+
cy.get('#target').iframe().then(({ get }) => {
66+
get('#counter p').contains('2')
67+
})
68+
69+
cy.get('.history .entry:nth-child(2) .mutation-type').click({ force: true })
70+
cy.get('.history .entry:nth-child(2)')
71+
.should('have.class', 'inspected')
72+
.should('not.have.class', 'active')
73+
cy.get('.history .entry:nth-child(3)')
74+
.should('not.have.class', 'inspected')
75+
.should('have.class', 'active')
76+
cy.get('.vuex-state-inspector').then(el => {
77+
expect(el.text()).to.include('type:"INCREMENT"')
78+
expect(el.text()).to.include('count:1')
79+
})
80+
cy.get('#target').iframe().then(({ get }) => {
81+
get('#counter p').contains('2')
82+
})
83+
cy.get('.history .entry:nth-child(2) .entry-actions .action:nth-child(3)').click({ force: true })
84+
cy.get('.history .entry:nth-child(2)')
85+
.should('have.class', 'inspected')
86+
.should('have.class', 'active')
87+
cy.get('.history .entry:nth-child(3)')
88+
.should('not.have.class', 'inspected')
89+
.should('not.have.class', 'active')
90+
cy.get('#target').iframe().then(({ get }) => {
91+
get('#counter p').contains('1')
92+
})
93+
94+
// Base state
95+
cy.get('.history .entry:nth-child(1) .mutation-type').click({ force: true })
96+
cy.get('.history .entry:nth-child(1)')
97+
.should('have.class', 'inspected')
98+
.should('not.have.class', 'active')
99+
cy.get('.vuex-state-inspector').then(el => {
100+
expect(el.text()).to.include('count:0')
101+
})
102+
cy.get('#target').iframe().then(({ get }) => {
103+
get('#counter p').contains('1')
104+
})
105+
cy.get('.history .entry:nth-child(1) .entry-actions .action:nth-child(1)').click({ force: true })
106+
cy.get('.history .entry:nth-child(1)')
107+
.should('have.class', 'inspected')
108+
.should('have.class', 'active')
109+
cy.get('#target').iframe().then(({ get }) => {
110+
get('#counter p').contains('0')
111+
})
112+
})
113+
114+
it('should revert', () => {
115+
cy.get('.history .entry:nth-child(4) .mutation-type').click({ force: true })
116+
cy.get('.history .entry:nth-child(4) .action:nth-child(2)').click({ force: true })
117+
cy.get('.history .entry').should('have.length', 3)
118+
cy.get('.history .entry:nth-child(3)')
119+
.should('have.class', 'inspected')
120+
.should('have.class', 'active')
121+
cy.get('.vuex-state-inspector').then(el => {
122+
expect(el.text()).to.include('count:2')
123+
})
124+
cy.get('#target').iframe().then(({ get }) => {
125+
get('#counter p').contains('2')
126+
})
127+
})
128+
129+
it('should commit', () => {
130+
cy.get('.history .entry:nth-child(3) .mutation-type').click({ force: true })
131+
cy.get('.history .entry:nth-child(3) .action:nth-child(1)').click({ force: true })
132+
cy.get('.history .entry').should('have.length', 1)
133+
cy.get('.history .entry:nth-child(1)')
134+
.should('have.class', 'inspected')
135+
.should('have.class', 'active')
136+
cy.get('.vuex-state-inspector').then(el => {
137+
expect(el.text()).to.include('count:2')
138+
})
139+
cy.get('#target').iframe().then(({ get }) => {
140+
get('#counter p').contains('2')
141+
})
142+
})
143+
144+
it('should display getters', () => {
145+
cy.get('.vuex-state-inspector').then(el => {
146+
expect(el.text()).to.include('isPositive:true')
147+
})
148+
cy.get('#target').iframe().then(({ get }) => {
149+
get('.decrement')
150+
.click({ force: true })
151+
.click({ force: true })
152+
.click({ force: true })
153+
})
154+
cy.get('.history .entry:nth-child(4)').click({ force: true })
155+
cy.get('.vuex-state-inspector').then(el => {
156+
expect(el.text()).to.include('isPositive:false')
157+
})
158+
})
159+
160+
it('should toggle recording', () => {
161+
cy.get('.toggle-recording')
162+
.click()
163+
.contains('Paused')
164+
cy.get('.toggle-recording .svg-icon').should('not.have.class', 'enabled')
165+
// should not record
166+
cy.get('#target').iframe().then(({ get }) => {
167+
get('.increment').click({ force: true })
168+
})
169+
cy.get('.history .entry').should('have.length', 4)
170+
})
171+
172+
it('should copy vuex state', () => {
173+
cy.get('.export').click()
174+
cy.get('.export .message')
175+
.contains('(Copied to clipboard!)')
176+
.should('not.be.visible', { timeout: 3000 })
177+
})
178+
179+
it('should import vuex state', () => {
180+
cy.get('.import').click()
181+
cy.get('.import-state').should('be.visible')
182+
cy.get('.import-state textarea').clear().type('{{}invalid: json}')
183+
cy.get('.message.invalid-json').should('be.visible')
184+
cy.get('.import-state textarea').clear().type('{{}"count":42,"date":"[native Date Fri Dec 22 2017 10:12:04 GMT+0100 (CET)]"}')
185+
cy.get('.message.invalid-json').should('not.be.visible')
186+
cy.get('.vuex-state-inspector').then(el => {
187+
expect(el.text()).to.include('count:42')
188+
expect(el.text()).to.include('date:' + new Date('Fri Dec 22 2017 10:12:04 GMT+0100 (CET)'))
189+
})
190+
cy.get('.import').click()
191+
cy.get('.import-state').should('not.be.visible')
192+
})
193+
})

0 commit comments

Comments
 (0)