Skip to content

Commit 7129ae4

Browse files
committed
feat: wrap actions in Cypress command queue, close #2
This makes running actions seem very natural and avoids `cy.then` blocks. ```js Cypress.main.toggle() cy.get('.toggle').should('be.checked') // because actions inside Cypress.main are queued into the // Cypress command queue first we can just call them // the toggle below will happen AFTER the toggle check above // has already passed Cypress.main.toggle() cy.get('.toggle').should('not.be.checked') ```
1 parent fa006df commit 7129ae4

File tree

4 files changed

+45
-27
lines changed

4 files changed

+45
-27
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,14 @@ beforeEach(() => {
4949

5050
```js
5151
Cypress.main.setName('Joe')
52-
expect(Cypress.main._getState().name).to.equal('Joe')
52+
Cypress.main._getState().its('name').should('equal', 'Joe')
53+
Cypress.main.setAge(37)
54+
Cypress.main._getState().should('deep.equal', {
55+
name: 'Joe',
56+
age: 37
57+
})
5358
```
59+
Note: the `Cypress.main` wraps returned Hyperapp actions with `cy.then` to queue the calls through the Cypress command queue. Thus the above code looks synchronous, but in reality there could be DOM updates, network calls, etc, and it still works.
5460

5561
## Use
5662

cypress/integration/hello-world-component-spec.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,6 @@ describe('HelloYou', () => {
4444
Cypress.main.setName('Great Person!')
4545
// mount function adds utility method to get the
4646
// current state object
47-
expect(Cypress.main._getState().name).to.equal('Great Person!')
48-
})
49-
50-
it('mutates state', () => {
51-
Cypress.main.setName('Great Person!')
52-
expect(state).to.not.equal(Cypress.main._getState())
47+
Cypress.main._getState().its('name').should('equal', 'Great Person!')
5348
})
5449
})

cypress/integration/todo-item-spec.js

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ describe('TodoItem', () => {
2727
})
2828

2929
it('is unchecked for unfinished item', () => {
30-
cy
31-
.get('.toggle')
32-
.should('have.length', 1)
33-
.should('not.be.checked')
30+
cy.get('.toggle').should('have.length', 1).should('not.be.checked')
3431
})
3532

3633
it('toggles item on click', () => {
@@ -39,27 +36,29 @@ describe('TodoItem', () => {
3936
})
4037

4138
it('changes state on click', () => {
42-
cy
43-
.get('.todo')
44-
.click()
45-
.then(() => {
46-
expect(Cypress.main._getState()).to.deep.equal({
47-
done: true,
48-
value: 'Try HyperApp'
49-
})
50-
})
39+
cy.get('.todo').click()
40+
Cypress.main._getState().should('deep.equal', {
41+
done: true,
42+
value: 'Try HyperApp'
43+
})
44+
45+
// click again
46+
cy.get('.todo').click()
47+
Cypress.main._getState().should('deep.equal', {
48+
done: false,
49+
value: 'Try HyperApp'
50+
})
5151
})
5252

5353
it('changes state by invoking action', () => {
5454
// the component's actions are referenced in Cypress.main
5555
Cypress.main.toggle()
5656
cy.get('.toggle').should('be.checked')
57-
// the action happens synchronously
58-
// but Cypress commands are queued
59-
// thus toggle again only after previous cy.get... has passed
60-
cy.then(() => {
61-
Cypress.main.toggle()
62-
})
57+
// because actions inside Cypress.main are queued into the
58+
// Cypress command queue first we can just call them
59+
// the toggle below will happen AFTER the toggle check above
60+
// has already passed
61+
Cypress.main.toggle()
6362
cy.get('.toggle').should('not.be.checked')
6463
})
6564
})

src/index.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,25 @@ export const mount = (state, actions, view) => {
2121
.its('hyperapp.app')
2222
.then(app => {
2323
const el = document.getElementById('app')
24-
Cypress.main = app(state, actions, view, el)
24+
const main = app(state, actions, view, el)
25+
26+
// wrap every hyper action with `cy.then` to
27+
// make sure it goes through the Cypress command queue
28+
// allows things like the example below to just work
29+
// Cypress.main.setText('foo')
30+
// cy.contains('foo')
31+
// Cypress.main.setText('bar')
32+
// cy.contains('bar')
33+
Cypress.main = {}
34+
Object.keys(main).forEach(name => {
35+
const action = main[name]
36+
Cypress.main[name] = function queueAction () {
37+
// should we log arguments?
38+
cy.log(`action: ${name}`)
39+
return cy.then(() => action.apply(null, arguments))
40+
}
41+
})
42+
2543
return Cypress.main
2644
})
2745

0 commit comments

Comments
 (0)