Skip to content

Commit

Permalink
fix(node): Enable e2e test (#23508)
Browse files Browse the repository at this point in the history
Re-enables e2e tests for node 

Docker changes to be merged first: #26365
  • Loading branch information
ndcunningham authored Jul 4, 2024
1 parent 929a57c commit 295c422
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 62 deletions.
29 changes: 29 additions & 0 deletions e2e/node/src/__snapshots__/node-server.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Node Applications + webpack should generate a Dockerfile 1`] = `
"# This file is generated by Nx.
#
# Build the docker image with \`npx nx docker-build docker-express-app\`.
# Tip: Modify "docker-build" options in project.json to change docker build args.
#
# Run the container with \`docker run -p 3000:3000 -t docker-express-app\`.
FROM docker.io/node:lts-alpine
ENV HOST=0.0.0.0
ENV PORT=3000
WORKDIR /app
RUN addgroup --system docker-express-app && \\
adduser --system -G docker-express-app docker-express-app
COPY dist/apps/docker-express-app docker-express-app/
RUN chown -R docker-express-app:docker-express-app .
# You can remove this install step if you build with \`--bundle\` option.
# The bundled output will include external dependencies.
RUN npm --prefix docker-express-app --omit=dev -f install
CMD [ "node", "docker-express-app" ]
"
`;
148 changes: 87 additions & 61 deletions e2e/node/src/node-server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
checkFilesDoNotExist,
checkFilesExist,
cleanupProject,
getSelectedPackageManager,
killPort,
newProject,
promisifiedTreeKill,
Expand All @@ -14,11 +15,19 @@ import {
} from '@nx/e2e/utils';
import { join } from 'path';

xdescribe('Node Applications + webpack', () => {
describe('Node Applications + webpack', () => {
let proj: string;
const selectedPm = getSelectedPackageManager();

// TODO(nicholas): Look into how this can work with npm instead of forcing pnpm.
beforeAll(() => {
proj = newProject({
packages: ['@nx/node'],
// npm has resolution for ajv some packages require ajv6 and some require ajv8 and npm resolves it to ajv6 (Error: Cannot find module 'ajv/dist/compile/codegen')
// - ajv@6 (fork-ts-checker-webpack-plugin, terser-webpack-plugin, webpack)
// - ajv@8 (babel-loader)
// Solution is to use pnpm or run fix it via npm ex.(npm dedupe --force)
packageManager: selectedPm === 'npm' ? 'pnpm' : selectedPm,
});
});

Expand Down Expand Up @@ -47,104 +56,121 @@ xdescribe('Node Applications + webpack', () => {
}
}

async function runE2eTests(appName: string) {
process.env.PORT = '5000';
async function runE2eTests(appName: string, port: number = 5000) {
process.env.PORT = `${port}`;
const childProcess = await runCommandUntil(`serve ${appName}`, (output) => {
return output.includes('http://localhost:5000');
return output.includes(`http://localhost:${port}`);
});
const result = runCLI(`e2e ${appName}-e2e --verbose`);
expect(result).toContain('Setting up...');
expect(result).toContain('Tearing down..');
expect(result).toContain('Successfully ran target e2e');

await promisifiedTreeKill(childProcess.pid, 'SIGKILL');
await killPort(5000);
await killPort(port);
process.env.PORT = '';
}

