diff --git a/jest.preset.js b/jest.preset.js index 28490c0c213ff3..8c28d1a19a1870 100644 --- a/jest.preset.js +++ b/jest.preset.js @@ -12,4 +12,6 @@ module.exports = { coverageReporters: ['html'], maxWorkers: 1, testEnvironment: 'node', + globalSetup: '../../scripts/unit-test-setup.js', + globalTeardown: '../../scripts/unit-test-teardown.js', }; diff --git a/packages/cypress/src/plugins/plugin.ts b/packages/cypress/src/plugins/plugin.ts index 5313637d35abcd..7634b7f7695f03 100644 --- a/packages/cypress/src/plugins/plugin.ts +++ b/packages/cypress/src/plugins/plugin.ts @@ -210,6 +210,7 @@ async function buildCypressTargets( ? cypressConfig.e2e.excludeSpecPattern.map((p) => join(projectRoot, p)) : [join(projectRoot, cypressConfig.e2e.excludeSpecPattern)]; const specFiles = await globWithWorkspaceContext( + context.workspaceRoot, specPatterns, excludeSpecPatterns ); diff --git a/packages/nx/src/daemon/client/client.ts b/packages/nx/src/daemon/client/client.ts index 0fb3fa08804af3..aa0c9829003ee9 100644 --- a/packages/nx/src/daemon/client/client.ts +++ b/packages/nx/src/daemon/client/client.ts @@ -4,7 +4,7 @@ import { readFileSync, statSync } from 'fs'; import { FileHandle, open } from 'fs/promises'; import { ensureDirSync, ensureFileSync } from 'fs-extra'; import { connect } from 'net'; -import { join } from 'path'; +import { extname, join } from 'path'; import { performance } from 'perf_hooks'; import { output } from '../../utils/output'; import { getFullOsSocketPath, killSocketOrPath } from '../socket-utils'; @@ -478,18 +478,35 @@ export class DaemonClient { this._out = await open(DAEMON_OUTPUT_LOG_FILE, 'a'); this._err = await open(DAEMON_OUTPUT_LOG_FILE, 'a'); - const backgroundProcess = spawn( - process.execPath, - [join(__dirname, '../server/start.js')], - { - cwd: workspaceRoot, - stdio: ['ignore', this._out.fd, this._err.fd], - detached: true, - windowsHide: true, - shell: false, - env: { ...process.env, ...DAEMON_ENV_SETTINGS }, - } - ); + // This stuff is only hit during our unit tests, + // as the daemon server is typescript during their execution. + const isTypescript = extname(__filename) === '.ts'; + const workerExt = isTypescript ? 'ts' : 'js'; + + const args = [join(__dirname, `../server/start.${workerExt}`)]; + + // If the daemon is typescript, we need to add the ts-node/register to support it. + if (isTypescript) { + args.unshift('-r', 'ts-node/register'); + } + + const backgroundProcess = spawn(process.execPath, args, { + cwd: workspaceRoot, + stdio: ['ignore', this._out.fd, this._err.fd], + detached: true, + windowsHide: true, + shell: false, + env: { + ...process.env, + ...DAEMON_ENV_SETTINGS, + ...(isTypescript + ? { + // Ensures that the worker uses the same tsconfig as the main process + TS_NODE_PROJECT: join(__dirname, '../../../tsconfig.lib.json'), + } + : {}), + }, + }); backgroundProcess.unref(); /** diff --git a/packages/nx/src/daemon/server/server.ts b/packages/nx/src/daemon/server/server.ts index 6310c497c372d1..47de78abe34a43 100644 --- a/packages/nx/src/daemon/server/server.ts +++ b/packages/nx/src/daemon/server/server.ts @@ -132,11 +132,12 @@ async function handleMessage(socket, data: string) { ); } - if (daemonIsOutdated()) { + const outdated = daemonIsOutdated(); + if (outdated) { await respondWithErrorAndExit( socket, - `Lock files changed`, - new Error('LOCK-FILES-CHANGED') + `Daemon outdated`, + new Error(outdated) ); } @@ -274,11 +275,19 @@ function registerProcessTerminationListeners() { let existingLockHash: string | undefined; -function daemonIsOutdated(): boolean { - return nxVersionChanged() || lockFileHashChanged(); +function daemonIsOutdated(): string | null { + if (nxVersionChanged()) { + return 'NX_VERSION_CHANGED'; + } else if (lockFileHashChanged()) { + return 'LOCK_FILES_CHANGED'; + } + return null; } function nxVersionChanged(): boolean { + if (process.env.NX_SKIP_NX_VERSION_CHECK === 'true') { + return false; + } return nxVersion !== getInstalledNxVersion(); } @@ -332,10 +341,11 @@ const handleWorkspaceChanges: FileWatcherCallback = async ( try { resetInactivityTimeout(handleInactivityTimeout); - if (daemonIsOutdated()) { + const outdatedReason = daemonIsOutdated(); + if (outdatedReason) { await handleServerProcessTermination({ server, - reason: 'Lock file changed', + reason: outdatedReason, }); return; } diff --git a/packages/nx/src/utils/workspace-context.ts b/packages/nx/src/utils/workspace-context.ts index 9640965e758f31..7fd48f1711cedf 100644 --- a/packages/nx/src/utils/workspace-context.ts +++ b/packages/nx/src/utils/workspace-context.ts @@ -89,7 +89,7 @@ export function getAllFileDataInContext(workspaceRoot: string) { return daemonClient.getAllFileData(); } -export function getFilesInDirectoryUsingContext( +export async function getFilesInDirectoryUsingContext( workspaceRoot: string, dir: string ) { diff --git a/packages/playwright/src/plugins/plugin.ts b/packages/playwright/src/plugins/plugin.ts index 69d143a3560e56..7cc373d1747840 100644 --- a/packages/playwright/src/plugins/plugin.ts +++ b/packages/playwright/src/plugins/plugin.ts @@ -163,7 +163,7 @@ async function buildPlaywrightTargets( playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)'; const dependsOn: TargetConfiguration['dependsOn'] = []; - forEachTestFile( + await forEachTestFile( (testFile) => { const relativeSpecFilePath = normalizePath( relative(projectRoot, testFile) @@ -210,7 +210,7 @@ async function buildPlaywrightTargets( return { targets, metadata }; } -function forEachTestFile( +async function forEachTestFile( cb: (path: string) => void, opts: { context: CreateNodesContext; @@ -218,7 +218,7 @@ function forEachTestFile( config: PlaywrightTestConfig; } ) { - const files = getFilesInDirectoryUsingContext( + const files = await getFilesInDirectoryUsingContext( opts.context.workspaceRoot, opts.path ); diff --git a/scripts/unit-test-setup.js b/scripts/unit-test-setup.js new file mode 100644 index 00000000000000..ed50e59cb71bac --- /dev/null +++ b/scripts/unit-test-setup.js @@ -0,0 +1,9 @@ +// Shuts down daemon before running any tests. This ensures that if a +// test needs the daemon, it will start up fresh and use the `.ts` daemon. +module.exports = () => { + process.env.NX_SKIP_NX_VERSION_CHECK = 'true'; + require('child_process').execSync('pnpm exec nx daemon --stop', { + shell: true, + stdio: 'inherit', + }); +}; diff --git a/scripts/unit-test-teardown.js b/scripts/unit-test-teardown.js new file mode 100644 index 00000000000000..a0d296b6af1d58 --- /dev/null +++ b/scripts/unit-test-teardown.js @@ -0,0 +1,6 @@ +// Shuts down daemon after running any tests. This ensures that subsequent +// commands use the installed Nx version's daemon. +module.exports = () => + require('child_process').execSync('pnpm exec nx daemon --stop', { + shell: true, + }); diff --git a/typedoc-theme/jest.config.ts b/typedoc-theme/jest.config.ts index 69cf4a39427b9c..9b0342cf74a083 100644 --- a/typedoc-theme/jest.config.ts +++ b/typedoc-theme/jest.config.ts @@ -14,5 +14,7 @@ export default { resolver: '../scripts/patched-jest-resolver.js', moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], coverageDirectory: '../coverage/typedoc-theme', + globalSetup: null, + globalTeardown: null, preset: '../jest.preset.js', };