From a0f9e7b4fb849f42a491fd9685055aa28bc47b97 Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Sat, 21 Dec 2024 17:29:16 +0000 Subject: [PATCH] test(player): play in incognito --- tests/crx/crxRecorderTest.ts | 13 ++++- tests/crx/player-incognito.spec.ts | 76 ++++++++++++++++++++++++++++++ tests/crx/recorder-edit.spec.ts | 26 +--------- tests/crx/utils.ts | 26 +++++++++- 4 files changed, 113 insertions(+), 28 deletions(-) create mode 100644 tests/crx/player-incognito.spec.ts diff --git a/tests/crx/crxRecorderTest.ts b/tests/crx/crxRecorderTest.ts index d5a2b404b..0e7d1a7f7 100644 --- a/tests/crx/crxRecorderTest.ts +++ b/tests/crx/crxRecorderTest.ts @@ -24,6 +24,13 @@ export { expect } from './crxTest'; declare function attach(tab: chrome.tabs.Tab): Promise; declare function _setUnderTest(): void; +type SettingOptions = { + testIdAttributeName?: string, + targetLanguage?: string, + playInIncognito?: boolean, + experimental?: boolean +}; + export function dumpLogHeaders(recorderPage: Page) { return async () => { return await recorderPage.evaluate(() => { @@ -75,7 +82,7 @@ export const test = crxTest.extend<{ recorderPage: Page; recordAction(action: () => Promise): Promise; recordAssertion(locator: Locator, type: AssertAction['name']): Promise; - configureRecorder: (config: { testIdAttributeName?: string, targetLanguage?: string, experimental?: boolean }) => Promise; + configureRecorder: (config: SettingOptions) => Promise; }>({ extensionPath: path.join(__dirname, '../../examples/recorder-crx/dist'), @@ -160,7 +167,7 @@ export const test = crxTest.extend<{ }, configureRecorder: async ({ context, extensionId }, run) => { - await run(async ({ testIdAttributeName, targetLanguage, experimental }: { testIdAttributeName?: string, targetLanguage?: string, experimental?: boolean }) => { + await run(async ({ testIdAttributeName, targetLanguage, playInIncognito, experimental }: SettingOptions) => { const configPage = await context.newPage(); try { await configPage.goto(`chrome-extension://${extensionId}/preferences.html`); @@ -168,6 +175,8 @@ export const test = crxTest.extend<{ await configPage.locator('#target-language').selectOption(targetLanguage); if (testIdAttributeName) await configPage.locator('#test-id').fill(testIdAttributeName); + if (playInIncognito !== undefined) + await configPage.locator('#playInIncognito').setChecked(playInIncognito); if (experimental !== undefined) await configPage.locator('#experimental').setChecked(experimental); await configPage.locator('#submit').click(); diff --git a/tests/crx/player-incognito.spec.ts b/tests/crx/player-incognito.spec.ts new file mode 100644 index 000000000..18408b1a6 --- /dev/null +++ b/tests/crx/player-incognito.spec.ts @@ -0,0 +1,76 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { dumpLogHeaders, expect, test } from './crxRecorderTest'; +import { editCode } from './utils'; + +test('should play in incognito', async ({ configureRecorder, attachRecorder, page, baseURL, extensionServiceWorker }) => { + await configureRecorder({ playInIncognito: true }); + + const recorderPage = await attachRecorder(page); + await recorderPage.getByTitle('Record').click(); + + editCode(recorderPage, `import { test, expect } from '@playwright/test'; + +test('test', async ({ page }) => { + await page.goto('${baseURL}/input/textarea.html'); + await page.locator('textarea').fill('some test'); +});`); + + const incognitoPagePromise = extensionServiceWorker.evaluate(url => new Promise(resolve => { + chrome.tabs.onUpdated.addListener((_, changes, tab) => { + if (!tab.incognito || changes.url !== url) + return; + resolve(); + }); + }), `${baseURL}/input/textarea.html`); + + await recorderPage.getByTitle('Resume (F8)').click(); + await incognitoPagePromise; + + await expect.poll(dumpLogHeaders(recorderPage)).toEqual([ + `► page.goto( ${baseURL}/input/textarea.html ) ✅ — XXms`, + `► page.locator('textarea') .fill() ✅ — XXms`, + ]); +}); + +test('should close and reopen incognito window on replay', async ({ configureRecorder, attachRecorder, page, baseURL, extensionServiceWorker }) => { + await configureRecorder({ playInIncognito: true }); + + const recorderPage = await attachRecorder(page); + await recorderPage.getByTitle('Record').click(); + + editCode(recorderPage, `import { test, expect } from '@playwright/test'; + +test('test', async ({ page }) => { + await page.goto('${baseURL}/input/textarea.html'); + await page.locator('textarea').fill('some test'); +});`); + + await recorderPage.getByTitle('Resume (F8)').click(); + await expect(recorderPage.getByTitle('Resume (F8)')).not.toBeDisabled(); + + const getIncognitoTabIds = async () => await extensionServiceWorker.evaluate(() => chrome.tabs.query({}).then(ts => ts.filter(t => t.incognito).map(t => t.id!))); + const tabIds = await getIncognitoTabIds(); + expect(tabIds).toHaveLength(1); + + await recorderPage.getByTitle('Resume (F8)').click(); + await expect(recorderPage.getByTitle('Resume (F8)')).not.toBeDisabled(); + + const newTabIds = await getIncognitoTabIds(); + expect(newTabIds).toHaveLength(1); + expect(newTabIds[0]).not.toEqual(tabIds[0]); +}); \ No newline at end of file diff --git a/tests/crx/recorder-edit.spec.ts b/tests/crx/recorder-edit.spec.ts index dcf437d03..cdfb49e3d 100644 --- a/tests/crx/recorder-edit.spec.ts +++ b/tests/crx/recorder-edit.spec.ts @@ -14,33 +14,9 @@ * limitations under the License. */ -import type { Page } from '@playwright/test'; import { test, expect } from './crxRecorderTest'; import type { CrxApplication } from '../../test'; - -async function editCode(recorderPage: Page, code: string) { - const editor = recorderPage.locator('.CodeMirror textarea').first(); - await editor.press('ControlOrMeta+a'); - await editor.fill(code); -} - -async function getCode(recorderPage: Page): Promise { - return await recorderPage.locator('.CodeMirror').first().evaluate((elem: any) => elem.CodeMirror.getValue()); -} - -async function moveCursorToLine(recorderPage: Page, line: number) { - await recorderPage.locator('.CodeMirror').first().evaluate((elem: any, line) => elem.CodeMirror.setCursor({ - // codemirror line is 0-based - line: line - 1, - ch: 0, - }), line); -} - -function editorLine(recorderPage: Page, linenumber: number) { - return recorderPage.locator('.CodeMirror-code > div') - .filter({ has: recorderPage.locator('.CodeMirror-linenumber', { hasText: String(linenumber) }) }) - .locator('.CodeMirror-line'); -} +import { editCode, editorLine, getCode, moveCursorToLine } from './utils'; test('should edit @smoke', async ({ page, attachRecorder, baseURL }) => { const recorderPage = await attachRecorder(page); diff --git a/tests/crx/utils.ts b/tests/crx/utils.ts index 206dfaa27..76989cc7e 100644 --- a/tests/crx/utils.ts +++ b/tests/crx/utils.ts @@ -152,4 +152,28 @@ export async function parseTraceRaw(file: string): Promise<{ events: any[], reso actionObjects, stacks, }; -} \ No newline at end of file +} + +export async function editCode(recorderPage: Page, code: string) { + const editor = recorderPage.locator('.CodeMirror textarea').first(); + await editor.press('ControlOrMeta+a'); + await editor.fill(code); +} + +export async function getCode(recorderPage: Page): Promise { + return await recorderPage.locator('.CodeMirror').first().evaluate((elem: any) => elem.CodeMirror.getValue()); +} + +export async function moveCursorToLine(recorderPage: Page, line: number) { + await recorderPage.locator('.CodeMirror').first().evaluate((elem: any, line) => elem.CodeMirror.setCursor({ + // codemirror line is 0-based + line: line - 1, + ch: 0, + }), line); +} + +export function editorLine(recorderPage: Page, linenumber: number) { + return recorderPage.locator('.CodeMirror-code > div') + .filter({ has: recorderPage.locator('.CodeMirror-linenumber', { hasText: String(linenumber) }) }) + .locator('.CodeMirror-line'); +}