diff --git a/packages/playwright-core/src/server/injected/recorder.ts b/packages/playwright-core/src/server/injected/recorder.ts
index 0db439e73a..cbaa83e60b 100644
--- a/packages/playwright-core/src/server/injected/recorder.ts
+++ b/packages/playwright-core/src/server/injected/recorder.ts
@@ -315,6 +315,9 @@ export class Recorder {
}
private _shouldGenerateKeyPressFor(event: KeyboardEvent): boolean {
+ // Enter aka. new line is handled in input event.
+ if (event.key === 'Enter' && (this._deepEventTarget(event).nodeName === 'TEXTAREA' || this._deepEventTarget(event).isContentEditable))
+ return false;
// Backspace, Delete, AltGraph are changing input, will handle it there.
if (['Backspace', 'Delete', 'AltGraph'].includes(event.key))
return false;
diff --git a/tests/library/inspector/cli-codegen-1.spec.ts b/tests/library/inspector/cli-codegen-1.spec.ts
index 4a8ff8c331..091bb23aa9 100644
--- a/tests/library/inspector/cli-codegen-1.spec.ts
+++ b/tests/library/inspector/cli-codegen-1.spec.ts
@@ -305,6 +305,21 @@ test.describe('cli codegen', () => {
expect(message.text()).toBe('John');
});
+ test('should fill textarea with new lines at the end', async ({ page, openRecorder }) => {
+ test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23774' });
+ const recorder = await openRecorder();
+ await recorder.setContentAndWait(``);
+ const textarea = page.locator('textarea');
+ await textarea.evaluate(e => e.addEventListener('input', () => (window as any).lastInputValue = e.value));
+ const waitForOutputPromise = recorder.waitForOutput('JavaScript', 'Hello\\n');
+ await textarea.type('Hello\n');
+ // Issue was that the input event was not fired for the last newline, so we check for that.
+ await page.waitForFunction(() => (window as any).lastInputValue === 'Hello\n');
+ const sources = await waitForOutputPromise;
+ expect(sources.get('JavaScript').text).toContain(`await page.locator('#textarea').fill('Hello\\n');`);
+ expect(sources.get('JavaScript').text).not.toContain(`Enter`);
+ });
+
test('should fill [contentEditable]', async ({ page, openRecorder }) => {
const recorder = await openRecorder();