From 603091e75c4fcebfa562640bd41ddaaba50d7d91 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Wed, 11 Dec 2024 22:16:22 -0500 Subject: [PATCH] chore(misc): add vue and node ts solution e2e tests --- e2e/node/src/node-ts-solution.test.ts | 157 ++++++++++++++++++++++++++ e2e/utils/create-project-utils.ts | 4 +- e2e/vue/src/vue-ts-solution.test.ts | 75 ++++++++++++ 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 e2e/node/src/node-ts-solution.test.ts create mode 100644 e2e/vue/src/vue-ts-solution.test.ts diff --git a/e2e/node/src/node-ts-solution.test.ts b/e2e/node/src/node-ts-solution.test.ts new file mode 100644 index 0000000000000..bf3666fb29506 --- /dev/null +++ b/e2e/node/src/node-ts-solution.test.ts @@ -0,0 +1,157 @@ +import { + checkFilesExist, + cleanupProject, + getSelectedPackageManager, + killPorts, + newProject, + promisifiedTreeKill, + runCLI, + runCommandUntil, + tmpProjPath, + uniq, + updateFile, + updateJson, +} from '@nx/e2e/utils'; +import { execSync } from 'child_process'; +import * as http from 'http'; + +let originalEnvPort; + +describe('Node Applications', () => { + const pm = getSelectedPackageManager(); + + beforeAll(() => { + originalEnvPort = process.env.PORT; + newProject({ + packages: ['@nx/node', '@nx/express', '@nx/nest', '@nx/webpack'], + preset: 'ts', + }); + if (pm === 'pnpm') { + updateFile( + 'pnpm-workspace.yaml', + ` +packages: + - 'apps/**' + - 'packages/**' +` + ); + } else { + updateJson('package.json', (json) => { + json.workspaces = ['apps/**', 'packages/**']; + return json; + }); + } + }); + + afterAll(() => { + process.env.PORT = originalEnvPort; + cleanupProject(); + }); + + it('should be able to generate an empty application', async () => { + const nodeapp = uniq('nodeapp'); + const port = getRandomPort(); + process.env.PORT = `${port}`; + runCLI( + `generate @nx/node:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest` + ); + + expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow(); + expect(() => runCLI(`test ${nodeapp}`)).not.toThrow(); + + updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`); + runCLI(`build ${nodeapp}`); + + checkFilesExist(`dist/apps/${nodeapp}/main.js`); + const result = execSync(`node dist/apps/${nodeapp}/main.js`, { + cwd: tmpProjPath(), + }).toString(); + expect(result).toContain('Hello World!'); + await killPorts(port); + }, 300_000); + + it('should be able to generate an express application', async () => { + const nodeapp = uniq('nodeapp'); + const nodelib = uniq('nodelib'); + const port = getRandomPort(); + process.env.PORT = `${port}`; + runCLI( + `generate @nx/express:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest` + ); + runCLI( + `generate @nx/node:lib packages/${nodelib} --linter=eslint --unitTestRunner=jest` + ); + + // No tests are generated by default, add a stub one. + updateFile( + `apps/${nodeapp}/src/app/test.spec.ts`, + ` + describe('test', () => { + it('should work', () => { + expect(true).toEqual(true); + }) + }) + ` + ); + + updateFile(`apps/${nodeapp}/src/assets/file.txt`, `Test`); + updateFile(`apps/${nodeapp}/src/main.ts`, (content) => { + return `import { ${nodelib} } from '@proj/${nodelib}';\n${content}\nconsole.log(${nodelib}());`; + }); + runCLI(`sync`); + + expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow(); + expect(() => runCLI(`test ${nodeapp}`)).not.toThrow(); + expect(() => runCLI(`build ${nodeapp}`)).not.toThrow(); + expect(() => runCLI(`lint ${nodelib}`)).not.toThrow(); + expect(() => runCLI(`test ${nodelib}`)).not.toThrow(); + expect(() => runCLI(`build ${nodelib}`)).not.toThrow(); + + const p = await runCommandUntil( + `serve ${nodeapp}`, + (output) => output.includes(`Listening at http://localhost:${port}`), + + { + env: { + NX_DAEMON: 'true', + }, + } + ); + + let result = await getData(port); + expect(result.message).toMatch(`Welcome to ${nodeapp}!`); + + result = await getData(port, '/assets/file.txt'); + expect(result).toMatch(`Test`); + + try { + await promisifiedTreeKill(p.pid, 'SIGKILL'); + expect(await killPorts(port)).toBeTruthy(); + } catch (err) { + expect(err).toBeFalsy(); + } + }, 300_000); +}); + +function getRandomPort() { + return Math.floor(1000 + Math.random() * 9000); +} + +function getData(port, path = '/api'): Promise { + return new Promise((resolve) => { + http.get(`http://localhost:${port}${path}`, (res) => { + expect(res.statusCode).toEqual(200); + let data = ''; + res.on('data', (chunk) => { + data += chunk; + }); + res.once('end', () => { + try { + resolve(JSON.parse(data)); + } catch (e) { + resolve(data); + } + }); + }); + }); +} diff --git a/e2e/utils/create-project-utils.ts b/e2e/utils/create-project-utils.ts index 7199e95e8623c..d0401f06d0f01 100644 --- a/e2e/utils/create-project-utils.ts +++ b/e2e/utils/create-project-utils.ts @@ -76,10 +76,12 @@ export function newProject({ name = uniq('proj'), packageManager = getSelectedPackageManager(), packages, + preset = 'apps', }: { name?: string; packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun'; readonly packages?: Array; + preset?: string; } = {}): string { const newProjectStart = performance.mark('new-project:start'); try { @@ -93,7 +95,7 @@ export function newProject({ 'create-nx-workspace:start' ); runCreateWorkspace(projScope, { - preset: 'apps', + preset, packageManager, }); const createNxWorkspaceEnd = performance.mark('create-nx-workspace:end'); diff --git a/e2e/vue/src/vue-ts-solution.test.ts b/e2e/vue/src/vue-ts-solution.test.ts new file mode 100644 index 0000000000000..50a932ad73e54 --- /dev/null +++ b/e2e/vue/src/vue-ts-solution.test.ts @@ -0,0 +1,75 @@ +import { + cleanupProject, + getSelectedPackageManager, + newProject, + runCLI, + uniq, + updateFile, + updateJson, +} from '@nx/e2e/utils'; + +describe('Vue Plugin', () => { + let proj: string; + + const pm = getSelectedPackageManager(); + + beforeAll(() => { + proj = newProject({ + packages: ['@nx/vue'], + preset: 'ts', + }); + if (pm === 'pnpm') { + updateFile( + 'pnpm-workspace.yaml', + ` +packages: + - 'apps/**' + - 'packages/**' +` + ); + } else { + updateJson('package.json', (json) => { + json.workspaces = ['apps/**', 'packages/**']; + return json; + }); + } + }); + + afterAll(() => cleanupProject()); + + it('should serve application in dev mode', async () => { + const app = uniq('app'); + const lib = uniq('lib'); + runCLI( + `generate @nx/vue:app apps/${app} --unitTestRunner=vitest --e2eTestRunner=playwright --linter=eslint` + ); + runCLI( + `generate @nx/vue:lib packages/${lib} --bundler=vite --unitTestRunner=vitest --linter=eslint` + ); + + // app and lib generators don't have specs by default, add some stubs + updateFile( + `apps/${app}/src/foo.spec.ts`, + ` + test('it should run', () => { + expect(true).toBeTruthy(); + }); + ` + ); + updateFile( + `packages/${lib}/src/foo.spec.ts`, + ` + test('it should run', () => { + expect(true).toBeTruthy(); + }); + ` + ); + + expect(() => runCLI(`lint ${app}`)).not.toThrow(); + expect(() => runCLI(`test ${app}`)).not.toThrow(); + expect(() => runCLI(`build ${app}`)).not.toThrow(); + expect(() => runCLI(`lint ${lib}`)).not.toThrow(); + expect(() => runCLI(`test ${lib}`)).not.toThrow(); + expect(() => runCLI(`build ${lib}`)).not.toThrow(); + }, 300_000); +});