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

Prevent chrome from changing checkbox checked state when button or link located inside the label is clicked(closes #6949) #6950

Merged
merged 2 commits into from Mar 30, 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
20 changes: 14 additions & 6 deletions src/client/automation/playback/click/click-command.js
Expand Up @@ -32,8 +32,8 @@ class LabelElementClickCommand extends ElementClickCommand {
constructor (eventState, eventArgs) {
super(eventState, eventArgs);

this.label = this.eventArgs.element;
this.input = getElementBoundToLabel(this.eventArgs.element);
this.targetElement = this.eventArgs.element;
this.input = getElementBoundToLabel(this.eventArgs.element);
}

run () {
Expand All @@ -49,7 +49,7 @@ class LabelElementClickCommand extends ElementClickCommand {

listeners.removeInternalEventBeforeListener(window, ['focus'], ensureFocusRaised);

if (domUtils.isElementFocusable(this.label) && !focusRaised)
if (domUtils.isElementFocusable(this.targetElement) && !focusRaised)
this._ensureBoundElementFocusRaised();
}

Expand Down Expand Up @@ -114,7 +114,10 @@ class LabelledCheckboxElementClickCommand extends LabelElementClickCommand {

listeners.removeInternalEventBeforeListener(window, ['change'], onChange);

if (browserUtils.isChrome && !changed)
// NOTE: Two overlapping issues: https://github.com/DevExpress/testcafe/issues/3348 and https://github.com/DevExpress/testcafe/issues/6949
// When label contains <a href=any> or <button> element, clicking these elements will prevent checkbox from changing checked state.
// We should to leave the code for fixing .focus issue and add additional check for the clickable elements inside the label:
if (browserUtils.isChrome && !changed && !this._isClickableElementInsideLabel(this.targetElement))
this._ensureCheckboxStateChanged();
}

Expand All @@ -123,6 +126,13 @@ class LabelledCheckboxElementClickCommand extends LabelElementClickCommand {

eventSimulator.change(this.checkbox);
}

_isClickableElementInsideLabel (element) {
const isClickableLink = domUtils.isAnchorElement(element) && element.getAttribute('href');
const isButton = domUtils.isButtonElement(element);

return isClickableLink || isButton;
}
}

export default function (eventState, eventArgs) {
Expand All @@ -146,5 +156,3 @@ export default function (eventState, eventArgs) {

return new ElementClickCommand(eventState, eventArgs);
}


16 changes: 16 additions & 0 deletions test/functional/fixtures/regression/gh-6949/pages/with-button.html
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="checkbox">
<input id="checkbox" type="checkbox">
<label for="checkbox" id="checkbox-label">
I have read and accept
<button id="clickable-element" type="button">terms and conditions.</button>
</label>
</div>
</body>
</html>
18 changes: 18 additions & 0 deletions test/functional/fixtures/regression/gh-6949/pages/with-div.html
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="checkbox">
<input id="checkbox" type="checkbox">
<label for="checkbox" id="checkbox-label">
I have read and accept
<div id="clickable-element" style="background-color: #00FF00; width: 200px; height: 50px;">
terms and conditions.
</div>
</label>
</div>
</body>
</html>
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="checkbox">
<input id="checkbox" type="checkbox">
<label for="checkbox" id="checkbox-label">
I have read and accept
<a id="clickable-element">
terms and conditions.
</a>
</label>
</div>
</body>
</html>
18 changes: 18 additions & 0 deletions test/functional/fixtures/regression/gh-6949/pages/with-link.html
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="checkbox">
<input id="checkbox" type="checkbox">
<label for="checkbox" id="checkbox-label">
I have read and accept
<a id="clickable-element" href="#">
terms and conditions.
</a>
</label>
</div>
</body>
</html>
23 changes: 23 additions & 0 deletions test/functional/fixtures/regression/gh-6949/test.js
@@ -0,0 +1,23 @@
describe('[Regression](GH-6949)', () => {
it('Should change checkbox state when clicking checkbox label', () => {
return runTests('./testcafe-fixtures/with-link.js', 'Click checkbox label');
});

it('Should NOT change checkbox state when clicking a LINK inside the checkbox label', () => {
return runTests('./testcafe-fixtures/with-link.js', 'Click link inside checkbox label');
});

it('Should change checkbox state when clicking a LINK without href attribute inside the checkbox label', () => {
//The behaviour in IE is different, so we should to exclude it from this test:
return runTests('./testcafe-fixtures/with-link-without-href.js', 'Click link without href inside checkbox label', { skip: 'ie' });
});

it('Should NOT change checkbox state when clicking a BUTTON inside the checkbox label', () => {
//The behaviour in IE is different, so we should to exclude it from this test:
return runTests('./testcafe-fixtures/with-button.js', 'Click button inside checkbox label', { skip: 'ie' });
});

it('Should change checkbox state when clicking a DIV with onclick handler inside the checkbox label', () => {
return runTests('./testcafe-fixtures/with-div.js', 'Click div inside checkbox label');
});
});
@@ -0,0 +1,12 @@
import { Selector } from 'testcafe';

fixture`Getting Started`
.page`http://localhost:3000/fixtures/regression/gh-6949/pages/with-button.html`;

test('Click button inside checkbox label', async t => {
const button = Selector('#clickable-element');
const checkBox = Selector('#checkbox');

await t.click(button);
await t.expect(checkBox.checked).eql(false);
});
@@ -0,0 +1,12 @@
import { Selector } from 'testcafe';

fixture`Getting Started`
.page`http://localhost:3000/fixtures/regression/gh-6949/pages/with-div.html`;

test('Click div inside checkbox label', async t => {
const div = Selector('#clickable-element');
const checkBox = Selector('#checkbox');

await t.click(div);
await t.expect(checkBox.checked).eql(true);
});
@@ -0,0 +1,12 @@
import { Selector } from 'testcafe';

fixture`Getting Started`
.page`http://localhost:3000/fixtures/regression/gh-6949/pages/with-link-without-href.html`;

test('Click link without href inside checkbox label', async t => {
const link = Selector('#clickable-element');
const checkBox = Selector('#checkbox');

await t.click(link);
await t.expect(checkBox.checked).eql(true);
});
@@ -0,0 +1,20 @@
import { Selector } from 'testcafe';

fixture`Getting Started`
.page`http://localhost:3000/fixtures/regression/gh-6949/pages/with-link.html`;

test('Click checkbox label', async t => {
const label = Selector('#checkbox-label');
const checkBox = Selector('#checkbox');

await t.click(label);
await t.expect(checkBox.checked).eql(true);
});

test('Click link inside checkbox label', async t => {
const link = Selector('#clickable-element');
const checkBox = Selector('#checkbox');

await t.click(link);
await t.expect(checkBox.checked).eql(false);
});