Skip to content

Commit 7c79a42

Browse files
authored
fix: Fire appropriate event when cy.type(). (#8255)
1 parent d3c480f commit 7c79a42

File tree

5 files changed

+82
-17
lines changed

5 files changed

+82
-17
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!-- Simplified version of https://signin.simple.com-->
2+
3+
<!doctype html>
4+
<html lang="en">
5+
<head>
6+
<title>Sign In | Simple</title>
7+
</head>
8+
<body>
9+
<form id="login">
10+
<label for="login_username">Username</label>
11+
<input type="text" name="username" id="login_username" autofocus="autofocus" tabindex="1" autocapitalize="off" autocorrect="off" autocomplete="off" class="validate-text validate-username validate-email-username" />
12+
13+
<label for="login_password">Password</label>
14+
<input type="password" name="password" id="login_password" tabindex="2" autocomplete="off" class="validate-text" />
15+
16+
<input type="submit" id="signin-btn" class="btn -primary" value="Sign In" tabindex="4" disabled>
17+
</form>
18+
<script src="issue-6125.js" type="text/javascript"></script>
19+
</body>
20+
</html>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Extracted the code that causes the problem in signin.simple.com
2+
// The cause was overriding the Event class.
3+
4+
(function() {
5+
this.Event = function(n, i) {
6+
const r = n.type
7+
8+
if (r.indexOf("key")) {
9+
// do something
10+
}
11+
}
12+
})()

packages/driver/cypress/integration/commands/actions/type_spec.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,28 @@ describe('src/cy/commands/actions/type - #type', () => {
177177
.should('have.value', 'foobar')
178178
})
179179

180+
// https://github.com/cypress-io/cypress/issues/6125
181+
it('works even if Event class is overridden', () => {
182+
cy.visit('fixtures/issue-6125.html')
183+
cy.get('#login_username')
184+
.type('foobar')
185+
})
186+
187+
// https://github.com/cypress-io/cypress/issues/5650
188+
it('should trigger KeyboardEvent, not Event, for event listeners', (done) => {
189+
cy.$$('input:first').on('keydown', (e) => {
190+
if (e.originalEvent instanceof e.currentTarget.ownerDocument.defaultView.KeyboardEvent) {
191+
done()
192+
193+
return
194+
}
195+
196+
throw new Error('event was not instanceOf KeyboardEvent')
197+
})
198+
199+
cy.get('input:first').type('A')
200+
})
201+
180202
describe('actionability', () => {
181203
it('can forcibly type + click even when element is invisible', () => {
182204
const $txt = cy.$$(':text:first').hide()

packages/driver/src/cy/commands/actions/type.js

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,19 +202,25 @@ module.exports = function (Commands, Cypress, cy, state, config) {
202202
return
203203
}
204204

205-
// issue the click event to the 'default button' of the form
206-
// we need this to be synchronous so not going through our
207-
// own click command
208-
// as of now, at least in Chrome, causing the click event
209-
// on the button will indeed trigger the form submit event
210-
// so we dont need to fire it manually anymore!
211-
if (!clickedDefaultButton(defaultButton)) {
212-
// if we werent able to click the default button
213-
// then synchronously fire the submit event
214-
// currently this is sync but if we use a waterfall
215-
// promise in the submit command it will break again
216-
// consider changing type to a Promise and juggle logging
217-
return cy.now('submit', form, { log: false, $el: form })
205+
// In Firefox, submit event is automatically fired
206+
// when we send {Enter} KeyboardEvent to the input fields.
207+
// Because of that, we don't have to click the submit buttons.
208+
// Otherwise, we trigger submit events twice.
209+
if (!Cypress.isBrowser('firefox')) {
210+
// issue the click event to the 'default button' of the form
211+
// we need this to be synchronous so not going through our
212+
// own click command
213+
// as of now, at least in Chrome, causing the click event
214+
// on the button will indeed trigger the form submit event
215+
// so we dont need to fire it manually anymore!
216+
if (!clickedDefaultButton(defaultButton)) {
217+
// if we werent able to click the default button
218+
// then synchronously fire the submit event
219+
// currently this is sync but if we use a waterfall
220+
// promise in the submit command it will break again
221+
// consider changing type to a Promise and juggle logging
222+
return cy.now('submit', form, { log: false, $el: form })
223+
}
218224
}
219225
}
220226

packages/driver/src/cy/keyboard.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,10 +900,15 @@ export class Keyboard {
900900

901901
// or is IE
902902
} else {
903-
// For some reason we can't set certain props on Keyboard Events in chrome < 63.
904-
// So we'll use the plain Event constructor
905-
// event = new win[eventConstructor](eventType, eventOptions)
906-
event = new win['Event'](eventType, eventOptions)
903+
let constructor = win[eventConstructor]
904+
905+
// When event constructor doesn't exist, fallback to KeyboardEvent.
906+
// It's necessary because Firefox doesn't support InputEvent.
907+
if (typeof constructor !== 'function') {
908+
constructor = win['KeyboardEvent']
909+
}
910+
911+
event = new constructor(eventType, eventOptions)
907912
_.extend(event, eventOptions)
908913
}
909914

0 commit comments

Comments
 (0)