From 0a889553946a43f8c131ddfecb70345a0dfdc2c6 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 13 Dec 2023 15:50:28 -0600 Subject: [PATCH] fix: Throw error when no entrypoints are found (#283) --- e2e/tests/manifest-content.test.ts | 8 ++++++++ e2e/tests/output-structure.test.ts | 8 +++++++- e2e/tests/typescript-project.test.ts | 6 ++++++ e2e/tests/user-config.test.ts | 5 +++-- .../building/__tests__/find-entrypoints.test.ts | 14 +++++++++++--- src/core/utils/building/find-entrypoints.ts | 9 ++++++++- 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/e2e/tests/manifest-content.test.ts b/e2e/tests/manifest-content.test.ts index 24ec067e..fc6da5b1 100644 --- a/e2e/tests/manifest-content.test.ts +++ b/e2e/tests/manifest-content.test.ts @@ -174,6 +174,7 @@ describe('Manifest Content', () => { describe('icons', () => { it('should auto-discover icons with the correct name', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.addFile('public/icon-16.png'); project.addFile('public/icon/32.png'); project.addFile('public/icon@48w.png'); @@ -196,6 +197,7 @@ describe('Manifest Content', () => { it('should return undefined when no icons are found', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.addFile('public/logo.png'); project.addFile('public/icon.jpeg'); @@ -207,6 +209,7 @@ describe('Manifest Content', () => { it('should allow icons to be overwritten from the wxt.config.ts file', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.addFile('public/icon-16.png'); project.addFile('public/icon-32.png'); project.addFile('public/logo-16.png'); @@ -524,6 +527,7 @@ describe('Manifest Content', () => { it('should respect the transformManifest option', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.addFile( 'wxt.config.ts', `import { defineConfig } from 'wxt'; @@ -587,6 +591,7 @@ describe('Manifest Content', () => { const project = new TestProject({ version: '1.0.0-alpha1', }); + project.addFile('entrypoints/unlisted.html'); await project.build({ browser, manifestVersion }); const manifest = await project.getOutputManifest( @@ -604,6 +609,7 @@ describe('Manifest Content', () => { const project = new TestProject({ version: '1.0.0-alpha1', }); + project.addFile('entrypoints/unlisted.html'); await project.build({ browser, manifestVersion }); const manifest = await project.getOutputManifest( @@ -626,6 +632,7 @@ describe('Manifest Content', () => { const project = new TestProject({ version: '1.0.0.1', }); + project.addFile('entrypoints/unlisted.html'); await project.build({ browser, manifestVersion }); const manifest = await project.getOutputManifest( @@ -640,6 +647,7 @@ describe('Manifest Content', () => { it('should respect the action field in the manifest without a popup', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.setConfigFileConfig({ manifest: { action: { diff --git a/e2e/tests/output-structure.test.ts b/e2e/tests/output-structure.test.ts index 9e89013a..e00bd284 100644 --- a/e2e/tests/output-structure.test.ts +++ b/e2e/tests/output-structure.test.ts @@ -7,13 +7,18 @@ describe('Output Directory Structure', () => { project.addFile('entrypoints/.DS_Store'); project.addFile('entrypoints/.hidden1/index.html'); project.addFile('entrypoints/.hidden2.html'); + project.addFile('entrypoints/unlisted.html'); await project.build(); expect(await project.serializeOutput()).toMatchInlineSnapshot(` ".output/chrome-mv3/manifest.json ---------------------------------------- - {"manifest_version":3,"name":"E2E Extension","description":"Example description","version":"0.0.0"}" + {"manifest_version":3,"name":"E2E Extension","description":"Example description","version":"0.0.0"} + ================================================================================ + .output/chrome-mv3/unlisted.html + ---------------------------------------- + " `); }); @@ -211,6 +216,7 @@ describe('Output Directory Structure', () => { it("should output to a custom directory when overriding 'outDir'", async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.setConfigFileConfig({ outDir: 'dist', }); diff --git a/e2e/tests/typescript-project.test.ts b/e2e/tests/typescript-project.test.ts index a9f04811..468f49e6 100644 --- a/e2e/tests/typescript-project.test.ts +++ b/e2e/tests/typescript-project.test.ts @@ -4,6 +4,7 @@ import { TestProject } from '../utils'; describe('TypeScript Project', () => { it('should generate defined constants correctly', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); await project.build(); @@ -58,6 +59,7 @@ describe('TypeScript Project', () => { it('should augment the types for browser.i18n.getMessage', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.addFile( 'public/_locales/en/messages.json', JSON.stringify({ @@ -216,6 +218,7 @@ describe('TypeScript Project', () => { it('should reference all the required types in a single declaration file', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); await project.build(); @@ -235,6 +238,7 @@ describe('TypeScript Project', () => { it('should generate a TSConfig file for the project', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); await project.build(); @@ -275,6 +279,7 @@ describe('TypeScript Project', () => { it('should generate correct path aliases for a custom srcDir', async () => { const project = new TestProject(); + project.addFile('src/entrypoints/unlisted.html'); project.setConfigFileConfig({ srcDir: 'src', }); @@ -318,6 +323,7 @@ describe('TypeScript Project', () => { it('should add additional path aliases listed in the alias config, preventing defaults from being overridden', async () => { const project = new TestProject(); + project.addFile('src/entrypoints/unlisted.html'); project.setConfigFileConfig({ srcDir: 'src', alias: { diff --git a/e2e/tests/user-config.test.ts b/e2e/tests/user-config.test.ts index 7f84720a..5913339e 100644 --- a/e2e/tests/user-config.test.ts +++ b/e2e/tests/user-config.test.ts @@ -61,6 +61,7 @@ describe('User Config', () => { it('should merge inline and user config based manifests', async () => { const project = new TestProject(); + project.addFile('entrypoints/unlisted.html'); project.addFile( 'wxt.config.ts', `import { defineConfig } from 'wxt'; @@ -79,8 +80,8 @@ describe('User Config', () => { }), }); - const output = await project.serializeOutput(); - expect(output).toMatchInlineSnapshot(` + expect(await project.serializeFile('.output/chrome-mv3/manifest.json')) + .toMatchInlineSnapshot(` ".output/chrome-mv3/manifest.json ---------------------------------------- {"manifest_version":3,"name":"E2E Extension","description":"Example description","version":"0.0.0","example_customization":["3","build","production","chrome"]}" diff --git a/src/core/utils/building/__tests__/find-entrypoints.test.ts b/src/core/utils/building/__tests__/find-entrypoints.test.ts index 438ea9df..158f44e5 100644 --- a/src/core/utils/building/__tests__/find-entrypoints.test.ts +++ b/src/core/utils/building/__tests__/find-entrypoints.test.ts @@ -244,15 +244,15 @@ describe('findEntrypoints', () => { ); it("should include a virtual background script so dev reloading works when there isn't a background entrypoint defined by the user", async () => { - globMock.mockResolvedValueOnce([]); + globMock.mockResolvedValueOnce(['popup.html']); const entrypoints = await findEntrypoints({ ...config, command: 'serve', }); - expect(entrypoints).toHaveLength(1); - expect(entrypoints[0]).toEqual({ + expect(entrypoints).toHaveLength(2); + expect(entrypoints).toContainEqual({ type: 'background', inputPath: 'virtual:user-background', name: 'background', @@ -586,6 +586,14 @@ describe('findEntrypoints', () => { ); }); + it('throw an error if there are no entrypoints', async () => { + globMock.mockResolvedValueOnce([]); + + await expect(() => findEntrypoints(config)).rejects.toThrowError( + `No entrypoints found in ${unnormalizePath(config.entrypointsDir)}`, + ); + }); + describe('include option', () => { it("should filter out the background when include doesn't contain the target browser", async () => { globMock.mockResolvedValueOnce(['background.ts']); diff --git a/src/core/utils/building/find-entrypoints.ts b/src/core/utils/building/find-entrypoints.ts index fc1d4ebe..f85f328e 100644 --- a/src/core/utils/building/find-entrypoints.ts +++ b/src/core/utils/building/find-entrypoints.ts @@ -53,7 +53,8 @@ export async function findEntrypoints( return results; }, []); - // Report duplicate entrypoint names + // Validation + preventNoEntrypoints(config, entrypointInfos); preventDuplicateEntrypointNames(config, entrypointInfos); // Import entrypoints to get their config @@ -169,6 +170,12 @@ function preventDuplicateEntrypointNames( } } +function preventNoEntrypoints(config: InternalConfig, files: EntrypointInfo[]) { + if (files.length === 0) { + throw Error(`No entrypoints found in ${config.entrypointsDir}`); + } +} + function getHtmlBaseOptions(document: Document): BaseEntrypointOptions { const options: BaseEntrypointOptions = {};