mirror of
https://github.com/microsoft/playwright.git
synced 2024-10-27 05:46:28 +03:00
fix: input events triggered by playwright actions should have composed=true (#28730)
Fixes https://github.com/microsoft/playwright/issues/28726
This commit is contained in:
parent
207585ef63
commit
ff99aa33b0
@ -720,8 +720,8 @@ export class InjectedScript {
|
||||
select.value = undefined as any;
|
||||
selectedOptions.forEach(option => option.selected = true);
|
||||
progress.log(' selected specified option(s)');
|
||||
select.dispatchEvent(new Event('input', { 'bubbles': true }));
|
||||
select.dispatchEvent(new Event('change', { 'bubbles': true }));
|
||||
select.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
||||
select.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
return selectedOptions.map(option => option.value);
|
||||
}
|
||||
|
||||
@ -732,7 +732,7 @@ export class InjectedScript {
|
||||
if (element.nodeName.toLowerCase() === 'input') {
|
||||
const input = element as HTMLInputElement;
|
||||
const type = input.type.toLowerCase();
|
||||
const kInputTypesToSetValue = new Set(['color', 'date', 'time', 'datetime', 'datetime-local', 'month', 'range', 'week']);
|
||||
const kInputTypesToSetValue = new Set(['color', 'date', 'time', 'datetime-local', 'month', 'range', 'week']);
|
||||
const kInputTypesToTypeInto = new Set(['', 'email', 'number', 'password', 'search', 'tel', 'text', 'url']);
|
||||
if (!kInputTypesToTypeInto.has(type) && !kInputTypesToSetValue.has(type)) {
|
||||
progress.log(` input of type "${type}" cannot be filled`);
|
||||
@ -749,8 +749,8 @@ export class InjectedScript {
|
||||
input.value = value;
|
||||
if (input.value !== value)
|
||||
throw this.createStacklessError('Malformed value');
|
||||
element.dispatchEvent(new Event('input', { 'bubbles': true }));
|
||||
element.dispatchEvent(new Event('change', { 'bubbles': true }));
|
||||
element.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
||||
element.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
return 'done'; // We have already changed the value, no need to input it.
|
||||
}
|
||||
} else if (element.nodeName.toLowerCase() === 'textarea') {
|
||||
@ -852,8 +852,8 @@ export class InjectedScript {
|
||||
for (const file of files)
|
||||
dt.items.add(file);
|
||||
input.files = dt.files;
|
||||
input.dispatchEvent(new Event('input', { 'bubbles': true }));
|
||||
input.dispatchEvent(new Event('change', { 'bubbles': true }));
|
||||
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
|
||||
expectHitTarget(hitPoint: { x: number, y: number }, targetElement: Element) {
|
||||
|
@ -89,6 +89,52 @@ it('should fill date input after clicking', async ({ page, server }) => {
|
||||
expect(await page.$eval('input', input => input.value)).toBe('2020-03-02');
|
||||
});
|
||||
|
||||
for (const [type, value] of Object.entries({
|
||||
'color': '#aaaaaa',
|
||||
'date': '2020-03-02',
|
||||
'time': '13:15',
|
||||
'datetime-local': '2020-03-02T13:15:30',
|
||||
'month': '2020-03',
|
||||
'range': '42',
|
||||
'week': '2020-W50'
|
||||
})) {
|
||||
it(`input event.composed should be true and cross shadow dom boundary - ${type}`, async ({ page, server, browserName }) => {
|
||||
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28726' });
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`<body><script>
|
||||
const div = document.createElement('div');
|
||||
const shadowRoot = div.attachShadow({mode: 'open'});
|
||||
shadowRoot.innerHTML = '<input type=${type}></input>';
|
||||
document.body.appendChild(div);
|
||||
</script></body>`);
|
||||
await page.locator('body').evaluate(select => {
|
||||
(window as any).firedBodyEvents = [];
|
||||
for (const event of ['input', 'change']) {
|
||||
select.addEventListener(event, e => {
|
||||
(window as any).firedBodyEvents.push(e.type + ':' + e.composed);
|
||||
}, false);
|
||||
}
|
||||
});
|
||||
|
||||
await page.locator('input').evaluate(select => {
|
||||
(window as any).firedEvents = [];
|
||||
for (const event of ['input', 'change']) {
|
||||
select.addEventListener(event, e => {
|
||||
(window as any).firedEvents.push(e.type + ':' + e.composed);
|
||||
}, false);
|
||||
}
|
||||
});
|
||||
await page.locator('input').fill(value);
|
||||
|
||||
expect(await page.evaluate(() => window['firedEvents'])).toEqual(
|
||||
(browserName !== 'chromium' && (type === 'month' || type === 'week')) ?
|
||||
['input:true'] :
|
||||
['input:true', 'change:false']
|
||||
);
|
||||
expect(await page.evaluate(() => window['firedBodyEvents'])).toEqual(['input:true']);
|
||||
});
|
||||
}
|
||||
|
||||
it('should throw on incorrect date', async ({ page, browserName }) => {
|
||||
it.skip(browserName === 'webkit', 'WebKit does not support date inputs');
|
||||
|
||||
|
@ -287,3 +287,37 @@ it('should wait for multiple options to be present', async ({ page, server }) =>
|
||||
const items = await selectPromise;
|
||||
expect(items).toStrictEqual(['green', 'scarlet']);
|
||||
});
|
||||
|
||||
it('input event.composed should be true and cross shadow dom boundary', async ({ page, server }) => {
|
||||
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28726' });
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`<body><script>
|
||||
const div = document.createElement('div');
|
||||
const shadowRoot = div.attachShadow({mode: 'open'});
|
||||
shadowRoot.innerHTML = \`<select>
|
||||
<option value="black">Black</option>
|
||||
<option value="blue">Blue</option>
|
||||
</select>\`;
|
||||
document.body.appendChild(div);
|
||||
</script></body>`);
|
||||
await page.locator('body').evaluate(select => {
|
||||
(window as any).firedBodyEvents = [];
|
||||
for (const event of ['input', 'change']) {
|
||||
select.addEventListener(event, e => {
|
||||
(window as any).firedBodyEvents.push(e.type + ':' + e.composed);
|
||||
}, false);
|
||||
}
|
||||
});
|
||||
|
||||
await page.locator('select').evaluate(select => {
|
||||
(window as any).firedEvents = [];
|
||||
for (const event of ['input', 'change']) {
|
||||
select.addEventListener(event, e => {
|
||||
(window as any).firedEvents.push(e.type + ':' + e.composed);
|
||||
}, false);
|
||||
}
|
||||
});
|
||||
await page.selectOption('select', 'blue');
|
||||
expect(await page.evaluate(() => window['firedEvents'])).toEqual(['input:true', 'change:false']);
|
||||
expect(await page.evaluate(() => window['firedBodyEvents'])).toEqual(['input:true']);
|
||||
});
|
||||
|
@ -533,6 +533,41 @@ it('should emit input and change events', async ({ page, asset }) => {
|
||||
expect(events[1].type).toBe('change');
|
||||
});
|
||||
|
||||
it('input event.composed should be true and cross shadow dom boundary', async ({ page, server, asset }) => {
|
||||
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28726' });
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`<body><script>
|
||||
const div = document.createElement('div');
|
||||
const shadowRoot = div.attachShadow({mode: 'open'});
|
||||
shadowRoot.innerHTML = '<input type=file></input>';
|
||||
document.body.appendChild(div);
|
||||
</script></body>`);
|
||||
await page.locator('body').evaluate(select => {
|
||||
(window as any).firedBodyEvents = [];
|
||||
for (const event of ['input', 'change']) {
|
||||
select.addEventListener(event, e => {
|
||||
(window as any).firedBodyEvents.push(e.type + ':' + e.composed);
|
||||
}, false);
|
||||
}
|
||||
});
|
||||
|
||||
await page.locator('input').evaluate(select => {
|
||||
(window as any).firedEvents = [];
|
||||
for (const event of ['input', 'change']) {
|
||||
select.addEventListener(event, e => {
|
||||
(window as any).firedEvents.push(e.type + ':' + e.composed);
|
||||
}, false);
|
||||
}
|
||||
});
|
||||
await page.locator('input').setInputFiles({
|
||||
name: 'test.txt',
|
||||
mimeType: 'text/plain',
|
||||
buffer: Buffer.from('this is a test')
|
||||
});
|
||||
expect(await page.evaluate(() => window['firedEvents'])).toEqual(['input:true', 'change:false']);
|
||||
expect(await page.evaluate(() => window['firedBodyEvents'])).toEqual(['input:true']);
|
||||
});
|
||||
|
||||
it('should work for single file pick', async ({ page, server }) => {
|
||||
await page.setContent(`<input type=file>`);
|
||||
const [fileChooser] = await Promise.all([
|
||||
|
Loading…
Reference in New Issue
Block a user