nx/e2e/node/src/node-ts-solution.test.ts
Leosvel Pérez Espinosa dd9b09f917
fix(js): generate js libs with exports in package.json and ensure esm output when using rollup bundler (#29565)
- Ensure libs are generated with `exports` in `package.json`
- Generate `types` instead of `typings` in package.json
- Update js lib with rollup to only output esm
- Update `tsconfig.spec.json` for js libraries with rollup to set
`module: esnext` and `moduleResolution: bundler` (they use `@swc/jest`)
- Fix `@nx/js/typescript` issue with absolute paths when normalizing
inputs/outputs
- Fix `@nx/js/typescript` issue identifying buildable libs
- Fix express app generator not installing `@types/express`

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-01-10 08:29:09 -05:00

173 lines
4.7 KiB
TypeScript

import {
checkFilesExist,
cleanupProject,
getPackageManagerCommand,
getSelectedPackageManager,
killPorts,
newProject,
promisifiedTreeKill,
runCLI,
runCommand,
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}());`;
});
// pnpm does not link packages unless they are deps
// npm, yarn, and bun will link them in the root node_modules regardless
if (pm === 'pnpm') {
updateJson(`apps/${nodeapp}/package.json`, (json) => {
json.dependencies = {
[`@proj/${nodelib}`]: 'workspace:',
};
return json;
});
runCommand(getPackageManagerCommand().install);
}
runCLI(`sync`);
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`build ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`typecheck ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`lint ${nodelib}`)).not.toThrow();
expect(() => runCLI(`test ${nodelib}`)).not.toThrow();
expect(() => runCLI(`build ${nodelib}`)).not.toThrow();
expect(() => runCLI(`typecheck ${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<any> {
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);
}
});
});
});
}