From 62638c6d1c6dc75bf446bbecc394b949bdcddbca Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Sat, 29 Jun 2024 16:05:59 +0200 Subject: [PATCH 01/12] test(esbuild-meta): add e2e test --- packages/esbuild-meta-e2e/.eslintrc.json | 18 ++++++ packages/esbuild-meta-e2e/jest.config.ts | 12 ++++ packages/esbuild-meta-e2e/project.json | 18 ++++++ .../esbuild-meta-e2e/src/esbuild-meta.spec.ts | 62 +++++++++++++++++++ packages/esbuild-meta-e2e/tsconfig.json | 10 +++ packages/esbuild-meta-e2e/tsconfig.spec.json | 9 +++ tools/scripts/start-local-registry.ts | 35 +++++++++++ tools/scripts/stop-local-registry.ts | 10 +++ 8 files changed, 174 insertions(+) create mode 100644 packages/esbuild-meta-e2e/.eslintrc.json create mode 100644 packages/esbuild-meta-e2e/jest.config.ts create mode 100644 packages/esbuild-meta-e2e/project.json create mode 100644 packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts create mode 100644 packages/esbuild-meta-e2e/tsconfig.json create mode 100644 packages/esbuild-meta-e2e/tsconfig.spec.json create mode 100644 tools/scripts/start-local-registry.ts create mode 100644 tools/scripts/stop-local-registry.ts diff --git a/packages/esbuild-meta-e2e/.eslintrc.json b/packages/esbuild-meta-e2e/.eslintrc.json new file mode 100644 index 00000000..9d9c0db5 --- /dev/null +++ b/packages/esbuild-meta-e2e/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/packages/esbuild-meta-e2e/jest.config.ts b/packages/esbuild-meta-e2e/jest.config.ts new file mode 100644 index 00000000..ee86590c --- /dev/null +++ b/packages/esbuild-meta-e2e/jest.config.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ +export default { + displayName: 'esbuild-meta-e2e', + preset: '../../jest.preset.js', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/packages/esbuild-meta-e2e', + globalSetup: '..\\..\\tools\\scripts\\start-local-registry.ts', + globalTeardown: '..\\..\\tools\\scripts\\stop-local-registry.ts', +}; diff --git a/packages/esbuild-meta-e2e/project.json b/packages/esbuild-meta-e2e/project.json new file mode 100644 index 00000000..d2cce1f2 --- /dev/null +++ b/packages/esbuild-meta-e2e/project.json @@ -0,0 +1,18 @@ +{ + "name": "esbuild-meta-e2e", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "packages/esbuild-meta-e2e/src", + "implicitDependencies": ["esbuild-meta"], + "targets": { + "e2e": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "packages/esbuild-meta-e2e/jest.config.ts", + "runInBand": true + }, + "dependsOn": ["^build"] + } + } +} diff --git a/packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts b/packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts new file mode 100644 index 00000000..a53aff3c --- /dev/null +++ b/packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts @@ -0,0 +1,62 @@ +import { execSync } from 'child_process'; +import { join, dirname } from 'path'; +import { mkdirSync, rmSync } from 'fs'; + +describe('esbuild-meta', () => { + let projectDirectory: string; + + beforeAll(() => { + projectDirectory = createTestProject(); + + // The plugin has been built and published to a local registry in the jest globalSetup + // Install the plugin built with the latest source code into the test repo + execSync(`npm install @app-speed/esbuild-meta@e2e`, { + cwd: projectDirectory, + stdio: 'inherit', + env: process.env, + }); + }); + + afterAll(() => { + // Cleanup the test project + rmSync(projectDirectory, { + recursive: true, + force: true, + }); + }); + + it('should be installed', () => { + // npm ls will fail if the package is not installed properly + execSync('npm ls @app-speed/esbuild-meta', { + cwd: projectDirectory, + stdio: 'inherit', + }); + }); +}); + +/** + * Creates a test project with create-nx-workspace and installs the plugin + * @returns The directory where the test project was created + */ +function createTestProject() { + const projectName = 'test-project'; + const projectDirectory = join(process.cwd(), 'tmp', projectName); + + // Ensure projectDirectory is empty + rmSync(projectDirectory, { + recursive: true, + force: true, + }); + mkdirSync(dirname(projectDirectory), { + recursive: true, + }); + + execSync(`npx --yes create-nx-workspace@latest ${projectName} --preset apps --nxCloud=skip --no-interactive`, { + cwd: dirname(projectDirectory), + stdio: 'inherit', + env: process.env, + }); + console.log(`Created test project in "${projectDirectory}"`); + + return projectDirectory; +} diff --git a/packages/esbuild-meta-e2e/tsconfig.json b/packages/esbuild-meta-e2e/tsconfig.json new file mode 100644 index 00000000..b9c9d953 --- /dev/null +++ b/packages/esbuild-meta-e2e/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/esbuild-meta-e2e/tsconfig.spec.json b/packages/esbuild-meta-e2e/tsconfig.spec.json new file mode 100644 index 00000000..f6d8ffcc --- /dev/null +++ b/packages/esbuild-meta-e2e/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/tools/scripts/start-local-registry.ts b/tools/scripts/start-local-registry.ts new file mode 100644 index 00000000..2cd2d56b --- /dev/null +++ b/tools/scripts/start-local-registry.ts @@ -0,0 +1,35 @@ +/** + * This script starts a local registry for e2e testing purposes. + * It is meant to be called in jest's globalSetup. + */ +import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry'; +import { execFileSync } from 'child_process'; +import { releasePublish, releaseVersion } from 'nx/release'; + +export default async () => { + // local registry target to run + const localRegistryTarget = 'app-speed:local-registry'; + // storage folder for the local registry + const storage = './tmp/local-registry/storage'; + + global.stopLocalRegistry = await startLocalRegistry({ + localRegistryTarget, + storage, + verbose: false, + }); + + await releaseVersion({ + specifier: '0.0.0-e2e', + stageChanges: false, + gitCommit: false, + gitTag: false, + firstRelease: true, + generatorOptionsOverrides: { + skipLockFileUpdate: true, + }, + }); + await releasePublish({ + tag: 'e2e', + firstRelease: true, + }); +}; diff --git a/tools/scripts/stop-local-registry.ts b/tools/scripts/stop-local-registry.ts new file mode 100644 index 00000000..31d5d347 --- /dev/null +++ b/tools/scripts/stop-local-registry.ts @@ -0,0 +1,10 @@ +/** + * This script stops the local registry for e2e testing purposes. + * It is meant to be called in jest's globalTeardown. + */ + +export default () => { + if (global.stopLocalRegistry) { + global.stopLocalRegistry(); + } +}; From 921a35f3ae03232fca3a4f8ae859ce2fdc242e1b Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Sat, 29 Jun 2024 16:09:24 +0200 Subject: [PATCH 02/12] revert "test(esbuild-meta): add e2e test" This reverts commit b31686c02d5cf651187a726b0d4089c9771c9aae. --- packages/esbuild-meta-e2e/.eslintrc.json | 18 ------ packages/esbuild-meta-e2e/jest.config.ts | 12 ---- packages/esbuild-meta-e2e/project.json | 18 ------ .../esbuild-meta-e2e/src/esbuild-meta.spec.ts | 62 ------------------- packages/esbuild-meta-e2e/tsconfig.json | 10 --- packages/esbuild-meta-e2e/tsconfig.spec.json | 9 --- tools/scripts/start-local-registry.ts | 35 ----------- tools/scripts/stop-local-registry.ts | 10 --- 8 files changed, 174 deletions(-) delete mode 100644 packages/esbuild-meta-e2e/.eslintrc.json delete mode 100644 packages/esbuild-meta-e2e/jest.config.ts delete mode 100644 packages/esbuild-meta-e2e/project.json delete mode 100644 packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts delete mode 100644 packages/esbuild-meta-e2e/tsconfig.json delete mode 100644 packages/esbuild-meta-e2e/tsconfig.spec.json delete mode 100644 tools/scripts/start-local-registry.ts delete mode 100644 tools/scripts/stop-local-registry.ts diff --git a/packages/esbuild-meta-e2e/.eslintrc.json b/packages/esbuild-meta-e2e/.eslintrc.json deleted file mode 100644 index 9d9c0db5..00000000 --- a/packages/esbuild-meta-e2e/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/packages/esbuild-meta-e2e/jest.config.ts b/packages/esbuild-meta-e2e/jest.config.ts deleted file mode 100644 index ee86590c..00000000 --- a/packages/esbuild-meta-e2e/jest.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'esbuild-meta-e2e', - preset: '../../jest.preset.js', - transform: { - '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], - }, - moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../coverage/packages/esbuild-meta-e2e', - globalSetup: '..\\..\\tools\\scripts\\start-local-registry.ts', - globalTeardown: '..\\..\\tools\\scripts\\stop-local-registry.ts', -}; diff --git a/packages/esbuild-meta-e2e/project.json b/packages/esbuild-meta-e2e/project.json deleted file mode 100644 index d2cce1f2..00000000 --- a/packages/esbuild-meta-e2e/project.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "esbuild-meta-e2e", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "packages/esbuild-meta-e2e/src", - "implicitDependencies": ["esbuild-meta"], - "targets": { - "e2e": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "packages/esbuild-meta-e2e/jest.config.ts", - "runInBand": true - }, - "dependsOn": ["^build"] - } - } -} diff --git a/packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts b/packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts deleted file mode 100644 index a53aff3c..00000000 --- a/packages/esbuild-meta-e2e/src/esbuild-meta.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { execSync } from 'child_process'; -import { join, dirname } from 'path'; -import { mkdirSync, rmSync } from 'fs'; - -describe('esbuild-meta', () => { - let projectDirectory: string; - - beforeAll(() => { - projectDirectory = createTestProject(); - - // The plugin has been built and published to a local registry in the jest globalSetup - // Install the plugin built with the latest source code into the test repo - execSync(`npm install @app-speed/esbuild-meta@e2e`, { - cwd: projectDirectory, - stdio: 'inherit', - env: process.env, - }); - }); - - afterAll(() => { - // Cleanup the test project - rmSync(projectDirectory, { - recursive: true, - force: true, - }); - }); - - it('should be installed', () => { - // npm ls will fail if the package is not installed properly - execSync('npm ls @app-speed/esbuild-meta', { - cwd: projectDirectory, - stdio: 'inherit', - }); - }); -}); - -/** - * Creates a test project with create-nx-workspace and installs the plugin - * @returns The directory where the test project was created - */ -function createTestProject() { - const projectName = 'test-project'; - const projectDirectory = join(process.cwd(), 'tmp', projectName); - - // Ensure projectDirectory is empty - rmSync(projectDirectory, { - recursive: true, - force: true, - }); - mkdirSync(dirname(projectDirectory), { - recursive: true, - }); - - execSync(`npx --yes create-nx-workspace@latest ${projectName} --preset apps --nxCloud=skip --no-interactive`, { - cwd: dirname(projectDirectory), - stdio: 'inherit', - env: process.env, - }); - console.log(`Created test project in "${projectDirectory}"`); - - return projectDirectory; -} diff --git a/packages/esbuild-meta-e2e/tsconfig.json b/packages/esbuild-meta-e2e/tsconfig.json deleted file mode 100644 index b9c9d953..00000000 --- a/packages/esbuild-meta-e2e/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/packages/esbuild-meta-e2e/tsconfig.spec.json b/packages/esbuild-meta-e2e/tsconfig.spec.json deleted file mode 100644 index f6d8ffcc..00000000 --- a/packages/esbuild-meta-e2e/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] -} diff --git a/tools/scripts/start-local-registry.ts b/tools/scripts/start-local-registry.ts deleted file mode 100644 index 2cd2d56b..00000000 --- a/tools/scripts/start-local-registry.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This script starts a local registry for e2e testing purposes. - * It is meant to be called in jest's globalSetup. - */ -import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry'; -import { execFileSync } from 'child_process'; -import { releasePublish, releaseVersion } from 'nx/release'; - -export default async () => { - // local registry target to run - const localRegistryTarget = 'app-speed:local-registry'; - // storage folder for the local registry - const storage = './tmp/local-registry/storage'; - - global.stopLocalRegistry = await startLocalRegistry({ - localRegistryTarget, - storage, - verbose: false, - }); - - await releaseVersion({ - specifier: '0.0.0-e2e', - stageChanges: false, - gitCommit: false, - gitTag: false, - firstRelease: true, - generatorOptionsOverrides: { - skipLockFileUpdate: true, - }, - }); - await releasePublish({ - tag: 'e2e', - firstRelease: true, - }); -}; diff --git a/tools/scripts/stop-local-registry.ts b/tools/scripts/stop-local-registry.ts deleted file mode 100644 index 31d5d347..00000000 --- a/tools/scripts/stop-local-registry.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * This script stops the local registry for e2e testing purposes. - * It is meant to be called in jest's globalTeardown. - */ - -export default () => { - if (global.stopLocalRegistry) { - global.stopLocalRegistry(); - } -}; From 9b966af86fe52c43a29bcbad63b592f89791b952 Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Mon, 1 Jul 2024 07:28:08 +0200 Subject: [PATCH 03/12] test(esbuild-meta): add e2e --- global-setup.e2e.ts | 13 +++ .../e2e/__snapshots__/root.test.e2e.ts.snap | 13 +++ packages/esbuild-meta/e2e/root.test.e2e.ts | 26 +++++ packages/esbuild-meta/e2e/utils.ts | 3 + packages/esbuild-meta/project.json | 12 +- packages/esbuild-meta/src/main.ts | 11 +- packages/esbuild-meta/tsconfig.json | 1 + packages/esbuild-meta/tsconfig.spec.json | 2 + packages/esbuild-meta/vitest.config.e2e.ts | 19 ++++ project.json | 2 +- tools/scripts/start-local-registry.ts | 103 ++++++++++++++++++ tools/scripts/stop-local-registry.ts | 10 ++ 12 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 global-setup.e2e.ts create mode 100644 packages/esbuild-meta/e2e/__snapshots__/root.test.e2e.ts.snap create mode 100644 packages/esbuild-meta/e2e/root.test.e2e.ts create mode 100644 packages/esbuild-meta/e2e/utils.ts create mode 100644 packages/esbuild-meta/vitest.config.e2e.ts create mode 100644 tools/scripts/start-local-registry.ts create mode 100644 tools/scripts/stop-local-registry.ts diff --git a/global-setup.e2e.ts b/global-setup.e2e.ts new file mode 100644 index 00000000..8a7e7c0c --- /dev/null +++ b/global-setup.e2e.ts @@ -0,0 +1,13 @@ +import { execSync } from 'child_process'; +import startLocalRegistry from './tools/scripts/start-local-registry'; +import stopLocalRegistry from './tools/scripts/stop-local-registry'; + +export async function setup() { + await startLocalRegistry(); + execSync('npm install -D @app-speed/esbuild-meta@e2e --force'); +} + +export async function teardown() { + stopLocalRegistry(); + execSync('npm uninstall @app-speed/esbuild-meta'); +} diff --git a/packages/esbuild-meta/e2e/__snapshots__/root.test.e2e.ts.snap b/packages/esbuild-meta/e2e/__snapshots__/root.test.e2e.ts.snap new file mode 100644 index 00000000..27fa9512 --- /dev/null +++ b/packages/esbuild-meta/e2e/__snapshots__/root.test.e2e.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`--help > should show help 1`] = ` +"esbuild-meta [command] + +Commands: + esbuild-meta filter Filters the meta file to only include chunks required by specified entry points [aliases: f] + +Options: + -v, --version Show version number [boolean] + -h, --help Show help [boolean] +" +`; diff --git a/packages/esbuild-meta/e2e/root.test.e2e.ts b/packages/esbuild-meta/e2e/root.test.e2e.ts new file mode 100644 index 00000000..8438e554 --- /dev/null +++ b/packages/esbuild-meta/e2e/root.test.e2e.ts @@ -0,0 +1,26 @@ +import { describe, it, expect, beforeAll } from 'vitest'; +import { version } from '../package.json'; + +import { commandOutput } from './utils.js'; + +describe('--help', () => { + let helpOutput: string; + + beforeAll(() => { + helpOutput = commandOutput('esbuild-meta --help'); + }); + + it('should show help', () => { + expect(helpOutput).toMatchSnapshot(); + }); + + it('should alias to -h', () => { + expect(commandOutput('esbuild-meta -h')).toBe(helpOutput); + }); +}); + +describe('--version', () => { + it('should show version', () => { + expect(commandOutput('esbuild-meta --version')).toContain(version); + }); +}); diff --git a/packages/esbuild-meta/e2e/utils.ts b/packages/esbuild-meta/e2e/utils.ts new file mode 100644 index 00000000..d61a3e22 --- /dev/null +++ b/packages/esbuild-meta/e2e/utils.ts @@ -0,0 +1,3 @@ +import { execSync } from 'child_process'; + +export const commandOutput = (command: string) => execSync(command).toString(); diff --git a/packages/esbuild-meta/project.json b/packages/esbuild-meta/project.json index 95b9a77f..d2ee919a 100644 --- a/packages/esbuild-meta/project.json +++ b/packages/esbuild-meta/project.json @@ -2,8 +2,7 @@ "name": "esbuild-meta", "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/esbuild-meta/src", - "projectType": "library", - "tags": [], + "projectType": "app", "targets": { "build": { "executor": "@nx/esbuild:esbuild", @@ -17,8 +16,7 @@ "format": ["esm"], "minify": true, "platform": "node", - "bundle": true, - "thirdParty": true + "bundle": true } }, "test": { @@ -27,6 +25,12 @@ "options": { "reportsDirectory": "../../coverage/packages/esbuild-meta" } + }, + "e2e": { + "executor": "@nx/vite:test", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}-e2e"], + "options": { "config": "packages/esbuild-meta/vitest.config.e2e.ts" }, + "dependsOn": ["build"] } } } diff --git a/packages/esbuild-meta/src/main.ts b/packages/esbuild-meta/src/main.ts index 415c99cc..d9dd4d73 100644 --- a/packages/esbuild-meta/src/main.ts +++ b/packages/esbuild-meta/src/main.ts @@ -4,7 +4,16 @@ import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import { argv } from 'node:process'; import { filterMetaCommand } from './lib/filter-meta.js'; +import { version } from '../package.json'; -yargs(hideBin(argv)).command('$0', 'Default Command is filter', filterMetaCommand).parse(); +yargs(hideBin(argv)) + .scriptName('esbuild-meta') + .version(version).alias('v', 'version') + .showHelpOnFail(true) + .command(filterMetaCommand) + .help() + .alias('h', 'help') + .wrap(null) + .parse(); console.log('Esbuild Meta completed successfully'); diff --git a/packages/esbuild-meta/tsconfig.json b/packages/esbuild-meta/tsconfig.json index 897f0b96..36d2a010 100644 --- a/packages/esbuild-meta/tsconfig.json +++ b/packages/esbuild-meta/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", + "resolveJsonModule": true, "esModuleInterop": true, "target": "ES2022", "forceConsistentCasingInFileNames": true, diff --git a/packages/esbuild-meta/tsconfig.spec.json b/packages/esbuild-meta/tsconfig.spec.json index 0edf3f2f..c872c81b 100644 --- a/packages/esbuild-meta/tsconfig.spec.json +++ b/packages/esbuild-meta/tsconfig.spec.json @@ -7,6 +7,8 @@ "include": [ "vite.config.ts", "vitest.config.ts", + "vitest.config.e2e.ts", + "e2e/**/*.test.e2e.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.test.tsx", diff --git a/packages/esbuild-meta/vitest.config.e2e.ts b/packages/esbuild-meta/vitest.config.e2e.ts new file mode 100644 index 00000000..78d57d6c --- /dev/null +++ b/packages/esbuild-meta/vitest.config.e2e.ts @@ -0,0 +1,19 @@ +/// +import { defineConfig } from 'vite'; +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/esbuild-meta/e2e', + + plugins: [nxViteTsPaths()], + + test: { + watch: false, + reporters: ['default'], + globals: true, + cache: { dir: '../../node_modules/.vitest' }, + environment: 'node', + include: ['e2e/**/*.test.e2e.ts'], + globalSetup: '../../global-setup.e2e.ts' + }, +}); diff --git a/project.json b/project.json index 084e3a89..7620b5a4 100644 --- a/project.json +++ b/project.json @@ -1,5 +1,5 @@ { - "name": "app-speed", + "name": "@app-speed/source", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { "local-registry": { diff --git a/tools/scripts/start-local-registry.ts b/tools/scripts/start-local-registry.ts new file mode 100644 index 00000000..0601c650 --- /dev/null +++ b/tools/scripts/start-local-registry.ts @@ -0,0 +1,103 @@ +/** + * This script starts a local registry for e2e testing purposes. + * It is meant to be called in jest's globalSetup. + */ +import { execSync, spawn } from 'node:child_process'; +import { releasePublish, releaseVersion } from 'nx/release'; + +export default async () => { + const localRegistryTarget = '@app-speed/source:local-registry'; + const storage = './tmp/local-registry/storage'; + + global.stopLocalRegistry = await startLocalRegistry({ + localRegistryTarget, + storage, + verbose: true, + }); + + await releaseVersion({ + specifier: '0.0.0-e2e', + stageChanges: false, + gitCommit: false, + gitTag: false, + generatorOptionsOverrides: { + skipLockFileUpdate: true, + }, + }); + + await releasePublish({ + projects: ['esbuild-meta'], + tag: 'e2e', + firstRelease: true, + }); +}; + +// soft copy from https://github.com/nrwl/nx/blob/16.9.x/packages/js/src/plugins/jest/start-local-registry.ts +// original function does not work, because it uses require.resolve('nx') and fork, +// and it does not work with vite +function startLocalRegistry({ localRegistryTarget, storage, verbose }: { + localRegistryTarget: string; + storage?: string; + verbose?: boolean; +}) { + if (!localRegistryTarget) { + throw new Error(`localRegistryTarget is required`); + } + return new Promise<() => void>((resolve, reject) => { + const childProcess = spawn( + 'npx', + [ + 'nx', + ...`run ${localRegistryTarget} --location none --clear true`.split(' '), + ...(storage ? [`--storage`, storage] : []), + ], + { stdio: 'pipe', shell: true }, + ); + + const listener = data => { + if (verbose) { + process.stdout.write(data); + } + if (data.toString().includes('http://localhost:')) { + const port = parseInt(data.toString().match(/localhost:(?\d+)/)?.groups?.port); + console.info('Local registry started on port ' + port); + + const registry = `http://localhost:${port}`; + process.env.npm_config_registry = registry; + execSync( + `npm config set //localhost:${port}/:_authToken "secretVerdaccioToken"`, + ); + + // yarnv1 + process.env.YARN_REGISTRY = registry; + // yarnv2 + process.env.YARN_NPM_REGISTRY_SERVER = registry; + process.env.YARN_UNSAFE_HTTP_WHITELIST = 'localhost'; + + console.info('Set npm and yarn config registry to ' + registry); + + resolve(() => { + childProcess.kill(); + execSync(`npm config delete //localhost:${port}/:_authToken`); + }); + childProcess?.stdout?.off('data', listener); + } + }; + childProcess?.stdout?.on('data', listener); + childProcess?.stderr?.on('data', data => { + process.stderr.write(data); + }); + childProcess.on('error', err => { + console.error('local registry error', err); + reject(err); + }); + childProcess.on('exit', code => { + console.info('local registry exit', code); + if (code !== 0) { + reject(code); + } else { + resolve(() => {}); + } + }); + }); +} diff --git a/tools/scripts/stop-local-registry.ts b/tools/scripts/stop-local-registry.ts new file mode 100644 index 00000000..31d5d347 --- /dev/null +++ b/tools/scripts/stop-local-registry.ts @@ -0,0 +1,10 @@ +/** + * This script stops the local registry for e2e testing purposes. + * It is meant to be called in jest's globalTeardown. + */ + +export default () => { + if (global.stopLocalRegistry) { + global.stopLocalRegistry(); + } +}; From 14ec44faf7467529ba955914bc4bb2db5cdd0dd5 Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Mon, 1 Jul 2024 07:37:16 +0200 Subject: [PATCH 04/12] refactor(workspace): add tmp to git ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index d0b8d1df..1a1d4566 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,6 @@ dist # Nx Cache .nx + +# Temporaty files +tmp From ea5133889220ef90b2eba255794cd2e7df657b27 Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Wed, 3 Jul 2024 11:22:43 +0200 Subject: [PATCH 05/12] fix(esbuild-meta): handle missing stats path --- .../e2e/__snapshots__/filter.test.e2e.ts.snap | 16 +++++++++++ packages/esbuild-meta/e2e/filter.test.e2e.ts | 28 +++++++++++++++++++ packages/esbuild-meta/e2e/root.test.e2e.ts | 26 ++++++++++------- packages/esbuild-meta/e2e/utils.ts | 20 +++++++++++-- packages/esbuild-meta/src/lib/filter-meta.ts | 14 ++++++---- packages/esbuild-meta/src/lib/utils.ts | 14 ++++++++-- packages/esbuild-meta/vitest.config.e2e.ts | 3 ++ 7 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 packages/esbuild-meta/e2e/__snapshots__/filter.test.e2e.ts.snap create mode 100644 packages/esbuild-meta/e2e/filter.test.e2e.ts diff --git a/packages/esbuild-meta/e2e/__snapshots__/filter.test.e2e.ts.snap b/packages/esbuild-meta/e2e/__snapshots__/filter.test.e2e.ts.snap new file mode 100644 index 00000000..62535c40 --- /dev/null +++ b/packages/esbuild-meta/e2e/__snapshots__/filter.test.e2e.ts.snap @@ -0,0 +1,16 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`filter command > should have a help option 1`] = ` +"esbuild-meta filter + +Filters the meta file to only include chunks required by specified entry points + +Options: + -s, --statsPath The path to the stats.json file [string] [required] + -o, --outPath The path where the new file should be saved [string] [default: "initial-stats.json"] + --excludeDynamicImports, --eDI Should the dynamic imports be filtered out of the output chunk imports [boolean] [default: false] + -e, --entryPoints Entry points that should be considered for the bundle [array] [default: ["main-","polyfills-"]] + -v, --version Show version number [boolean] + -h, --help Show help [boolean] +" +`; diff --git a/packages/esbuild-meta/e2e/filter.test.e2e.ts b/packages/esbuild-meta/e2e/filter.test.e2e.ts new file mode 100644 index 00000000..1c705b05 --- /dev/null +++ b/packages/esbuild-meta/e2e/filter.test.e2e.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest'; +import { cliProcess } from './utils.js'; +import { DEMAND_STATS_PATH } from '../src/lib/filter-meta.js'; +import { INVALID_FILE_PATH_ERROR_MSG } from '../src/lib/utils.js'; + +describe('filter command', () => { + it('should have a help option', async () => { + const { stdout, stderr, code } = await cliProcess('esbuild-meta filter --help'); + expect(stdout).toMatchSnapshot(); + expect(stderr).toBeFalsy(); + expect(code).toBe(0); + }); + + it('should demand stats path option', async () => { + const { stdout, stderr, code } = await cliProcess('esbuild-meta filter'); + expect(stderr).toContain(DEMAND_STATS_PATH); + expect(stdout).toBeFalsy(); + expect(code).toBe(1); + }); + + it('should throw if stats path does not point to a file', async () => { + const INVALID_STATS_FILE = 'invalid-path.json'; + const { stdout, stderr, code } = await cliProcess(`esbuild-meta filter --statsPath ${INVALID_STATS_FILE}`); + expect(stderr).toContain(INVALID_FILE_PATH_ERROR_MSG('invalid-path.json')); + expect(stdout).toBeFalsy(); + expect(code).toBe(1); + }); +}); diff --git a/packages/esbuild-meta/e2e/root.test.e2e.ts b/packages/esbuild-meta/e2e/root.test.e2e.ts index 8438e554..e89bdb36 100644 --- a/packages/esbuild-meta/e2e/root.test.e2e.ts +++ b/packages/esbuild-meta/e2e/root.test.e2e.ts @@ -1,26 +1,32 @@ import { describe, it, expect, beforeAll } from 'vitest'; import { version } from '../package.json'; -import { commandOutput } from './utils.js'; +import { cliProcess, CliProcessOutput } from './utils.js'; describe('--help', () => { - let helpOutput: string; + let output: CliProcessOutput; - beforeAll(() => { - helpOutput = commandOutput('esbuild-meta --help'); + beforeAll(async () => { + output = await cliProcess('esbuild-meta --help'); }); - it('should show help', () => { - expect(helpOutput).toMatchSnapshot(); + it('should show help', async () => { + const { stdout, stderr, code } = output; + expect(stdout).toMatchSnapshot(); + expect(stderr).toBeFalsy(); + expect(code).toBe(0); }); - it('should alias to -h', () => { - expect(commandOutput('esbuild-meta -h')).toBe(helpOutput); + it('should alias to -h', async () => { + expect(await cliProcess('esbuild-meta --help')).toEqual(output); }); }); describe('--version', () => { - it('should show version', () => { - expect(commandOutput('esbuild-meta --version')).toContain(version); + it('should show version', async () => { + const {stdout, stderr, code} = await cliProcess('esbuild-meta --version'); + expect(stdout).toContain(version); + expect(stderr).toBeFalsy(); + expect(code).toBe(0); }); }); diff --git a/packages/esbuild-meta/e2e/utils.ts b/packages/esbuild-meta/e2e/utils.ts index d61a3e22..c5f356c0 100644 --- a/packages/esbuild-meta/e2e/utils.ts +++ b/packages/esbuild-meta/e2e/utils.ts @@ -1,3 +1,19 @@ -import { execSync } from 'child_process'; +import { spawn } from 'node:child_process'; -export const commandOutput = (command: string) => execSync(command).toString(); +export type CliProcessOutput = { + stdout: string; + stderr: string; + code: number | null; +} + +export const cliProcess = (command: string) => { + return new Promise((resolve) => { + const process = spawn(command, [], { stdio: 'pipe', shell: true }); + + let stdout = ''; + let stderr = ''; + process.stdout.on('data', (data) => stdout += String(data)); + process.stderr.on('data', (data) => stderr += String(data)); + process.on('close', code => resolve({ stdout, stderr, code })); + }) +} diff --git a/packages/esbuild-meta/src/lib/filter-meta.ts b/packages/esbuild-meta/src/lib/filter-meta.ts index 0fe0eadb..6f914c3b 100644 --- a/packages/esbuild-meta/src/lib/filter-meta.ts +++ b/packages/esbuild-meta/src/lib/filter-meta.ts @@ -8,11 +8,13 @@ import { makeJson, } from './utils.js'; -const distPath = { - alias: 'd', +export const DEMAND_STATS_PATH = 'The path to a stats.json file is required'; + +const statsPath = { + alias: 's', type: 'string', - default: 'dist', - description: 'The path to the stats.json file' + description: 'The path to the stats.json file', + demandOption: DEMAND_STATS_PATH, } as const satisfies Options; const outPath = { @@ -37,7 +39,7 @@ const entryPoints = { description: 'Entry points that should be considered for the bundle', } as const satisfies Options; -const filterMetaOptions = { distPath, outPath, excludeDynamicImports, entryPoints }; +const filterMetaOptions = { statsPath, outPath, excludeDynamicImports, entryPoints }; type FilterMetaOptions = InferredOptionTypes; type FilterMetaCommandModule = CommandModule; @@ -47,7 +49,7 @@ const filterMetaBuilder: CommandBuilder = (argv: Arg } const filterMetaHandler: FilterMetaCommandModule['handler'] = (argv: FilterMetaOptions) => { - const meta = getJson([argv.distPath]); + const meta = getJson(argv.statsPath); const entryPoints = extractEntryPoints(meta, argv.entryPoints); filterMetaFromEntryPoints(meta, entryPoints); if (argv.excludeDynamicImports) { diff --git a/packages/esbuild-meta/src/lib/utils.ts b/packages/esbuild-meta/src/lib/utils.ts index fb502a3b..f1fa1b4e 100644 --- a/packages/esbuild-meta/src/lib/utils.ts +++ b/packages/esbuild-meta/src/lib/utils.ts @@ -1,9 +1,17 @@ import { readFileSync, writeFileSync } from 'node:fs'; -import { join } from 'node:path'; +import { join, normalize } from 'node:path'; import { Metafile } from 'esbuild'; -export function getJson(path: string[]) { - return JSON.parse(readFileSync(join(...path), {encoding: 'utf-8'})) as T; +export const INVALID_FILE_PATH_ERROR_MSG = (path: string) => `No file found at ${path}`; + +export function getJson(path: string) { + const normalizedPath = normalize(path); + try { + return JSON.parse(readFileSync(normalizedPath, {encoding: 'utf-8'})) as T; + } + catch (e) { + throw new Error(INVALID_FILE_PATH_ERROR_MSG(normalizedPath)); + } } export function makeJson(path: string, file: any) { diff --git a/packages/esbuild-meta/vitest.config.e2e.ts b/packages/esbuild-meta/vitest.config.e2e.ts index 78d57d6c..6cae177e 100644 --- a/packages/esbuild-meta/vitest.config.e2e.ts +++ b/packages/esbuild-meta/vitest.config.e2e.ts @@ -9,6 +9,9 @@ export default defineConfig({ test: { watch: false, + pool: 'threads', + poolOptions: { threads: { singleThread: true } }, + testTimeout: 140_000, reporters: ['default'], globals: true, cache: { dir: '../../node_modules/.vitest' }, From aa50a44afcedd25cd72f19eda1022ad6b6d508c7 Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Wed, 3 Jul 2024 11:27:35 +0200 Subject: [PATCH 06/12] fix(esbuild-meta): add e2e to pipeline --- .github/workflows/ci.yml | 61 +++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 533b074f..51f84bb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,6 +132,33 @@ jobs: - name: Build Affected run: npx nx affected -t build build-storybook --parallel=3 + e2e: + name: E2E Affected + needs: [build] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: nrwl/nx-set-shas@v3 + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: Cache NPM Dependencies + uses: actions/cache@v4 + with: + path: | + node_modules + ~/.cache + dist + key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} + + - name: E2E Affected + run: npx nx affected --target=e2e --parallel=3 + # publish-storybook: # name: Publish Storybook # needs: [build, lint] @@ -161,7 +188,7 @@ jobs: deploy-front-end: name: Deploy Front-End - needs: [build, lint] + needs: [e2e, build, lint] runs-on: ubuntu-latest steps: @@ -203,7 +230,7 @@ jobs: deploy-server: name: Deploy Server - needs: [build, lint] + needs: [e2e, build, lint] runs-on: ubuntu-latest steps: @@ -239,33 +266,3 @@ jobs: - name: Deploy Prod Server if: ${{ env.is-main-branch == 'true' }} run: npx nx affected --target=deploy --exclude='*,!tag:backend' --configuration=production - -# release: -# name: Release Affected -# needs: [build, lint] -# runs-on: ubuntu-latest -# -# steps: -# - uses: actions/checkout@v4 -# with: -# # We need to fetch all branches and commits so that Nx affected has a base to compare against. -# fetch-depth: 0 -# # Derive appropriate SHAs for base and head for `nx affected` commands -# - uses: nrwl/nx-set-shas@v3 -# - uses: actions/setup-node@v4 -# with: -# node-version: 20 -# cache: 'npm' -# -# - name: Cache NPM Dependencies -# uses: actions/cache@v4 -# with: -# path: | -# node_modules -# ~/.cache -# dist -# key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} -# -# - name: Release Affected -## if: ${{ env.is-main-branch == 'true' }} -# run: npx nx affected -t nx-release-publish --parallel=3 From 2df834ab18df1240bfd462d5f12249b95b6a8030 Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Thu, 4 Jul 2024 06:43:56 +0200 Subject: [PATCH 07/12] fix(esbuild-meta): fix dependency check --- packages/esbuild-meta/.eslintrc.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/esbuild-meta/.eslintrc.json b/packages/esbuild-meta/.eslintrc.json index 0dc93dd7..76597944 100644 --- a/packages/esbuild-meta/.eslintrc.json +++ b/packages/esbuild-meta/.eslintrc.json @@ -21,7 +21,10 @@ "@nx/dependency-checks": [ "error", { - "ignoredFiles": ["{projectRoot}/vite.config.{js,ts,mjs,mts}"] + "ignoredFiles": [ + "{projectRoot}/e2e/*.{js,ts,mjs,mts}", + "{projectRoot}/vite.config.{js,ts,mjs,mts}" + ] } ] } From b1a0a7d288a71bc30f518484c2d32eb0d0717dc6 Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Thu, 4 Jul 2024 07:21:59 +0200 Subject: [PATCH 08/12] fix(esbuild-meta): fix dependency check --- packages/esbuild-meta/project.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/esbuild-meta/project.json b/packages/esbuild-meta/project.json index d2ee919a..49a743d8 100644 --- a/packages/esbuild-meta/project.json +++ b/packages/esbuild-meta/project.json @@ -1,6 +1,7 @@ { "name": "esbuild-meta", "$schema": "../../node_modules/nx/schemas/project-schema.json", + "root": "packages/esbuild-meta", "sourceRoot": "packages/esbuild-meta/src", "projectType": "app", "targets": { @@ -19,6 +20,10 @@ "bundle": true } }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + }, "test": { "executor": "@nx/vite:test", "outputs": ["{options.reportsDirectory}"], From 07691de5a8d67a790b518af54284b108453c624d Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Thu, 4 Jul 2024 07:23:16 +0200 Subject: [PATCH 09/12] test(workspace): re introduce test to pipeline --- .github/workflows/ci.yml | 57 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51f84bb4..504fb485 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,35 +73,34 @@ jobs: - name: Lint Affected run: npx nx affected --target=lint --parallel=3 -# Commented out because its hanging -# test: -# name: Test Affected -# needs: setup -# runs-on: ubuntu-latest -# -# steps: -# - uses: actions/checkout@v4 -# with: -# # We need to fetch all branches and commits so that Nx affected has a base to compare against. -# fetch-depth: 0 -# # Derive appropriate SHAs for base and head for `nx affected` commands -# - uses: nrwl/nx-set-shas@v3 -# - uses: actions/setup-node@v4 -# with: -# node-version: ${{ env.NODE_VERSION }} -# cache: 'npm' -# -# - name: Cache NPM Dependencies -# uses: actions/cache@v4 -# with: -# path: | -# node_modules -# ~/.cache -# dist -# key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} -# -# - name: Test Affected -# run: npx nx affected --target=test --parallel=3 + test: + name: Test Affected + needs: setup + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + # We need to fetch all branches and commits so that Nx affected has a base to compare against. + fetch-depth: 0 + # Derive appropriate SHAs for base and head for `nx affected` commands + - uses: nrwl/nx-set-shas@v3 + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: Cache NPM Dependencies + uses: actions/cache@v4 + with: + path: | + node_modules + ~/.cache + dist + key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} + + - name: Test Affected + run: npx nx affected --target=test --parallel=3 build: name: Build Affected From d7178455e786f8bb5ce6a13db149ee71bebcc79a Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Thu, 4 Jul 2024 07:49:33 +0200 Subject: [PATCH 10/12] fix(esbuild-meta): fix dependency check --- packages/esbuild-meta/.eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/esbuild-meta/.eslintrc.json b/packages/esbuild-meta/.eslintrc.json index 76597944..22d31df3 100644 --- a/packages/esbuild-meta/.eslintrc.json +++ b/packages/esbuild-meta/.eslintrc.json @@ -22,7 +22,8 @@ "error", { "ignoredFiles": [ - "{projectRoot}/e2e/*.{js,ts,mjs,mts}", + "{projectRoot}/e2e/**/*", + "{projectRoot}/vitest.config.e2e.{js,ts,mjs,mts}", "{projectRoot}/vite.config.{js,ts,mjs,mts}" ] } From 7718211945ccf3e0fac8f3bd57bf34de89ad75bf Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Thu, 4 Jul 2024 07:50:15 +0200 Subject: [PATCH 11/12] fix(esbuild-meta): fix no unit test pass --- packages/esbuild-meta/vite.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/esbuild-meta/vite.config.ts b/packages/esbuild-meta/vite.config.ts index d6c5228c..007c41e4 100644 --- a/packages/esbuild-meta/vite.config.ts +++ b/packages/esbuild-meta/vite.config.ts @@ -14,6 +14,7 @@ export default defineConfig({ environment: 'node', include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], reporters: ['default'], + passWithNoTests: true, coverage: { reportsDirectory: '../../coverage/packages/esbuild-meta', provider: 'v8' }, }, }); From 08d5e1ff54f52717653ae2e313bfa2fabb32b228 Mon Sep 17 00:00:00 2001 From: ChristopherPHolder Date: Thu, 4 Jul 2024 07:53:27 +0200 Subject: [PATCH 12/12] fix(workspace): pipeline depends on test --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 504fb485..2411c04f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -187,7 +187,7 @@ jobs: deploy-front-end: name: Deploy Front-End - needs: [e2e, build, lint] + needs: [test, build, lint, e2e] runs-on: ubuntu-latest steps: @@ -229,7 +229,7 @@ jobs: deploy-server: name: Deploy Server - needs: [e2e, build, lint] + needs: [test, build, lint, e2e] runs-on: ubuntu-latest steps: