diff --git a/packages/labs/prefetch/playwright.config.js b/packages/labs/prefetch/playwright.config.js new file mode 100644 index 000000000..c8353201f --- /dev/null +++ b/packages/labs/prefetch/playwright.config.js @@ -0,0 +1,41 @@ +import { devices } from '@playwright/test'; + +const config = { + testMatch: 'test/*.test.js', + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* Fail the build on CI if you accidentally left test in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 5 : 0, + /* Opt out of parallel tests on CI. */ + workers: 1, + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + projects: [ + { + name: 'Chrome Stable', + use: { + browserName: 'chromium', + channel: 'chrome', + }, + }, + ], +}; + +export default config; diff --git a/packages/labs/prefetch/src/client.ts b/packages/labs/prefetch/src/client.ts index 34b61a952..4a8602d3e 100644 --- a/packages/labs/prefetch/src/client.ts +++ b/packages/labs/prefetch/src/client.ts @@ -58,11 +58,9 @@ async function preloadHref(link: HTMLAnchorElement) { export interface PrefetchOptions { selectors?: string | HTMLAnchorElement[]; - root?: ParentNode; } export default function prefetch({ - root = document, selectors = 'a[href][rel="prefetch"]', }: PrefetchOptions) { const [toAdd, isDone] = throttle(); @@ -79,7 +77,7 @@ export default function prefetch({ requestIdleCallback(() => { const links = Array.from( - typeof selectors === 'string' ? root.querySelectorAll(selectors) : selectors + typeof selectors === 'string' ? document.querySelectorAll(selectors) : selectors ).filter(shouldPreload); for (const link of links) { diff --git a/packages/labs/prefetch/test/basic-prefetch.test.js b/packages/labs/prefetch/test/basic-prefetch.test.js index ae34561ac..897c00590 100644 --- a/packages/labs/prefetch/test/basic-prefetch.test.js +++ b/packages/labs/prefetch/test/basic-prefetch.test.js @@ -3,60 +3,62 @@ import { testFactory } from './test-utils.js'; const test = testFactory({ root: './fixtures/basic-prefetch/' }); -test.describe('dev', () => { - let devServer; +test.describe('Basic prefetch', () => { + test.describe('dev', () => { + let devServer; - test.beforeEach(async ({ astro }) => { - devServer = await astro.startDevServer(); + test.beforeEach(async ({ astro }) => { + devServer = await astro.startDevServer(); + }); + + test.afterEach(async () => { + await devServer.stop(); + }); + + test.describe('prefetches rel="prefetch" links', () => { + test('skips /admin', async ({ page, astro }) => { + const requests = new Set(); + + page.on('request', async (request) => requests.add(request.url())); + + await page.goto(astro.resolveUrl('/')); + + await page.waitForLoadState('networkidle'); + + await expect(requests.has(astro.resolveUrl('/about')), '/about was prefetched').toBeTruthy(); + await expect(requests.has(astro.resolveUrl('/contact')), '/contact was prefetched').toBeTruthy(); + await expect(requests.has(astro.resolveUrl('/admin')), '/admin was skipped').toBeFalsy(); + }); + }); }); - test.afterEach(async () => { - await devServer.stop(); - }); + test.describe('build', () => { + let previewServer; - test.describe('prefetches rel="prefetch" links', () => { - test('skips /admin', async ({ page, astro }) => { - const requests = new Set(); + test.beforeAll(async ({ astro }) => { + await astro.build(); + previewServer = await astro.preview(); + }); - page.on('request', async (request) => requests.add(request.url())); + // important: close preview server (free up port and connection) + test.afterAll(async () => { + await previewServer.stop(); + }); - await page.goto(astro.resolveUrl('/')); + test.describe('prefetches rel="prefetch" links', () => { + test('skips /admin', async ({ page, astro }) => { + const requests = new Set(); - await page.waitForLoadState('networkidle'); + page.on('request', async (request) => requests.add(request.url())); - await expect(requests.has(astro.resolveUrl('/about'))).toBeTruthy(); - await expect(requests.has(astro.resolveUrl('/contact'))).toBeTruthy(); - await expect(requests.has(astro.resolveUrl('/admin'))).toBeFalsy(); - }); - }); -}); - -test.describe('build', () => { - let previewServer; - - test.beforeAll(async ({ astro }) => { - await astro.build(); - previewServer = await astro.preview(); - }); - - // important: close preview server (free up port and connection) - test.afterAll(async () => { - await previewServer.stop(); - }); - - test.describe('prefetches rel="prefetch" links', () => { - test('skips /admin', async ({ page, astro }) => { - const requests = new Set(); - - page.on('request', async (request) => requests.add(request.url())); - - await page.goto(astro.resolveUrl('/')); - - await page.waitForLoadState('networkidle'); - - await expect(requests.has(astro.resolveUrl('/about'))).toBeTruthy(); - await expect(requests.has(astro.resolveUrl('/contact'))).toBeTruthy(); - await expect(requests.has(astro.resolveUrl('/admin'))).toBeFalsy(); + await page.goto(astro.resolveUrl('/')); + + await page.waitForLoadState('networkidle'); + + await expect(requests.has(astro.resolveUrl('/about')), '/about was prefetched').toBeTruthy(); + await expect(requests.has(astro.resolveUrl('/contact')), '/contact was prefetched').toBeTruthy(); + await expect(requests.has(astro.resolveUrl('/admin')), '/admin was skipped').toBeFalsy(); + }); }); }); }); diff --git a/packages/labs/prefetch/test/custom-selectors.test.js b/packages/labs/prefetch/test/custom-selectors.test.js new file mode 100644 index 000000000..83a497456 --- /dev/null +++ b/packages/labs/prefetch/test/custom-selectors.test.js @@ -0,0 +1,72 @@ +import { expect } from '@playwright/test'; +import { testFactory } from './test-utils.js'; +import prefetch from '../dist/index.js'; + +const test = testFactory({ + root: './fixtures/basic-prefetch/', + integrations: [ + prefetch({ + selectors: 'a[href="/admin"]' + }), + ] +}); + +test.describe('Custom prefetch selectors', () => { + test.describe('dev', () => { + let devServer; + + test.beforeEach(async ({ astro }) => { + devServer = await astro.startDevServer(); + }); + + test.afterEach(async () => { + await devServer.stop(); + }); + + test.describe('prefetches links by custom selector', () => { + test('only prefetches /contact', async ({ page, astro }) => { + const requests = new Set(); + + page.on('request', async (request) => requests.add(request.url())); + + await page.goto(astro.resolveUrl('/')); + + await page.waitForLoadState('networkidle'); + + await expect(requests.has(astro.resolveUrl('/about')), '/about was skipped').toBeFalsy(); + await expect(requests.has(astro.resolveUrl('/contact')), '/contact was prefetched').toBeTruthy(); + await expect(requests.has(astro.resolveUrl('/admin')), '/admin was skipped').toBeFalsy(); + }); + }); + }); + + test.describe('build', () => { + let previewServer; + + test.beforeAll(async ({ astro }) => { + await astro.build(); + previewServer = await astro.preview(); + }); + + // important: close preview server (free up port and connection) + test.afterAll(async () => { + await previewServer.stop(); + }); + + test.describe('prefetches links by custom selector', () => { + test('only prefetches /contact', async ({ page, astro }) => { + const requests = new Set(); + + page.on('request', async (request) => requests.add(request.url())); + + await page.goto(astro.resolveUrl('/')); + + await page.waitForLoadState('networkidle'); + + await expect(requests.has(astro.resolveUrl('/about')), '/about was skipped').toBeFalsy(); + await expect(requests.has(astro.resolveUrl('/contact')), '/contact was prefetched').toBeTruthy(); + await expect(requests.has(astro.resolveUrl('/admin')), '/admin was skipped').toBeFalsy(); + }); + }); + }); +}); diff --git a/packages/labs/prefetch/test/fixtures/basic-prefetch/src/pages/index.astro b/packages/labs/prefetch/test/fixtures/basic-prefetch/src/pages/index.astro index 1aa921c58..d2c674ebc 100644 --- a/packages/labs/prefetch/test/fixtures/basic-prefetch/src/pages/index.astro +++ b/packages/labs/prefetch/test/fixtures/basic-prefetch/src/pages/index.astro @@ -13,13 +13,14 @@
  • About
  • -
  • - Contact -
  • Admin
  • + +