Skip to content

Commit

Permalink
feat: can dispatch events with the type they want. (#8305)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris Breiding <[email protected]>
  • Loading branch information
sainthkh and chrisbreiding authored Aug 31, 2020
1 parent 2469473 commit 15fdf12
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 4 deletions.
6 changes: 6 additions & 0 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2916,6 +2916,12 @@ declare namespace Cypress {
* @default true
*/
cancelable: boolean
/**
* The type of the event you want to trigger
*
* @default 'Event'
*/
eventConstructor: string
}

/** Options to change the default behavior of .writeFile */
Expand Down
21 changes: 21 additions & 0 deletions packages/driver/cypress/fixtures/issue-5650.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Test input event</title>
</head>
<body>
<input id="test-input"/>
<div id="result"></div>
</body>
<script>
let elem = window.document.getElementById('test-input');
let resultDiv = window.document.getElementById('result');
elem.addEventListener('keydown', (event) => {
resultDiv.innerText = `isKeyboardEvent: ${event instanceof KeyboardEvent}`;
});
elem.addEventListener('mousedown', (event) => {
resultDiv.innerText = `isMouseEvent: ${event instanceof MouseEvent}`;
});
</script>
</html>
104 changes: 104 additions & 0 deletions packages/driver/cypress/integration/commands/actions/trigger_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,27 @@ describe('src/cy/commands/actions/trigger', () => {
cy.window().should('have.length.gt', 1).trigger('click')
})

// https://github.com/cypress-io/cypress/issues/3686
it('view should be AUT window', (done) => {
cy.window().then((win) => {
cy.get('input:first').then((jQueryElement) => {
let elem = jQueryElement.get(0)

elem.addEventListener('mousedown', (event) => {
expect(event.view).to.eql(win)
done()
})
})
})

cy.get('input:first').trigger('mousedown', {
eventConstructor: 'MouseEvent',
button: 0,
shiftKey: false,
ctrlKey: false,
})
})

describe('actionability', () => {
it('can trigger on elements which are hidden until scrolled within parent container', () => {
cy.get('#overflow-auto-container').contains('quux').trigger('mousedown')
Expand Down Expand Up @@ -742,6 +763,76 @@ describe('src/cy/commands/actions/trigger', () => {
})
})

// https://github.com/cypress-io/cypress/issues/5650
describe('dispatches correct Event objects', () => {
it('should trigger KeyboardEvent with .trigger inside Cypress event listener', (done) => {
cy.window().then((win) => {
cy.get('input:first').then((jQueryElement) => {
let elemHtml = jQueryElement.get(0)

elemHtml.addEventListener('keydown', (event) => {
expect(event instanceof win['KeyboardEvent']).to.be.true
done()
})
})
})

cy.get('input:first').trigger('keydown', {
eventConstructor: 'KeyboardEvent',
keyCode: 65,
which: 65,
shiftKey: false,
ctrlKey: false,
})
})

it('should trigger KeyboardEvent with .trigger inside html script event listener', () => {
cy.visit('fixtures/issue-5650.html')

cy.get('#test-input').trigger('keydown', {
eventConstructor: 'KeyboardEvent',
keyCode: 65,
which: 65,
shiftKey: false,
ctrlKey: false,
})

cy.get('#result').contains('isKeyboardEvent: true')
})

it('should trigger MouseEvent with .trigger inside Cypress event listener', (done) => {
cy.window().then((win) => {
cy.get('input:first').then((jQueryElement) => {
let elem = jQueryElement.get(0)

elem.addEventListener('mousedown', (event) => {
expect(event instanceof win['MouseEvent']).to.be.true
done()
})
})
})

cy.get('input:first').trigger('mousedown', {
eventConstructor: 'MouseEvent',
button: 0,
shiftKey: false,
ctrlKey: false,
})
})

it('should trigger MouseEvent with .trigger inside html script event listener', () => {
cy.visit('fixtures/issue-5650.html')
cy.get('#test-input').trigger('mousedown', {
eventConstructor: 'MouseEvent',
button: 0,
shiftKey: false,
ctrlKey: false,
})

cy.get('#result').contains('isMouseEvent: true')
})
})

describe('errors', {
defaultCommandTimeout: 100,
}, () => {
Expand Down Expand Up @@ -864,6 +955,19 @@ describe('src/cy/commands/actions/trigger', () => {
cy.get('button:first').trigger('mouseover', 'foo')
})

it('throws when provided invalid event type', function (done) {
cy.on('fail', (err) => {
expect(this.logs.length).to.eq(2)
expect(err.message).to.eq('Timed out retrying: `cy.trigger()` `eventConstructor` option must be a valid event (e.g. \'MouseEvent\', \'KeyboardEvent\'). You passed: `FooEvent`')

done()
})

cy.get('button:first').trigger('mouseover', {
eventConstructor: 'FooEvent',
})
})

it('throws when element animation exceeds timeout', (done) => {
// force the animation calculation to think we moving at a huge distance ;-)
cy.stub(Cypress.utils, 'getDistanceBetween').returns(100000)
Expand Down
29 changes: 25 additions & 4 deletions packages/driver/src/cy/commands/actions/trigger.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,29 @@ const $dom = require('../../../dom')
const $errUtils = require('../../../cypress/error_utils')
const $actionability = require('../../actionability')

const dispatch = (target, eventName, options) => {
const event = new Event(eventName, options)
const dispatch = (target, appWindow, eventName, options) => {
const eventConstructor = options.eventConstructor ?? 'Event'
const ctor = appWindow[eventConstructor]

if (typeof ctor !== 'function') {
$errUtils.throwErrByPath('trigger.invalid_event_type', {
args: { eventConstructor },
})
}

// eventConstructor property should not be added to event instance.
delete options.eventConstructor

// https://github.com/cypress-io/cypress/issues/3686
// UIEvent and its derived events like MouseEvent, KeyboardEvent
// has a property, view, which is the window object where the event happened.
// Logic below checks the ctor function is UIEvent itself or its children
// and adds view to the instance init object.
if (ctor === appWindow['UIEvent'] || ctor.prototype instanceof appWindow['UIEvent']) {
options.view = appWindow
}

const event = new ctor(eventName, options)

// some options, like clientX & clientY, must be set on the
// instance instead of passing them into the constructor
Expand Down Expand Up @@ -85,7 +106,7 @@ module.exports = (Commands, Cypress, cy, state, config) => {

const trigger = () => {
if (dispatchEarly) {
return dispatch(subject, eventName, eventOptions)
return dispatch(subject, state('window'), eventName, eventOptions)
}

return $actionability.verify(cy, subject, options, {
Expand All @@ -112,7 +133,7 @@ module.exports = (Commands, Cypress, cy, state, config) => {
pageY: fromElWindow.y,
}, eventOptions)

return dispatch($elToClick.get(0), eventName, eventOptions)
return dispatch($elToClick.get(0), state('window'), eventName, eventOptions)
},
})
}
Expand Down
4 changes: 4 additions & 0 deletions packages/driver/src/cypress/error_messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,10 @@ module.exports = {
message: `${cmd('trigger')} can only be called on a single element. Your subject contained {{num}} elements.`,
docsUrl: 'https://on.cypress.io/trigger',
},
invalid_event_type: {
message: `${cmd('trigger')} \`eventConstructor\` option must be a valid event (e.g. 'MouseEvent', 'KeyboardEvent'). You passed: \`{{eventConstructor}}\``,
docsUrl: 'https://on.cypress.io/trigger',
},
},

type: {
Expand Down

4 comments on commit 15fdf12

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 15fdf12 Aug 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/linux-x64/circle-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-434980/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/circle-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-434959/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 15fdf12 Aug 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

Instructions are included below, depending on the shell you are using.

In Command Prompt (cmd.exe):

set CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/win32-x64/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

In PowerShell:

$env:CYPRESS_INSTALL_BINARY = https://cdn.cypress.io/beta/binary/5.1.0/win32-x64/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

In Git Bash:

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/win32-x64/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

Using cross-env:

If the above commands do not work for you, you can also try using cross-env:

npm i -g cross-env
cross-env CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/win32-x64/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 15fdf12 Aug 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 ia32 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

Instructions are included below, depending on the shell you are using.

In Command Prompt (cmd.exe):

set CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/win32-ia32/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

In PowerShell:

$env:CYPRESS_INSTALL_BINARY = https://cdn.cypress.io/beta/binary/5.1.0/win32-ia32/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

In Git Bash:

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/win32-ia32/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

Using cross-env:

If the above commands do not work for you, you can also try using cross-env:

npm i -g cross-env
cross-env CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/win32-ia32/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.zip npm install https://cdn.cypress.io/beta/npm/5.1.0/appveyor-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-34947444/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 15fdf12 Aug 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.1.0/darwin-x64/circle-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-435051/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.1.0/circle-develop-15fdf12ae740a07eff36250073c5be7e001d8aa2-434965/cypress.tgz

Please sign in to comment.