mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-05 19:04:43 +03:00
feat(recorder): make it work with [contenteditable] (#19066)
https://github.com/microsoft/playwright/issues/19029
This commit is contained in:
parent
1d3feba578
commit
3565d97a36
@ -283,21 +283,20 @@ class Recorder {
|
||||
if (this._mode !== 'recording')
|
||||
return true;
|
||||
const target = this._deepEventTarget(event);
|
||||
if (['INPUT', 'TEXTAREA'].includes(target.nodeName)) {
|
||||
const inputElement = target as HTMLInputElement;
|
||||
const elementType = (inputElement.type || '').toLowerCase();
|
||||
if (['checkbox', 'radio'].includes(elementType)) {
|
||||
// Checkbox is handled in click, we can't let input trigger on checkbox - that would mean we dispatched click events while recording.
|
||||
return;
|
||||
}
|
||||
|
||||
if (elementType === 'file') {
|
||||
globalThis.__pw_recorderRecordAction({
|
||||
name: 'setInputFiles',
|
||||
selector: this._activeModel!.selector,
|
||||
signals: [],
|
||||
files: [...(inputElement.files || [])].map(file => file.name),
|
||||
});
|
||||
if (target.nodeName === 'INPUT' && (target as HTMLInputElement).type.toLowerCase() === 'file') {
|
||||
globalThis.__pw_recorderRecordAction({
|
||||
name: 'setInputFiles',
|
||||
selector: this._activeModel!.selector,
|
||||
signals: [],
|
||||
files: [...((target as HTMLInputElement).files || [])].map(file => file.name),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (['INPUT', 'TEXTAREA'].includes(target.nodeName) || target.isContentEditable) {
|
||||
if (target.nodeName === 'INPUT' && ['checkbox', 'radio'].includes((target as HTMLInputElement).type.toLowerCase())) {
|
||||
// Checkbox is handled in click, we can't let input trigger on checkbox - that would mean we dispatched click events while recording.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -308,7 +307,7 @@ class Recorder {
|
||||
name: 'fill',
|
||||
selector: this._activeModel!.selector,
|
||||
signals: [],
|
||||
text: inputElement.value,
|
||||
text: target.isContentEditable ? target.innerText : (target as HTMLInputElement).value,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -306,6 +306,23 @@ test.describe('cli codegen', () => {
|
||||
expect(message.text()).toBe('John');
|
||||
});
|
||||
|
||||
test('should fill [contentEditable]', async ({ page, openRecorder }) => {
|
||||
const recorder = await openRecorder();
|
||||
|
||||
await recorder.setContentAndWait(`<div id="content" contenteditable="" oninput="console.log(content.innerText)"/>`);
|
||||
const locator = await recorder.focusElement('div');
|
||||
expect(locator).toBe(`locator('#content')`);
|
||||
|
||||
const [message, sources] = await Promise.all([
|
||||
page.waitForEvent('console', msg => msg.type() !== 'error'),
|
||||
recorder.waitForOutput('JavaScript', 'fill'),
|
||||
page.fill('div', 'John Doe')
|
||||
]);
|
||||
expect(sources.get('JavaScript').text).toContain(`
|
||||
await page.locator('#content').fill('John Doe');`);
|
||||
expect(message.text()).toBe('John Doe');
|
||||
});
|
||||
|
||||
test('should press', async ({ page, openRecorder }) => {
|
||||
const recorder = await openRecorder();
|
||||
|
||||
|
@ -159,6 +159,15 @@ it('should fill contenteditable', async ({ page, server }) => {
|
||||
expect(await page.$eval('div[contenteditable]', div => div.textContent)).toBe('some value');
|
||||
});
|
||||
|
||||
it('should fill contenteditable with new lines', async ({ page, server, browserName }) => {
|
||||
it.fixme(browserName === 'firefox', 'Firefox does not handle new lines in contenteditable');
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`<div contenteditable="true"></div>`);
|
||||
await page.locator('div[contenteditable]').fill('John\nDoe');
|
||||
expect(await page.locator('div[contenteditable]').innerText()).toBe('John\nDoe');
|
||||
});
|
||||
|
||||
it('should fill elements with existing value and selection', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user