From 389a583e840dd30fbd74d2eca679f71fe706d1d2 Mon Sep 17 00:00:00 2001 From: Darius Jahandarie Date: Wed, 1 Jan 2025 16:38:33 +0900 Subject: [PATCH] More minor playwright performance improvements (#1734) * reduce viewport size on screenshots for popup to make them slightly faster * split dictionary loads into separate tests --- test/playwright/visual.spec.js | 145 ++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 66 deletions(-) diff --git a/test/playwright/visual.spec.js b/test/playwright/visual.spec.js index 87103eb87..4603037fe 100644 --- a/test/playwright/visual.spec.js +++ b/test/playwright/visual.spec.js @@ -36,66 +36,75 @@ test('welcome', async ({page, extensionId}) => { // Take a screenshot of the welcome page await expect.soft(page).toHaveScreenshot('welcome-page.png'); }); -test('settings', async ({page, extensionId}) => { - // Open settings - console.log('Open settings'); - await page.goto(`chrome-extension://${extensionId}/settings.html`); - - await expect(page.locator('id=dictionaries')).toBeVisible(); - - // Get the locator for the disk usage indicator so we can later mask it out of the screenshot - const storage_locator = page.locator('.storage-use-finite >> xpath=..'); - - // Take a simple screenshot of the settings page - await expect.soft(page).toHaveScreenshot('settings-fresh.png', {mask: [storage_locator]}); - - // Load in jmdict_english.zip - console.log('Load in jmdict_english.zip'); - await page.locator('input[id="dictionary-import-file-input"]').setInputFiles(path.join(root, 'dictionaries/jmdict_english.zip')); - await expect(page.locator('id=dictionaries')).toHaveText('Dictionaries (1 installed, 1 enabled)', {timeout: 5 * 60 * 1000}); - - // Take a screenshot of the settings page with jmdict loaded - await expect.soft(page).toHaveScreenshot('settings-jmdict-loaded.png', {mask: [storage_locator]}); - - // Enable advanced settings - // Wait for the advanced settings to be visible - await page.locator('input#advanced-checkbox').evaluate((/** @type {HTMLInputElement} */ element) => element.click()); - - // Import jmdict_swedish.zip from a URL - console.log('Load in jmdict_swedish.zip'); - await page.locator('.settings-item[data-modal-action="show,dictionaries"]').click(); - await page.locator('button[id="dictionary-import-button"]').click(); - await page.locator('textarea[id="dictionary-import-url-text"]').fill('https://github.com/yomidevs/yomitan/raw/dictionaries/jmdict_swedish.zip'); - await page.locator('button[id="dictionary-import-url-button"]').click(); - await expect(page.locator('id=dictionaries')).toHaveText('Dictionaries (2 installed, 2 enabled)', {timeout: 5 * 60 * 1000}); - - // Delete the jmdict_swedish dictionary - await page.locator('button.dictionary-menu-button').nth(1).click(); - await page.locator('button.popup-menu-item[data-menu-action="delete"]').click(); - await page.locator('#dictionary-confirm-delete-button').click(); - await page.locator('#dictionaries-modal button[data-modal-action="hide"]').getByText('Close').click(); - await expect(page.locator('id=dictionaries')).toHaveText('Dictionaries (1 installed, 1 enabled)', {timeout: 5 * 60 * 1000}); - - // Get page height by getting the footer and adding height and y position as other methods of calculation don't work for some reason - const footer = /** @type {import('@playwright/test').ElementHandle} */ (await page.locator('.footer-padding').elementHandle()); - expect(footer).not.toBe(null); - const boundingBox = /** @type {NonNullable['boundingBox']>>>} */ (await footer.boundingBox()); - expect(boundingBox).not.toBe(null); - const pageHeight = Math.ceil(boundingBox.y + boundingBox.height); - - await page.setViewportSize({width: 1280, height: pageHeight}); - - // Wait for any animations or changes to complete - console.log('Waiting for animations to complete'); - await page.waitForTimeout(500); - - // Take a full page screenshot of the settings page with advanced settings enabled - await expect.soft(page).toHaveScreenshot('settings-fresh-full-advanced.png', { - fullPage: true, - mask: [storage_locator], +test.describe('settings', () => { + test('local load of jmdict_english', async ({page, extensionId}) => { + // Open settings + console.log('Open settings'); + await page.goto(`chrome-extension://${extensionId}/settings.html`); + + await expect(page.locator('id=dictionaries')).toBeVisible(); + + // Get the locator for the disk usage indicator so we can later mask it out of the screenshot + const storage_locator = page.locator('.storage-use-finite >> xpath=..'); + + // Take a simple screenshot of the settings page + await expect.soft(page).toHaveScreenshot('settings-fresh.png', {mask: [storage_locator]}); + + // Load in jmdict_english.zip + console.log('Load in jmdict_english.zip'); + await page.locator('input[id="dictionary-import-file-input"]').setInputFiles(path.join(root, 'dictionaries/jmdict_english.zip')); + await expect(page.locator('id=dictionaries')).toHaveText('Dictionaries (1 installed, 1 enabled)', {timeout: 5 * 60 * 1000}); + + // Take a screenshot of the settings page with jmdict loaded + await expect.soft(page).toHaveScreenshot('settings-jmdict-loaded.png', {mask: [storage_locator]}); }); -}); + test('remote load and delete of jmdict_swedish', async ({page, extensionId}) => { + // Open settings + console.log('Open settings'); + await page.goto(`chrome-extension://${extensionId}/settings.html`); + // Enable advanced settings + // Wait for the advanced settings to be visible + await page.locator('input#advanced-checkbox').evaluate((/** @type {HTMLInputElement} */ element) => element.click()); + + // Import jmdict_swedish.zip from a URL + console.log('Load in jmdict_swedish.zip'); + await page.locator('.settings-item[data-modal-action="show,dictionaries"]').click(); + await page.locator('button[id="dictionary-import-button"]').click(); + await page.locator('textarea[id="dictionary-import-url-text"]').fill('https://github.com/yomidevs/yomitan/raw/dictionaries/jmdict_swedish.zip'); + await page.locator('button[id="dictionary-import-url-button"]').click(); + await expect(page.locator('id=dictionaries')).toHaveText('Dictionaries (1 installed, 1 enabled)', {timeout: 5 * 60 * 1000}); + + // Delete the jmdict_swedish dictionary + await page.locator('button.dictionary-menu-button').nth(0).click(); + await page.locator('button.popup-menu-item[data-menu-action="delete"]').click(); + await page.locator('#dictionary-confirm-delete-button').click(); + await page.locator('#dictionaries-modal button[data-modal-action="hide"]').getByText('Close').click(); + await expect(page.locator('id=dictionaries')).toHaveText('Dictionaries (0 installed, 0 enabled)', {timeout: 5 * 60 * 1000}); + + // Get page height by getting the footer and adding height and y position as other methods of calculation don't work for some reason + const footer = /** @type {import('@playwright/test').ElementHandle} */ (await page.locator('.footer-padding').elementHandle()); + expect(footer).not.toBe(null); + const boundingBox = /** @type {NonNullable['boundingBox']>>>} */ (await footer.boundingBox()); + expect(boundingBox).not.toBe(null); + const pageHeight = Math.ceil(boundingBox.y + boundingBox.height); + + await page.setViewportSize({width: 1280, height: pageHeight}); + + // Wait for any animations or changes to complete + console.log('Waiting for animations to complete'); + await page.waitForTimeout(500); + + // Get the locator for the disk usage indicator so we can later mask it out of the screenshot + const storage_locator = page.locator('.storage-use-finite >> xpath=..'); + + // Take a full page screenshot of the settings page with advanced settings enabled + await expect.soft(page).toHaveScreenshot('settings-fresh-full-advanced.png', { + fullPage: true, + mask: [storage_locator], + }); + }); +}); test.describe('popup', () => { test.beforeEach(async ({page, extensionId}) => { // Open settings @@ -115,7 +124,7 @@ test.describe('popup', () => { console.log('Open popup-tests.html'); await page.goto(pathToFileURL(popupTestsPath).toString()); - await page.setViewportSize({width: 1000, height: 4500}); + await page.setViewportSize({width: 700, height: 500}); await expect(page.locator('id=footer')).toBeVisible(); await page.keyboard.down('Shift'); }); @@ -123,30 +132,34 @@ test.describe('popup', () => { const numberOfTests = (readFileSync(popupTestsPath, 'utf8').match(/hovertarget/g) || []).length; for (let i = 1; i <= numberOfTests; i++) { test(`test${i}`, async ({page}) => { + const frame_attached = page.waitForEvent('frameattached', {timeout: 10000}); const test_name = 'doc2-test' + i; console.log(test_name); // Find the test element - const test_locator = page.locator('.hovertarget').nth(i - 1); + const hovertarget_locator = page.locator('.hovertarget').nth(i - 1); + + const testcase_locator = hovertarget_locator.locator('..'); + + await testcase_locator.scrollIntoViewIfNeeded(); - const box = (await test_locator.boundingBox()) || {x: 0, y: 0, width: 0, height: 0}; + const box = (await hovertarget_locator.boundingBox()) || {x: 0, y: 0, width: 0, height: 0}; - const expectedState = (await test_locator.locator('..').getAttribute('data-expected-result')) === 'failure' ? 'hidden' : 'visible'; + const expectedState = (await testcase_locator.getAttribute('data-expected-result')) === 'failure' ? 'hidden' : 'visible'; try { - const frame_attached = page.waitForEvent('frameattached', {timeout: 5000}); await page.mouse.move(box.x - 5, box.y - 5); // Hover near the test - await page.mouse.move(box.x + 15, box.y + 15, {steps: 10}); // Hover over the test + await page.mouse.move(box.x + 15, box.y + 15); // Hover over the test if (expectedState === 'visible') { const popup_frame = await frame_attached; await (await /** @type {import('@playwright/test').Frame} */ (popup_frame).frameElement()) - .waitForElementState(expectedState, {timeout: 500}); + .waitForElementState(expectedState, {timeout: 1000}); } else { expect( await Promise.race([ frame_attached, new Promise((resolve) => { - setTimeout(() => resolve('timeout'), 2000); + setTimeout(() => resolve('timeout'), 1000); }), ]), ).toStrictEqual('timeout');