Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: send click event with cy.type('{enter}'). #19726

Merged
merged 2 commits into from Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 75 additions & 0 deletions packages/driver/cypress/fixtures/type-enter.html
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html>
<head>
<title>type('{enter}') </title>
<meta charset="UTF-8" />
</head>

<body>
<button id="reset">clear log</button>
<button id="target-button-tag">click me then press enter</button>
<input id="target-input-button" type="button" value="click me then press enter" />
<input id="target-input-image" type="image" value="click me then press enter" />
<input id="target-input-reset" type="reset" value="click me then press enter" />
<input id="target-input-submit" type="submit" value="click me then press enter" />
<input id="target-input-checkbox" type="checkbox" value="click me then press enter" />
<input id="target-input-radio" type="radio" value="click me then press enter" />

<div id="log"></div>

<script>
const reset = document.getElementById("reset");

let log = [];

reset.addEventListener("click", () => {
log = [];
updateLog();
});

const updateLog = (msg) => {
if (msg) {
log.push(msg);
}

const ol = document.createElement("ol");

log.forEach((text) => {
const node = document.createTextNode(text);
const li = document.createElement("li");
li.appendChild(node);
ol.appendChild(li);
});

document.getElementById("log").replaceChildren(ol);
};

const targets = [
'target-button-tag',
'target-input-button',
'target-input-image',
'target-input-reset',
'target-input-submit',
'target-input-checkbox',
'target-input-radio',
]

targets.forEach((targetId) => {
const target = document.getElementById(targetId);

target.addEventListener("keydown", () => {
updateLog("keydown");
});
target.addEventListener("keypress", () => {
updateLog("keypress");
});
target.addEventListener("click", () => {
updateLog("click");
});
target.addEventListener("keyup", () => {
updateLog("keyup");
});
});
</script>
</body>
</html>
47 changes: 47 additions & 0 deletions packages/driver/cypress/integration/commands/actions/type_spec.js
Expand Up @@ -557,6 +557,53 @@ describe('src/cy/commands/actions/type - #type', () => {
})
})

// https://github.com/cypress-io/cypress/issues/19541
describe(`type('{enter}') and click event on button-like elements`, () => {
beforeEach(() => {
cy.visit('fixtures/type-enter.html')
})

describe('triggers', () => {
const targets = [
'button-tag',
'input-button',
'input-image',
'input-reset',
'input-submit',
]

targets.forEach((targetId) => {
it(`${targetId}`, () => {
cy.get(`#target-${targetId}`).focus()
cy.get(`#target-${targetId}`).type('{enter}')

cy.get('li').eq(0).should('have.text', 'keydown')
cy.get('li').eq(1).should('have.text', 'keypress')
cy.get('li').eq(2).should('have.text', 'click')
cy.get('li').eq(3).should('have.text', 'keyup')
})
})
})

describe('does not trigger', () => {
const targets = [
'input-checkbox',
'input-radio',
]

targets.forEach((targetId) => {
it(`${targetId}`, () => {
cy.get(`#target-${targetId}`).focus()
cy.get(`#target-${targetId}`).type('{enter}')

cy.get('li').eq(0).should('have.text', 'keydown')
cy.get('li').eq(1).should('have.text', 'keypress')
cy.get('li').eq(2).should('have.text', 'keyup')
})
})
})
})

describe('tabindex', () => {
beforeEach(function () {
this.$div = cy.$$('#tabindex')
Expand Down
22 changes: 19 additions & 3 deletions packages/driver/src/cy/commands/actions/type.ts
Expand Up @@ -272,6 +272,11 @@ export default function (Commands, Cypress, cy, state, config) {
const isContentEditable = $elements.isContentEditable(options.$el.get(0))
const isTextarea = $elements.isTextarea(options.$el.get(0))

// click event is only fired on button, image, submit, reset elements.
// That's why we cannot use $elements.isButtonLike() here.
const type = (type) => $elements.isInputType(options.$el.get(0), type)
const sendClickEvent = type('button') || type('image') || type('submit') || type('reset')

return keyboard.type({
$el: options.$el,
chars,
Expand Down Expand Up @@ -347,22 +352,33 @@ export default function (Commands, Cypress, cy, state, config) {
})
},

onEnterPressed (id) {
onEnterPressed (el) {
// dont dispatch change events or handle
// submit event if we've pressed enter into
// a textarea or contenteditable

if (isTextarea || isContentEditable) {
return
}

// https://github.com/cypress-io/cypress/issues/19541
// Send click event on type('{enter}')
if (sendClickEvent) {
// Firefox sends a click event automatically.
if (!Cypress.isBrowser('firefox')) {
const ctor = $dom.getDocumentFromElement(el).defaultView?.PointerEvent
const event = new ctor('click')

el.dispatchEvent(event)
}
}

// if our value has changed since our
// element was activated we need to
// fire a change event immediately
const changeEvent = state('changeEvent')

if (changeEvent) {
changeEvent(id)
changeEvent()
}

// handle submit event handler here
Expand Down
2 changes: 1 addition & 1 deletion packages/driver/src/cy/keyboard.ts
Expand Up @@ -582,7 +582,7 @@ const simulatedDefaultKeyMap: { [key: string]: SimulatedDefault } = {
$selection.replaceSelectionContents(el, '\n')
}

options.onEnterPressed && options.onEnterPressed()
options.onEnterPressed && options.onEnterPressed(el)
},
Delete: (el, key) => {
key.events.input = $selection.deleteRightOfCursor(el)
Expand Down