From 1212ca0488dbc9db65bc4bd07e901ea769d9d904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Berg=C3=A9?= Date: Tue, 14 Jan 2025 15:54:59 +0100 Subject: [PATCH 1/8] Stabilize the table of content scrolling in visual tests --- packages/gitbook/e2e/pages.spec.ts | 82 +++++++++++++++---- .../TableOfContents/TOCScroller.tsx | 2 +- .../TableOfContents/TableOfContents.tsx | 1 + 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/packages/gitbook/e2e/pages.spec.ts b/packages/gitbook/e2e/pages.spec.ts index 485ca5030..0c1a8ee07 100644 --- a/packages/gitbook/e2e/pages.spec.ts +++ b/packages/gitbook/e2e/pages.spec.ts @@ -27,12 +27,40 @@ import { getContentTestURL } from '../tests/utils'; interface Test { name: string; - url: string; // URL to visit for testing + /** + * URL to visit for testing. + */ + url: string; cookies?: Parameters[0]; - run?: (page: Page) => Promise; // The test to run - fullPage?: boolean; // Whether the test should be fullscreened during testing - screenshot?: false | { threshold: number }; // Disable screenshot or set threshold - only?: boolean; // Only run this test + /** + * Test to run + */ + run?: (page: Page) => Promise; + /** + * Whether the test should be fullscreened during testing. + */ + fullPage?: boolean; + /** + * Whether to take a screenshot of the test or set a threshold for the screenshot. + */ + screenshot?: + | false + | { + /** + * Screenshot threshold. + * From 0 to 1, where 0 is the most strict and 1 is the most permissive. + * @default 0.5 + */ + threshold?: number; + /** + * Whether to wait for the table of contents to finish scrolling before taking the screenshot. + */ + waitForTOCScrolling?: boolean; + }; + /** + * Whether to only run this test. + */ + only?: boolean; } interface TestsCase { @@ -323,6 +351,9 @@ const testCases: TestsCase[] = [ { name: 'PDF', url: '~gitbook/pdf?limit=10', + screenshot: { + waitForTOCScrolling: false, + }, }, ], }, @@ -474,6 +505,9 @@ const testCases: TestsCase[] = [ name: 'With cover and no TOC', url: 'page-options/page-with-cover-and-no-toc', run: waitForCookiesDialog, + screenshot: { + waitForTOCScrolling: false, + }, }, { name: 'With icon', @@ -662,6 +696,7 @@ const testCases: TestsCase[] = [ expect(url.includes('shared-space-uno')).toBeTruthy(); // same uno site expect(url.endsWith('/shared')).toBeTruthy(); // correct page }, + screenshot: false, }, ], }, @@ -680,6 +715,7 @@ const testCases: TestsCase[] = [ expect(url.includes('shared-space-dos')).toBeTruthy(); // same dos site expect(url.endsWith('/shared')).toBeTruthy(); // correct page }, + screenshot: false, }, ], }, @@ -1377,20 +1413,23 @@ for (const testCase of testCases) { if (testEntry.run) { await testEntry.run(page); } - if (testEntry.screenshot !== false) { - await scrollTOCToTop(page); + const screenshotOptions = testEntry.screenshot; + if (screenshotOptions !== false) { await argosScreenshot(page, `${testCase.name} - ${testEntry.name}`, { - viewports: ['macbook-16', 'macbook-13', 'iphone-x', 'ipad-2'], + viewports: ['macbook-16', 'macbook-13', 'ipad-2', 'iphone-x'], argosCSS: ` /* Hide Intercom */ .intercom-lightweight-app { display: none !important; - } - `, - threshold: testEntry.screenshot?.threshold ?? undefined, + } + `, + threshold: screenshotOptions?.threshold ?? undefined, fullPage: testEntry.fullPage ?? false, beforeScreenshot: async () => { await waitForIcons(page); + if (screenshotOptions?.waitForTOCScrolling !== false) { + await waitForTOCScrolling(page); + } }, }); } @@ -1501,10 +1540,21 @@ async function waitForIcons(page: Page) { } /** - * Scroll the table of contents to the top to stabilize the screenshot. + * Wait for TOC to be correctly scrolled into view. */ -async function scrollTOCToTop(page: Page) { - await page.evaluate(() => { - document.querySelector('[data-testid=toc-container]')?.scrollTo(0, 0); - }); +async function waitForTOCScrolling(page: Page) { + const viewport = await page.viewportSize(); + if (viewport && viewport.width >= 1024) { + const toc = page.getByTestId('table-of-contents'); + await expect(toc).toBeVisible(); + await page.evaluate(() => { + const tocScrollContainer = document.querySelector( + '[data-testid="table-of-contents"] [data-testid="toc-scroll-container"]', + ); + if (!tocScrollContainer) { + throw new Error('TOC scroll container not found'); + } + tocScrollContainer.scrollTo(0, 0); + }); + } } diff --git a/packages/gitbook/src/components/TableOfContents/TOCScroller.tsx b/packages/gitbook/src/components/TableOfContents/TOCScroller.tsx index 46a0560bb..94f16d399 100644 --- a/packages/gitbook/src/components/TableOfContents/TOCScroller.tsx +++ b/packages/gitbook/src/components/TableOfContents/TOCScroller.tsx @@ -28,7 +28,7 @@ export function TOCScrollContainer(props: {
diff --git a/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx b/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx index 8f2ebe7e7..d549c3758 100644 --- a/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx +++ b/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx @@ -49,6 +49,7 @@ export function TableOfContents(props: { return (