From 7c79a4260cac991db85396932aa74d6f109272c6 Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Fri, 11 Sep 2020 08:20:39 +0900 Subject: [PATCH] fix: Fire appropriate event when cy.type(). (#8255) --- .../driver/cypress/fixtures/issue-6125.html | 20 ++++++++++++ .../driver/cypress/fixtures/issue-6125.js | 12 +++++++ .../integration/commands/actions/type_spec.js | 22 +++++++++++++ .../driver/src/cy/commands/actions/type.js | 32 +++++++++++-------- packages/driver/src/cy/keyboard.ts | 13 +++++--- 5 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 packages/driver/cypress/fixtures/issue-6125.html create mode 100644 packages/driver/cypress/fixtures/issue-6125.js diff --git a/packages/driver/cypress/fixtures/issue-6125.html b/packages/driver/cypress/fixtures/issue-6125.html new file mode 100644 index 000000000000..d4a63a75c1ce --- /dev/null +++ b/packages/driver/cypress/fixtures/issue-6125.html @@ -0,0 +1,20 @@ + + + + + + Sign In | Simple + + +
+ + + + + + + +
+ + + diff --git a/packages/driver/cypress/fixtures/issue-6125.js b/packages/driver/cypress/fixtures/issue-6125.js new file mode 100644 index 000000000000..cca9307836a3 --- /dev/null +++ b/packages/driver/cypress/fixtures/issue-6125.js @@ -0,0 +1,12 @@ +// Extracted the code that causes the problem in signin.simple.com +// The cause was overriding the Event class. + +(function() { + this.Event = function(n, i) { + const r = n.type + + if (r.indexOf("key")) { + // do something + } + } +})() diff --git a/packages/driver/cypress/integration/commands/actions/type_spec.js b/packages/driver/cypress/integration/commands/actions/type_spec.js index fdc823b6a283..3ae5a4a3039c 100644 --- a/packages/driver/cypress/integration/commands/actions/type_spec.js +++ b/packages/driver/cypress/integration/commands/actions/type_spec.js @@ -177,6 +177,28 @@ describe('src/cy/commands/actions/type - #type', () => { .should('have.value', 'foobar') }) + // https://github.com/cypress-io/cypress/issues/6125 + it('works even if Event class is overridden', () => { + cy.visit('fixtures/issue-6125.html') + cy.get('#login_username') + .type('foobar') + }) + + // https://github.com/cypress-io/cypress/issues/5650 + it('should trigger KeyboardEvent, not Event, for event listeners', (done) => { + cy.$$('input:first').on('keydown', (e) => { + if (e.originalEvent instanceof e.currentTarget.ownerDocument.defaultView.KeyboardEvent) { + done() + + return + } + + throw new Error('event was not instanceOf KeyboardEvent') + }) + + cy.get('input:first').type('A') + }) + describe('actionability', () => { it('can forcibly type + click even when element is invisible', () => { const $txt = cy.$$(':text:first').hide() diff --git a/packages/driver/src/cy/commands/actions/type.js b/packages/driver/src/cy/commands/actions/type.js index b58504a6bc21..7a5754e2d073 100644 --- a/packages/driver/src/cy/commands/actions/type.js +++ b/packages/driver/src/cy/commands/actions/type.js @@ -202,19 +202,25 @@ module.exports = function (Commands, Cypress, cy, state, config) { return } - // issue the click event to the 'default button' of the form - // we need this to be synchronous so not going through our - // own click command - // as of now, at least in Chrome, causing the click event - // on the button will indeed trigger the form submit event - // so we dont need to fire it manually anymore! - if (!clickedDefaultButton(defaultButton)) { - // if we werent able to click the default button - // then synchronously fire the submit event - // currently this is sync but if we use a waterfall - // promise in the submit command it will break again - // consider changing type to a Promise and juggle logging - return cy.now('submit', form, { log: false, $el: form }) + // In Firefox, submit event is automatically fired + // when we send {Enter} KeyboardEvent to the input fields. + // Because of that, we don't have to click the submit buttons. + // Otherwise, we trigger submit events twice. + if (!Cypress.isBrowser('firefox')) { + // issue the click event to the 'default button' of the form + // we need this to be synchronous so not going through our + // own click command + // as of now, at least in Chrome, causing the click event + // on the button will indeed trigger the form submit event + // so we dont need to fire it manually anymore! + if (!clickedDefaultButton(defaultButton)) { + // if we werent able to click the default button + // then synchronously fire the submit event + // currently this is sync but if we use a waterfall + // promise in the submit command it will break again + // consider changing type to a Promise and juggle logging + return cy.now('submit', form, { log: false, $el: form }) + } } } diff --git a/packages/driver/src/cy/keyboard.ts b/packages/driver/src/cy/keyboard.ts index 2152422ff2a6..dfdb62f7f40a 100644 --- a/packages/driver/src/cy/keyboard.ts +++ b/packages/driver/src/cy/keyboard.ts @@ -900,10 +900,15 @@ export class Keyboard { // or is IE } else { - // For some reason we can't set certain props on Keyboard Events in chrome < 63. - // So we'll use the plain Event constructor - // event = new win[eventConstructor](eventType, eventOptions) - event = new win['Event'](eventType, eventOptions) + let constructor = win[eventConstructor] + + // When event constructor doesn't exist, fallback to KeyboardEvent. + // It's necessary because Firefox doesn't support InputEvent. + if (typeof constructor !== 'function') { + constructor = win['KeyboardEvent'] + } + + event = new constructor(eventType, eventOptions) _.extend(event, eventOptions) }