Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/jest-docblock/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, '')
Expand All @@ -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, '')
Expand Down Expand Up @@ -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 = ' */';
Expand Down
24 changes: 14 additions & 10 deletions packages/jest-environment-jsdom/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ type Win = Window &
};
};

function isString(value: unknown): value is string {
return typeof value === 'string';
}

export default class JSDOMEnvironment implements JestEnvironment<number> {
dom: JSDOM | null;
fakeTimers: LegacyFakeTimers<number> | null;
Expand Down Expand Up @@ -65,33 +69,33 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
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);
}
};
global.addEventListener('error', this.errorEventListener);

// 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<typeof originalAddListener>
Expand All @@ -114,7 +118,7 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
const {customExportConditions} = projectConfig.testEnvironmentOptions;
if (
Array.isArray(customExportConditions) &&
customExportConditions.every(item => typeof item === 'string')
customExportConditions.every(isString)
) {
this.customExportConditions = customExportConditions;
} else {
Expand All @@ -124,7 +128,7 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
}
}

this.moduleMocker = new ModuleMocker(global as any);
this.moduleMocker = new ModuleMocker(global);

this.fakeTimers = new LegacyFakeTimers({
config: projectConfig,
Expand Down Expand Up @@ -152,7 +156,7 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
if (this.fakeTimersModern) {
this.fakeTimersModern.dispose();
}
if (this.global) {
if (this.global != null) {
if (this.errorEventListener) {
this.global.removeEventListener('error', this.errorEventListener);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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();
});
Expand Down
19 changes: 12 additions & 7 deletions packages/jest-environment-node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Timer> {
context: Context | null;
fakeTimers: LegacyFakeTimers<Timer> | null;
Expand All @@ -65,10 +69,11 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
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) {
Expand All @@ -78,7 +83,7 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
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, {
Expand All @@ -89,7 +94,7 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
});
return val;
},
set(val) {
set(val: unknown) {
// override lazy getter
Object.defineProperty(global, nodeGlobalsKey, {
configurable: descriptor.configurable,
Expand All @@ -102,6 +107,7 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
}
}

// @ts-expect-error - Buffer and gc is "missing"
global.global = global;
global.Buffer = Buffer;
global.ArrayBuffer = ArrayBuffer;
Expand All @@ -120,7 +126,7 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
const {customExportConditions} = projectConfig.testEnvironmentOptions;
if (
Array.isArray(customExportConditions) &&
customExportConditions.every(item => typeof item === 'string')
customExportConditions.every(isString)
) {
this.customExportConditions = customExportConditions;
} else {
Expand All @@ -142,8 +148,7 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
},
});

const timerRefToId = (timer: Timer): number | undefined =>
(timer && timer.id) || undefined;
const timerRefToId = (timer: Timer): number | undefined => timer?.id;

this.fakeTimers = new LegacyFakeTimers({
config: projectConfig,
Expand Down
4 changes: 3 additions & 1 deletion packages/jest-globals/src/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, (path: string) => boolean> = {
fancyCondition: path => path.length > 10,
Expand All @@ -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'],
Expand Down
4 changes: 2 additions & 2 deletions packages/jest-resolve-dependencies/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class DependencyResolver {
}
}

if (!resolvedDependency) {
if (resolvedDependency == null) {
return acc;
}

Expand All @@ -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__',
Expand Down
54 changes: 16 additions & 38 deletions packages/jest-test-result/src/formatTestResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@

import type {
AggregatedResult,
AssertionResult,
CodeCoverageFormatter,
CodeCoverageReporter,
FormattedAssertionResult,
FormattedTestResult,
FormattedTestResults,
TestResult,
Expand All @@ -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(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how this did anything

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,
Expand Down
Loading