diff --git a/packages/jest-docblock/src/index.ts b/packages/jest-docblock/src/index.ts index f682fe90b1c3..82b3b1781394 100644 --- a/packages/jest-docblock/src/index.ts +++ b/packages/jest-docblock/src/index.ts @@ -39,7 +39,7 @@ export function parseWithComments(docblock: string): { comments: string; pragmas: Pragmas; } { - const line = detectNewline(docblock) || EOL; + const line = detectNewline(docblock) ?? EOL; docblock = docblock .replace(commentStartRe, '') @@ -54,7 +54,7 @@ export function parseWithComments(docblock: string): { } docblock = docblock.replace(ltrimNewlineRe, '').trimRight(); - const result = Object.create(null); + const result = Object.create(null) as Pragmas; const comments = docblock .replace(propertyRe, '') .replace(ltrimNewlineRe, '') @@ -83,7 +83,7 @@ export function print({ comments?: string; pragmas?: Pragmas; }): string { - const line = detectNewline(comments) || EOL; + const line = detectNewline(comments) ?? EOL; const head = '/**'; const start = ' *'; const tail = ' */'; diff --git a/packages/jest-environment-jsdom/src/index.ts b/packages/jest-environment-jsdom/src/index.ts index 7ae1345df4be..5973678a40f8 100644 --- a/packages/jest-environment-jsdom/src/index.ts +++ b/packages/jest-environment-jsdom/src/index.ts @@ -26,6 +26,10 @@ type Win = Window & }; }; +function isString(value: unknown): value is string { + return typeof value === 'string'; +} + export default class JSDOMEnvironment implements JestEnvironment { dom: JSDOM | null; fakeTimers: LegacyFakeTimers | null; @@ -65,24 +69,24 @@ export default class JSDOMEnvironment implements JestEnvironment { const global = (this.global = this.dom.window.document .defaultView as unknown as Win); - if (!global) { + if (global == null) { throw new Error('JSDOM did not return a Window object'); } - // for "universal" code (code should use `globalThis`) - global.global = global as any; + // @ts-expect-error - for "universal" code (code should use `globalThis`) + global.global = global; // Node's error-message stack size is limited at 10, but it's pretty useful // to see more than that when a test fails. this.global.Error.stackTraceLimit = 100; - installCommonGlobals(global as any, projectConfig.globals); + installCommonGlobals(global, projectConfig.globals); // TODO: remove this ASAP, but it currently causes tests to run really slow global.Buffer = Buffer; // Report uncaught errors. this.errorEventListener = event => { - if (userErrorListenerCount === 0 && event.error) { + if (userErrorListenerCount === 0 && event.error != null) { process.emit('uncaughtException', event.error); } }; @@ -90,8 +94,8 @@ export default class JSDOMEnvironment implements JestEnvironment { // However, don't report them as uncaught if the user listens to 'error' event. // In that case, we assume the might have custom error handling logic. - const originalAddListener = global.addEventListener; - const originalRemoveListener = global.removeEventListener; + const originalAddListener = global.addEventListener.bind(global); + const originalRemoveListener = global.removeEventListener.bind(global); let userErrorListenerCount = 0; global.addEventListener = function ( ...args: Parameters @@ -114,7 +118,7 @@ export default class JSDOMEnvironment implements JestEnvironment { const {customExportConditions} = projectConfig.testEnvironmentOptions; if ( Array.isArray(customExportConditions) && - customExportConditions.every(item => typeof item === 'string') + customExportConditions.every(isString) ) { this.customExportConditions = customExportConditions; } else { @@ -124,7 +128,7 @@ export default class JSDOMEnvironment implements JestEnvironment { } } - this.moduleMocker = new ModuleMocker(global as any); + this.moduleMocker = new ModuleMocker(global); this.fakeTimers = new LegacyFakeTimers({ config: projectConfig, @@ -152,7 +156,7 @@ export default class JSDOMEnvironment implements JestEnvironment { if (this.fakeTimersModern) { this.fakeTimersModern.dispose(); } - if (this.global) { + if (this.global != null) { if (this.errorEventListener) { this.global.removeEventListener('error', this.errorEventListener); } diff --git a/packages/jest-environment-node/src/__tests__/node_environment.test.ts b/packages/jest-environment-node/src/__tests__/node_environment.test.ts index fcfd8d0fcb88..47b385249f41 100644 --- a/packages/jest-environment-node/src/__tests__/node_environment.test.ts +++ b/packages/jest-environment-node/src/__tests__/node_environment.test.ts @@ -5,44 +5,60 @@ * LICENSE file in the root directory of this source tree. */ +import type {EnvironmentContext} from '@jest/environment'; import {makeGlobalConfig, makeProjectConfig} from '@jest/test-utils'; import NodeEnvironment from '../'; +const context: EnvironmentContext = { + console, + docblockPragmas: {}, + testPath: __filename, +}; + describe('NodeEnvironment', () => { it('uses a copy of the process object', () => { const testEnvConfig = { globalConfig: makeGlobalConfig(), projectConfig: makeProjectConfig(), }; - const env1 = new NodeEnvironment(testEnvConfig); - const env2 = new NodeEnvironment(testEnvConfig); + const env1 = new NodeEnvironment(testEnvConfig, context); + const env2 = new NodeEnvironment(testEnvConfig, context); expect(env1.global.process).not.toBe(env2.global.process); }); it('exposes process.on', () => { - const env1 = new NodeEnvironment({ - globalConfig: makeGlobalConfig(), - projectConfig: makeProjectConfig(), - }); + const env1 = new NodeEnvironment( + { + globalConfig: makeGlobalConfig(), + projectConfig: makeProjectConfig(), + }, + context, + ); expect(env1.global.process.on).not.toBeNull(); }); it('exposes global.global', () => { - const env1 = new NodeEnvironment({ - globalConfig: makeGlobalConfig(), - projectConfig: makeProjectConfig(), - }); + const env1 = new NodeEnvironment( + { + globalConfig: makeGlobalConfig(), + projectConfig: makeProjectConfig(), + }, + context, + ); expect(env1.global.global).toBe(env1.global); }); it('should configure setTimeout/setInterval to use the node api', () => { - const env1 = new NodeEnvironment({ - globalConfig: makeGlobalConfig(), - projectConfig: makeProjectConfig(), - }); + const env1 = new NodeEnvironment( + { + globalConfig: makeGlobalConfig(), + projectConfig: makeProjectConfig(), + }, + context, + ); env1.fakeTimers!.useFakeTimers(); @@ -57,10 +73,13 @@ describe('NodeEnvironment', () => { }); it('has modern fake timers implementation', () => { - const env = new NodeEnvironment({ - globalConfig: makeGlobalConfig(), - projectConfig: makeProjectConfig(), - }); + const env = new NodeEnvironment( + { + globalConfig: makeGlobalConfig(), + projectConfig: makeProjectConfig(), + }, + context, + ); expect(env.fakeTimersModern).toBeDefined(); }); diff --git a/packages/jest-environment-node/src/index.ts b/packages/jest-environment-node/src/index.ts index 97f8e319f7ba..5d326167e133 100644 --- a/packages/jest-environment-node/src/index.ts +++ b/packages/jest-environment-node/src/index.ts @@ -53,6 +53,10 @@ const nodeGlobals = new Map( }), ); +function isString(value: unknown): value is string { + return typeof value === 'string'; +} + export default class NodeEnvironment implements JestEnvironment { context: Context | null; fakeTimers: LegacyFakeTimers | null; @@ -65,10 +69,11 @@ export default class NodeEnvironment implements JestEnvironment { constructor(config: JestEnvironmentConfig, _context: EnvironmentContext) { const {projectConfig} = config; this.context = createContext(); - const global = (this.global = runInContext( + const global = runInContext( 'this', Object.assign(this.context, projectConfig.testEnvironmentOptions), - )); + ) as Global.Global; + this.global = global; const contextGlobals = new Set(Object.getOwnPropertyNames(global)); for (const [nodeGlobalsKey, descriptor] of nodeGlobals) { @@ -78,7 +83,7 @@ export default class NodeEnvironment implements JestEnvironment { enumerable: descriptor.enumerable, get() { // @ts-expect-error: no index signature - const val = globalThis[nodeGlobalsKey]; + const val = globalThis[nodeGlobalsKey] as unknown; // override lazy getter Object.defineProperty(global, nodeGlobalsKey, { @@ -89,7 +94,7 @@ export default class NodeEnvironment implements JestEnvironment { }); return val; }, - set(val) { + set(val: unknown) { // override lazy getter Object.defineProperty(global, nodeGlobalsKey, { configurable: descriptor.configurable, @@ -102,6 +107,7 @@ export default class NodeEnvironment implements JestEnvironment { } } + // @ts-expect-error - Buffer and gc is "missing" global.global = global; global.Buffer = Buffer; global.ArrayBuffer = ArrayBuffer; @@ -120,7 +126,7 @@ export default class NodeEnvironment implements JestEnvironment { const {customExportConditions} = projectConfig.testEnvironmentOptions; if ( Array.isArray(customExportConditions) && - customExportConditions.every(item => typeof item === 'string') + customExportConditions.every(isString) ) { this.customExportConditions = customExportConditions; } else { @@ -142,8 +148,7 @@ export default class NodeEnvironment implements JestEnvironment { }, }); - const timerRefToId = (timer: Timer): number | undefined => - (timer && timer.id) || undefined; + const timerRefToId = (timer: Timer): number | undefined => timer?.id; this.fakeTimers = new LegacyFakeTimers({ config: projectConfig, diff --git a/packages/jest-globals/src/__tests__/index.ts b/packages/jest-globals/src/__tests__/index.ts index 3cd8f7797b06..47a7a8cab632 100644 --- a/packages/jest-globals/src/__tests__/index.ts +++ b/packages/jest-globals/src/__tests__/index.ts @@ -6,7 +6,9 @@ */ test('throw when directly imported', () => { - expect(() => require('../')).toThrow( + expect(() => { + require('../'); + }).toThrow( 'Do not import `@jest/globals` outside of the Jest test environment', ); }); diff --git a/packages/jest-resolve-dependencies/src/__tests__/dependency_resolver.test.ts b/packages/jest-resolve-dependencies/src/__tests__/dependency_resolver.test.ts index 73d404a473fe..d6d98cdd8569 100644 --- a/packages/jest-resolve-dependencies/src/__tests__/dependency_resolver.test.ts +++ b/packages/jest-resolve-dependencies/src/__tests__/dependency_resolver.test.ts @@ -16,7 +16,6 @@ import {DependencyResolver} from '../index'; const maxWorkers = 1; let dependencyResolver: DependencyResolver; let runtimeContextResolver: Resolver; -let Runtime: typeof import('jest-runtime').default; let config: Config.ProjectConfig; const cases: Record boolean> = { fancyCondition: path => path.length > 10, @@ -26,7 +25,8 @@ const filter = (path: string) => Object.keys(cases).every(key => cases[key](path)); beforeEach(async () => { - Runtime = require('jest-runtime').default; + const Runtime = (require('jest-runtime') as typeof import('jest-runtime')) + .default; config = makeProjectConfig({ cacheDirectory: path.resolve(tmpdir(), 'jest-resolve-dependencies-test'), moduleDirectories: ['node_modules'], diff --git a/packages/jest-resolve-dependencies/src/index.ts b/packages/jest-resolve-dependencies/src/index.ts index 6e6c6c004cfc..75bb8d6c5ac4 100644 --- a/packages/jest-resolve-dependencies/src/index.ts +++ b/packages/jest-resolve-dependencies/src/index.ts @@ -61,7 +61,7 @@ export class DependencyResolver { } } - if (!resolvedDependency) { + if (resolvedDependency == null) { return acc; } @@ -78,7 +78,7 @@ export class DependencyResolver { // leave resolvedMockDependency as undefined if nothing can be found } - if (resolvedMockDependency) { + if (resolvedMockDependency != null) { const dependencyMockDir = path.resolve( path.dirname(resolvedDependency), '__mocks__', diff --git a/packages/jest-test-result/src/formatTestResults.ts b/packages/jest-test-result/src/formatTestResults.ts index 67ea02cf1b0a..60fb8ab0d039 100644 --- a/packages/jest-test-result/src/formatTestResults.ts +++ b/packages/jest-test-result/src/formatTestResults.ts @@ -7,10 +7,8 @@ import type { AggregatedResult, - AssertionResult, CodeCoverageFormatter, CodeCoverageReporter, - FormattedAssertionResult, FormattedTestResult, FormattedTestResults, TestResult, @@ -21,55 +19,35 @@ const formatTestResult = ( codeCoverageFormatter?: CodeCoverageFormatter, reporter?: CodeCoverageReporter, ): FormattedTestResult => { - const assertionResults = testResult.testResults.map(formatTestAssertion); if (testResult.testExecError) { const now = Date.now(); return { - assertionResults, + assertionResults: testResult.testResults, coverage: {}, endTime: now, - message: testResult.failureMessage - ? testResult.failureMessage - : testResult.testExecError.message, + message: testResult.failureMessage ?? testResult.testExecError.message, name: testResult.testFilePath, startTime: now, status: 'failed', summary: '', }; - } else { - const allTestsPassed = testResult.numFailingTests === 0; - return { - assertionResults, - coverage: codeCoverageFormatter - ? codeCoverageFormatter(testResult.coverage, reporter) - : testResult.coverage, - endTime: testResult.perfStats.end, - message: testResult.failureMessage || '', - name: testResult.testFilePath, - startTime: testResult.perfStats.start, - status: allTestsPassed ? 'passed' : 'failed', - summary: '', - }; } -}; -function formatTestAssertion( - assertion: AssertionResult, -): FormattedAssertionResult { - const result: FormattedAssertionResult = { - ancestorTitles: assertion.ancestorTitles, - duration: assertion.duration, - failureMessages: null, - fullName: assertion.fullName, - location: assertion.location, - status: assertion.status, - title: assertion.title, + const allTestsPassed = testResult.numFailingTests === 0; + return { + assertionResults: testResult.testResults, + coverage: + codeCoverageFormatter != null + ? codeCoverageFormatter(testResult.coverage, reporter) + : testResult.coverage, + endTime: testResult.perfStats.end, + message: testResult.failureMessage ?? '', + name: testResult.testFilePath, + startTime: testResult.perfStats.start, + status: allTestsPassed ? 'passed' : 'failed', + summary: '', }; - if (assertion.failureMessages) { - result.failureMessages = assertion.failureMessages; - } - return result; -} +}; export default function formatTestResults( results: AggregatedResult, diff --git a/packages/jest-test-result/src/helpers.ts b/packages/jest-test-result/src/helpers.ts index 539e51d247d8..882c49c5dbe2 100644 --- a/packages/jest-test-result/src/helpers.ts +++ b/packages/jest-test-result/src/helpers.ts @@ -128,7 +128,7 @@ export const addResult = ( aggregatedResults.snapshot.matched += testResult.snapshot.matched; aggregatedResults.snapshot.unchecked += testResult.snapshot.unchecked; if ( - testResult.snapshot.uncheckedKeys && + testResult.snapshot.uncheckedKeys != null && testResult.snapshot.uncheckedKeys.length > 0 ) { aggregatedResults.snapshot.uncheckedKeysByFile.push({ diff --git a/scripts/lintTs.mjs b/scripts/lintTs.mjs index 149ba0c53e5f..4ae352e36732 100644 --- a/scripts/lintTs.mjs +++ b/scripts/lintTs.mjs @@ -26,7 +26,16 @@ const packagesToTest = [ 'babel-jest', 'babel-plugin-jest-hoist', 'diff-sequences', + 'jest-docblock', + 'jest-environment', + 'jest-globals', + 'jest-resolve-dependencies', + 'jest-schemas', 'jest-source-map', + 'jest-test-result', + 'jest-types', + 'test-globals', + 'test-utils', ]; const packagesWithTs = getPackagesWithTsConfig()