// Disabled due to flakiness of ajv disabled (Error: Cannot find module 'ajv/dist/compile/codegen')
// TODO: (nicholas) Re-enable when the flakiness is resolved
xit('should generate an app using webpack', async () => {
describe('frameworks', () => {
const testLib1 = uniq('test1');
const testLib2 = uniq('test2');
const expressApp = uniq('expressapp');
const fastifyApp = uniq('fastifyapp');
const koaApp = uniq('koaapp');
const nestApp = uniq('nest');

runCLI(`generate @nx/node:lib ${testLib1}`);
runCLI(`generate @nx/node:lib ${testLib2} --importPath=@acme/test2`);
runCLI(
`generate @nx/node:app ${expressApp} --framework=express --no-interactive`
);
runCLI(
`generate @nx/node:app ${fastifyApp} --framework=fastify --no-interactive`
);
runCLI(`generate @nx/node:app ${koaApp} --framework=koa --no-interactive`);
runCLI(
`generate @nx/node:app ${nestApp} --framework=nest --bundler=webpack --no-interactive`
);
beforeAll(() => {
runCLI(`generate @nx/node:lib ${testLib1}`);
runCLI(`generate @nx/node:lib ${testLib2} --importPath=@acme/test2`);
runCLI(
`generate @nx/node:app ${expressApp} --framework=express --port=7000 --no-interactive`
);
runCLI(
`generate @nx/node:app ${fastifyApp} --framework=fastify --port=7001 --no-interactive`
);
runCLI(
`generate @nx/node:app ${koaApp} --framework=koa --port=7002 --no-interactive`
);
runCLI(
`generate @nx/node:app ${nestApp} --framework=nest --port=7003 --bundler=webpack --no-interactive`
);

// Use esbuild by default
checkFilesDoNotExist(`apps/${expressApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${fastifyApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${koaApp}/webpack.config.js`);
addLibImport(expressApp, testLib1);
addLibImport(expressApp, testLib2, '@acme/test2');
addLibImport(fastifyApp, testLib1);
addLibImport(fastifyApp, testLib2, '@acme/test2');
addLibImport(koaApp, testLib1);
addLibImport(koaApp, testLib2, '@acme/test2');

// Uses only webpack
checkFilesExist(`apps/${nestApp}/webpack.config.js`);
addLibImport(nestApp, testLib1);
addLibImport(nestApp, testLib2, '@acme/test2');
});

expect(() => runCLI(`lint ${expressApp}`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}`)).not.toThrow();
it('should generate an app defaults using webpack or esbuild', async () => {
// Use esbuild by default
checkFilesDoNotExist(`apps/${expressApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${fastifyApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${koaApp}/webpack.config.js`);

expect(() => runCLI(`lint ${expressApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}-e2e`)).not.toThrow();
// Uses only webpack
checkFilesExist(`apps/${nestApp}/webpack.config.js`);

// Only Fastify generates with unit tests since it supports them without additional libraries.
expect(() => runCLI(`test ${fastifyApp}`)).not.toThrow();
expect(() => runCLI(`lint ${expressApp}`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}`)).not.toThrow();

// https://github.com/nrwl/nx/issues/16601
const nestMainContent = readFile(`apps/${nestApp}/src/main.ts`);
updateFile(
`apps/${nestApp}/src/main.ts`,
`
expect(() => runCLI(`lint ${expressApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}-e2e`)).not.toThrow();

// Only Fastify generates with unit tests since it supports them without additional libraries.
expect(() => runCLI(`test ${fastifyApp}`)).not.toThrow();

// https://github.com/nrwl/nx/issues/16601
const nestMainContent = readFile(`apps/${nestApp}/src/main.ts`);
updateFile(
`apps/${nestApp}/src/main.ts`,
`
${nestMainContent}
// Make sure this is not replaced during build time
console.log('env: ' + process.env['NODE_ENV']);
`
);
runCLI(`build ${nestApp}`);
expect(readFile(`dist/apps/${nestApp}/main.js`)).toContain(
`'env: ' + process.env['NODE_ENV']`
);
);
runCLI(`build ${nestApp}`);
expect(readFile(`dist/apps/${nestApp}/main.js`)).toContain(
`'env: ' + process.env['NODE_ENV']`
);
}, 300_000);

addLibImport(expressApp, testLib1);
addLibImport(expressApp, testLib2, '@acme/test2');
addLibImport(fastifyApp, testLib1);
addLibImport(fastifyApp, testLib2, '@acme/test2');
addLibImport(koaApp, testLib1);
addLibImport(koaApp, testLib2, '@acme/test2');
it('should e2e test express app', async () => {
await runE2eTests(expressApp, 7000);
});

addLibImport(nestApp, testLib1);
addLibImport(nestApp, testLib2, '@acme/test2');
it('should e2e test fastify app', async () => {
await runE2eTests(fastifyApp, 7001);
});

await runE2eTests(expressApp);
await runE2eTests(fastifyApp);
await runE2eTests(koaApp);
await runE2eTests(nestApp);
}, 900_000);
it('should e2e test koa app', async () => {
await runE2eTests(koaApp, 7002);
});

it('should e2e test nest app', async () => {
await runE2eTests(nestApp, 7003);
});
});

it('should generate a Dockerfile', async () => {
const expressApp = uniq('expressapp');
const expressApp = 'docker-express-app'; // needs to be consistent for the Dockerfile snapshot

runCLI(
`generate @nx/node:app ${expressApp} --framework=express --docker --no-interactive`
`generate @nx/node:app ${expressApp} --framework=express --docker --no-interactive`
);

checkFilesExist(`apps/${expressApp}/Dockerfile`);
const dockerFile = readFile(`apps/${expressApp}/Dockerfile`);
expect(dockerFile).toMatchSnapshot();
}, 300_000);

it('should support waitUntilTargets for serve target', async () => {
Expand Down
12 changes: 11 additions & 1 deletion packages/node/src/generators/setup-docker/setup-docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,22 @@ function normalizeOptions(

function addDocker(tree: Tree, options: SetUpDockerOptions) {
const projectConfig = readProjectConfiguration(tree, options.project);

const outputPath =
projectConfig.targets[options.buildTarget]?.options['outputPath'];

if (!projectConfig) {
throw new Error(`Cannot find project configuration for ${options.project}`);
}

if (!outputPath && !options.outputPath) {
throw new Error(
`The output path for the project ${options.project} is not defined. Please provide it as an option to the generator.`
);
}
generateFiles(tree, join(__dirname, './files'), projectConfig.root, {
tmpl: '',
buildLocation: options.outputPath,
buildLocation: options.outputPath ?? outputPath,
project: options.project,
});
}
Expand Down

0 comments on commit 295c422

Please sign in to comment.