diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 706c6a390..97e5a96db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -259,7 +259,7 @@ importers: version: 6.3.0(rollup@4.59.0)(typescript@5.9.3) rollup-plugin-license: specifier: ^3.7.0 - version: 3.7.0(picomatch@4.0.3)(rollup@4.59.0) + version: 3.7.0(picomatch@4.0.4)(rollup@4.59.0) tinyglobby: specifier: 'catalog:' version: 0.2.15 @@ -1541,6 +1541,9 @@ importers: '@vitest/browser-playwright': specifier: workspace:* version: link:../../packages/browser-playwright + '@vitest/browser-preview': + specifier: workspace:* + version: link:../../packages/browser-preview happy-dom: specifier: latest version: 20.9.0 @@ -18300,10 +18303,10 @@ snapshots: optionalDependencies: '@babel/code-frame': 7.27.1 - rollup-plugin-license@3.7.0(picomatch@4.0.3)(rollup@4.59.0): + rollup-plugin-license@3.7.0(picomatch@4.0.4)(rollup@4.59.0): dependencies: commenting: 1.1.0 - fdir: 6.5.0(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.4) lodash: 4.17.21 magic-string: 0.30.21 moment: 2.30.1 diff --git a/test/ui/fixtures/browser-preview/basic.test.ts b/test/ui/fixtures/browser-preview/basic.test.ts new file mode 100644 index 000000000..9e2bc3e57 --- /dev/null +++ b/test/ui/fixtures/browser-preview/basic.test.ts @@ -0,0 +1,7 @@ +import { expect, test } from "vitest"; +import { page } from "vitest/browser"; + +test("hello button", async () => { + document.body.innerHTML = ""; + await expect.element(page.getByRole("button")).toHaveTextContent("hello"); +}); diff --git a/test/ui/fixtures/browser-preview/vitest.config.ts b/test/ui/fixtures/browser-preview/vitest.config.ts new file mode 100644 index 000000000..7df7b7bb8 --- /dev/null +++ b/test/ui/fixtures/browser-preview/vitest.config.ts @@ -0,0 +1,67 @@ +import { preview } from "@vitest/browser-preview"; +import { defineConfig, Plugin } from "vitest/config"; +import type { Vitest } from "vitest/node"; + +// run preview provider on headless playwright +// PREVIEW_PLAYWRIGHT=true pnpm -C test/ui test-fixtures --root fixtures/browser-preview +// PREVIEW_PLAYWRIGHT=headless pnpm -C test/ui test-fixtures --root fixtures/browser-preview + +export default defineConfig({ + test: { + browser: { + enabled: true, + traceView: true, + headless: false, + ui: true, + provider: preview(), + instances: [{ browser: "chromium" }], + }, + }, + plugins: [ + customPreviewPlugin(), + ], +}); + +declare global { + var __hackVitest: Vitest; + var __hackOpenBrowser: ((url: string) => void) | undefined; +} + +function customPreviewPlugin(): Plugin { + async function handlePreviewPlaywright(url: string) { + const { chromium } = await import("@playwright/test"); + const browser = await chromium.launch({ + headless: process.env.PREVIEW_PLAYWRIGHT === 'headless', + }); + globalThis.__hackVitest.onClose(async () => { + await browser.close(); + }) + const page = await browser.newPage(); + await page.goto(url); + } + + return { + name: "custom-preview", + configureVitest(context) { + // pass vitest instance through globalThis + // since this config/plugin is loaded twice + // as main vite server and as browser mode vite server + globalThis.__hackVitest = context.vitest; + }, + configureServer(server) { + const overrideOpenBrowser = + process.env.PREVIEW_PLAYWRIGHT + ? handlePreviewPlaywright + : globalThis.__hackOpenBrowser; + if (overrideOpenBrowser) { + server.openBrowser = () => { + const url = server.config.server.open; + if (typeof url !== "string") { + throw new Error(`Invalid preview url ${url}`); + } + overrideOpenBrowser(url); + }; + } + }, + } +} diff --git a/test/ui/package.json b/test/ui/package.json index 0644cc6c1..35edd89bc 100644 --- a/test/ui/package.json +++ b/test/ui/package.json @@ -10,6 +10,7 @@ "@testing-library/dom": "^10.4.1", "@types/codemirror": "^5.60.17", "@vitest/browser-playwright": "workspace:*", + "@vitest/browser-preview": "workspace:*", "happy-dom": "latest", "vitest": "workspace:*" } diff --git a/test/ui/test/browser-preview.spec.ts b/test/ui/test/browser-preview.spec.ts new file mode 100644 index 000000000..e1890ee0d --- /dev/null +++ b/test/ui/test/browser-preview.spec.ts @@ -0,0 +1,33 @@ +import { Writable } from 'node:stream' +import { expect, test } from '@playwright/test' +import { startVitest } from 'vitest/node' +import { assertTestCounts } from './helper' + +test.describe('orchestrator UI on preview provider', () => { + test('basic', async ({ page }) => { + globalThis.__hackOpenBrowser = async (url: string) => { + await page.goto(url) + } + const vitest = await startVitest( + undefined, + { + root: './fixtures/browser-preview', + watch: true, + }, + undefined, + { + stdout: new Writable({ write: (_, __, callback) => callback() }), + stderr: new Writable({ write: (_, __, callback) => callback() }), + }, + ) + + // results in dashboard + await assertTestCounts(page, { pass: 1, fail: 0 }) + + // test code runs in tester iframe + const testerFrame = page.frameLocator('iframe[data-vitest="true"]') + await expect(testerFrame.getByRole('button')).toHaveText('hello') + + await vitest.close() + }) +})