From c0bd9da29132a530de37d7113dca8c31fa09e3f4 Mon Sep 17 00:00:00 2001 From: Tony Sullivan Date: Sun, 15 May 2022 12:08:47 -0600 Subject: [PATCH] adding a basic HMR test for tailwind styles --- packages/astro/e2e/tailwindcss.test.js | 25 +++++++++++++++++++++++- packages/astro/e2e/test-utils.js | 4 ++++ packages/astro/src/runtime/client/hmr.ts | 8 ++++++-- packages/astro/test/test-utils.js | 18 ++++++++++++++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/astro/e2e/tailwindcss.test.js b/packages/astro/e2e/tailwindcss.test.js index e156a7be7f..0de09e8559 100644 --- a/packages/astro/e2e/tailwindcss.test.js +++ b/packages/astro/e2e/tailwindcss.test.js @@ -1,5 +1,5 @@ import { test as base, expect } from '@playwright/test'; -import { loadFixture } from './test-utils.js'; +import { loadFixture, onAfterHMR } from './test-utils.js'; const test = base.extend({ astro: async ({}, use) => { @@ -18,6 +18,10 @@ test.afterAll(async ({ astro }) => { await devServer.stop(); }); +test.afterEach(async ({ astro }) => { + astro.clean(); +}); + test('Tailwind CSS', async ({ page, astro }) => { await page.goto(astro.resolveUrl('/')); @@ -48,4 +52,23 @@ test('Tailwind CSS', async ({ page, astro }) => { await expect(button, 'should have font-[900]').toHaveClass(/font-\[900\]/); await expect(button, 'should have font weight').toHaveCSS('font-weight', '900'); }); + + await test.step('HMR', async () => { + const afterHMR = onAfterHMR(page); + + await astro.writeFile( + 'src/components/Button.astro', + (original) => original.replace('bg-purple-600', 'bg-purple-400') + ); + + await afterHMR; + + const button = page.locator('button'); + + await expect(button, 'should have bg-purple-400').toHaveClass(/bg-purple-400/); + await expect(button, 'should have background color').toHaveCSS( + 'background-color', + 'rgb(192, 132, 252)' + ); + }); }); diff --git a/packages/astro/e2e/test-utils.js b/packages/astro/e2e/test-utils.js index e2552042c9..614491401f 100644 --- a/packages/astro/e2e/test-utils.js +++ b/packages/astro/e2e/test-utils.js @@ -11,3 +11,7 @@ export function loadFixture(inlineConfig) { root: new URL(inlineConfig.root, import.meta.url).toString() }) } + +export function onAfterHMR(page) { + return page.waitForEvent('console', message => message.text() === 'astro:hmr:after') +} diff --git a/packages/astro/src/runtime/client/hmr.ts b/packages/astro/src/runtime/client/hmr.ts index 7cd7732569..119ba87546 100644 --- a/packages/astro/src/runtime/client/hmr.ts +++ b/packages/astro/src/runtime/client/hmr.ts @@ -14,7 +14,11 @@ if (import.meta.hot) { root.innerHTML = current?.innerHTML; } } - return diff(document, doc); + const result = diff(document, doc); + + // event used for synchronizing E2E tests + console.log('astro:hmr:after'); + return result; } async function updateAll(files: any[]) { let hasAstroUpdate = false; @@ -31,7 +35,7 @@ if (import.meta.hot) { } } if (hasAstroUpdate) { - return updatePage(); + return await updatePage(); } } import.meta.hot.on('vite:beforeUpdate', async (event) => { diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index bc7ff3f0b2..c351b0dfaa 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -28,6 +28,7 @@ polyfill(globalThis, { * @property {(url: string) => string} resolveUrl * @property {(url: string, opts: any) => Promise} fetch * @property {(path: string) => Promise} readFile + * @property {(path: string, updater: (content: string) => string) => Promise} writeFile * @property {(path: string) => Promise} readdir * @property {() => Promise} startDevServer * @property {() => Promise} preview @@ -96,6 +97,17 @@ export async function loadFixture(inlineConfig) { const resolveUrl = (url) => `http://${'127.0.0.1'}:${config.server.port}${url.replace(/^\/?/, '/')}`; + let cleanupCallbacks = []; + + async function writeFile(filePath, updater) { + const pathname = new URL(filePath.replace(/^\//, ''), config.root); + const initial = await fs.promises.readFile(pathname, 'utf8'); + + await fs.promises.writeFile(pathname, updater(initial), 'utf-8'); + + cleanupCallbacks.push(() => fs.promises.writeFile(pathname, initial, 'utf-8')); + } + return { build: (opts = {}) => build(config, { mode: 'development', logging, telemetry, ...opts }), startDevServer: async (opts = {}) => { @@ -113,8 +125,12 @@ export async function loadFixture(inlineConfig) { }, readFile: (filePath) => fs.promises.readFile(new URL(filePath.replace(/^\//, ''), config.outDir), 'utf8'), + writeFile, readdir: (fp) => fs.promises.readdir(new URL(fp.replace(/^\//, ''), config.outDir)), - clean: () => fs.promises.rm(config.outDir, { maxRetries: 10, recursive: true, force: true }), + clean: async () => { + await fs.promises.rm(config.outDir, { maxRetries: 10, recursive: true, force: true }); + await Promise.all(cleanupCallbacks.map(cb => cb())); + }, loadTestAdapterApp: async () => { const url = new URL('./server/entry.mjs', config.outDir); const { createApp } = await import(url);