UNPKG

@stencil/playwright

Version:

Testing adapter to use Playwright with Stencil

151 lines (146 loc) 5.4 kB
// src/wizard.ts import { access, readdir, readFile, writeFile } from "node:fs/promises"; import { join } from "node:path"; async function fileExists(path) { try { await access(path); return true; } catch { return false; } } function detectOutputTargets(config) { const outputs = config.outputTargets; const www = outputs.some((o) => o.type === "www"); const loaderBundle = outputs.some((o) => o.type === "loader-bundle"); return { www, loaderBundle }; } var PLAYWRIGHT_CONFIG_TEMPLATE = `import { expect } from '@playwright/test'; import { matchers, createConfig } from '@stencil/playwright'; // Add custom Stencil matchers to Playwright assertions expect.extend(matchers); export default createConfig({ // Overwrite Playwright config options here }); `; function e2eSpecTemplate(tagName) { return `import { expect } from '@playwright/test'; import { test } from '@stencil/playwright'; test.describe('${tagName}', () => { test('renders', async ({ page }) => { await page.setContent('<${tagName}></${tagName}>'); const el = page.locator('${tagName}'); await expect(el).toBeAttached(); }); }); `; } async function ensureDisposableLib(rootDir) { const tsconfigPath = join(rootDir, "tsconfig.json"); if (!await fileExists(tsconfigPath)) return; try { const tsconfig = JSON.parse(await readFile(tsconfigPath, "utf8")); const lib = tsconfig.compilerOptions?.lib ?? []; if (lib.some((l) => l.toLowerCase() === "esnext.disposable")) return; tsconfig.compilerOptions ??= {}; tsconfig.compilerOptions.lib = [...lib, "ESNext.Disposable"]; await writeFile(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n", "utf8"); } catch { } } async function ensureOutputTarget(context) { const { config, prompts } = context; const { www, loaderBundle } = detectOutputTargets(config); if (www || loaderBundle) return; const stencilConfigPath = join(config.rootDir, "stencil.config.ts"); if (!await fileExists(stencilConfigPath)) { return; } const addWww = await prompts.confirm({ message: 'No "www" or "loader-bundle" output target found. Add a "www" output target now?', initialValue: true }); if (!prompts.isCancel(addWww) && addWww) { const editor = await context.openStencilConfig(); editor.addOutputTarget("{ type: 'www', serviceWorker: null }"); await editor.save(); return; } prompts.log.warn( 'No "www" or "loader-bundle" output target configured - Playwright tests may not have anything to run against.' ); } async function updatePackageJsonScripts(rootDir) { const pkgPath = join(rootDir, "package.json"); const pkg = JSON.parse(await readFile(pkgPath, "utf8")); pkg.scripts ??= {}; pkg.scripts["test:e2e"] ??= "playwright test"; await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8"); } async function generateExampleTests(rootDir) { const componentsDir = join(rootDir, "src", "components"); const entries = await readdir(componentsDir, { withFileTypes: true }).catch(() => []); for (const entry of entries) { if (!entry.isDirectory()) continue; const componentFile = join(componentsDir, entry.name, `${entry.name}.tsx`); if (!await fileExists(componentFile)) continue; const source = await readFile(componentFile, "utf8"); if (!source.includes("@Component")) continue; const tagMatch = source.match(/tag:\s*['"]([^'"]+)['"]/); const tagName = tagMatch?.[1] ?? entry.name; const specFile = join(componentsDir, entry.name, `${tagName}.e2e.ts`); if (await fileExists(specFile)) continue; await writeFile(specFile, e2eSpecTemplate(tagName), "utf8"); } } var wizard = { init: { id: "@stencil/playwright", displayName: "Playwright", description: "E2E testing", async run(context) { const { config, isNewProject, prompts, nypm } = context; const { intro, outro, confirm, isCancel, cancel, spinner } = prompts; const rootDir = config.rootDir; intro("Playwright - E2E testing for Stencil"); const playwrightConfigPath = join(rootDir, "playwright.config.ts"); if (!isNewProject && await fileExists(playwrightConfigPath)) { const overwrite = await confirm({ message: "playwright.config.ts already exists. Overwrite it?", initialValue: false }); if (isCancel(overwrite) || !overwrite) { cancel("Skipping Playwright setup - existing config kept."); return; } } const s = spinner(); s.start("Installing dependencies"); await nypm.addDependency(["@playwright/test"], { cwd: rootDir, dev: true }); s.stop("Dependencies installed"); await writeFile(playwrightConfigPath, PLAYWRIGHT_CONFIG_TEMPLATE, "utf8"); await ensureDisposableLib(rootDir); await ensureOutputTarget(context); await updatePackageJsonScripts(rootDir); if (isNewProject) { await generateExampleTests(rootDir); } prompts.log.info('Run "npx playwright install" to download the browser binaries before running tests.'); outro("Playwright configured"); } }, generate: { fileTemplates: [ { label: "E2E test (.e2e.ts)", extension: "e2e.ts", selectedByDefault: true, template: (tagName) => e2eSpecTemplate(tagName) } ] } }; export { wizard }; //# sourceMappingURL=wizard.js.map