Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 12 additions & 24 deletions src/test/wizard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ function makeSpinner() {
return { start: vi.fn(), stop: vi.fn() };
}

function makeInitCtx(
rootDir: string,
outputTargets: Array<{ type: string; copy?: Array<{ src?: string }> }> = [],
isNewProject = false,
) {
function makeInitCtx(rootDir: string, outputTargets: Array<{ type: string }> = [], isNewProject = false) {
return {
config: { rootDir, fsNamespace: 'my-lib', outputTargets },
isNewProject,
Expand Down Expand Up @@ -85,7 +81,7 @@ describe('wizard.init.run', () => {
it('proceeds and overwrites when user accepts overwrite', async () => {
writeFileSync(join(tmpDir, 'playwright.config.ts'), 'export default {};\n');

const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);
ctx.prompts.confirm.mockResolvedValueOnce(true); // accept overwrite

await wizard.init!.run(ctx as any);
Expand All @@ -96,15 +92,15 @@ describe('wizard.init.run', () => {
});

it('installs @playwright/test as a dev dependency', async () => {
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

expect(ctx.nypm.addDependency).toHaveBeenCalledWith(['@playwright/test'], { cwd: tmpDir, dev: true });
});

it('writes playwright.config.ts with the expected boilerplate', async () => {
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

Expand All @@ -119,7 +115,7 @@ describe('wizard.init.run', () => {
join(tmpDir, 'tsconfig.json'),
JSON.stringify({ compilerOptions: { lib: ['ES2022', 'DOM'] } }, null, 2) + '\n',
);
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

Expand All @@ -132,7 +128,7 @@ describe('wizard.init.run', () => {
join(tmpDir, 'tsconfig.json'),
JSON.stringify({ compilerOptions: { lib: ['ES2022', 'ESNext.Disposable'] } }, null, 2) + '\n',
);
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

Expand All @@ -141,7 +137,7 @@ describe('wizard.init.run', () => {
});

it('skips tsconfig editing when no tsconfig.json exists', async () => {
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

Expand Down Expand Up @@ -185,19 +181,11 @@ describe('wizard.init.run', () => {
);
});

it('warns about a missing copy config on an existing www target', async () => {
it('does not warn when a "www" output target is already configured', async () => {
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

expect(ctx.prompts.log.warn).toHaveBeenCalledWith(expect.stringContaining('no "copy" config'));
});

it('does not warn when the www target already has a suitable copy config', async () => {
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);

await wizard.init!.run(ctx as any);

expect(ctx.prompts.log.warn).not.toHaveBeenCalled();
});

Expand All @@ -206,7 +194,7 @@ describe('wizard.init.run', () => {
join(tmpDir, 'package.json'),
JSON.stringify({ name: 'test-lib', scripts: { test: 'my-custom-test' } }, null, 2) + '\n',
);
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

Expand All @@ -216,7 +204,7 @@ describe('wizard.init.run', () => {
});

it('does not add a bare "test" script', async () => {
const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }]);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }]);

await wizard.init!.run(ctx as any);

Expand All @@ -236,7 +224,7 @@ export class MyButton { render() { return <button />; } }
`,
);

const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }], true);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }], true);

await wizard.init!.run(ctx as any);

Expand All @@ -257,7 +245,7 @@ export class MyButton { render() { return <button />; } }
`,
);

const ctx = makeInitCtx(tmpDir, [{ type: 'www', copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }], false);
const ctx = makeInitCtx(tmpDir, [{ type: 'www' }], false);

await wizard.init!.run(ctx as any);

Expand Down
39 changes: 7 additions & 32 deletions src/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ import { join } from 'node:path';

import type { ProjectConfig, StencilWizardPlugin, WizardContext } from '@stencil/cli';

interface OutputTargetWithCopy {
type: string;
copy?: ReadonlyArray<{ src?: string }>;
}

async function fileExists(path: string): Promise<boolean> {
try {
await access(path);
Expand All @@ -18,27 +13,17 @@ async function fileExists(path: string): Promise<boolean> {
}

/**
* Looks for a "www" or "loader-bundle" output target.
* Checks for a "www" or "loader-bundle" output target.
* @param config The resolved Stencil project config.
* @returns The matching "www" and/or "loader-bundle" output targets, if present.
* @returns Whether a "www" and/or "loader-bundle" output target is present.
*/
function detectOutputTargets(config: ProjectConfig) {
const outputs = config.outputTargets as ReadonlyArray<OutputTargetWithCopy>;
const www = outputs.find((o) => o.type === 'www');
const loaderBundle = outputs.find((o) => o.type === 'loader-bundle');
const outputs = config.outputTargets as ReadonlyArray<{ type: string }>;
const www = outputs.some((o) => o.type === 'www');
const loaderBundle = outputs.some((o) => o.type === 'loader-bundle');
return { www, loaderBundle };
}

/**
* Checks a "www" output target's `copy` config for HTML/CSS globs, needed for the `page.goto()` pattern.
* @param www The "www" output target to check.
* @returns `true` if the target's `copy` config includes both an HTML and a CSS glob.
*/
function hasHtmlCssCopy(www: OutputTargetWithCopy): boolean {
const copy = www.copy ?? [];
return copy.some((c) => c.src?.endsWith('.html')) && copy.some((c) => c.src?.endsWith('.css'));
}

const PLAYWRIGHT_CONFIG_TEMPLATE = `import { expect } from '@playwright/test';
import { matchers, createConfig } from '@stencil/playwright';

Expand Down Expand Up @@ -96,17 +81,7 @@ async function ensureOutputTarget(context: WizardContext): Promise<void> {
const { config, prompts } = context;
const { www, loaderBundle } = detectOutputTargets(config);

if (www) {
if (!hasHtmlCssCopy(www)) {
prompts.log.warn(
'The "www" output target has no "copy" config for HTML/CSS files.\n' +
"Add copy: [{ src: '**/*.html' }, { src: '**/*.css' }] to use the page.goto() testing pattern.",
);
}
return;
}

if (loaderBundle) return;
if (www || loaderBundle) return;

const stencilConfigPath = join(config.rootDir, 'stencil.config.ts');
if (!(await fileExists(stencilConfigPath))) {
Expand All @@ -121,7 +96,7 @@ async function ensureOutputTarget(context: WizardContext): Promise<void> {
});
if (!prompts.isCancel(addWww) && addWww) {
const editor = await context.openStencilConfig();
editor.addOutputTarget("{ type: 'www', serviceWorker: null, copy: [{ src: '**/*.html' }, { src: '**/*.css' }] }");
editor.addOutputTarget("{ type: 'www', serviceWorker: null }");
await editor.save();
return;
}
Expand Down
Loading