Skip to content
/ jest Public
forked from jestjs/jest

Commit

Permalink
feat: stringify Errors properly with --json flag (jestjs#15329)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyd33 authored Jan 15, 2025
1 parent c987cf8 commit afc0cfb
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 9 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
- `[@jest/core]` Add `perfStats` to surface test setup overhead ([#14622](https://github.com/jestjs/jest/pull/14622))
- `[@jest/core]` [**BREAKING**] Changed `--filter` to accept an object with shape `{ filtered: Array<string> }` to match [documentation](https://jestjs.io/docs/cli#--filterfile) ([#13319](https://github.com/jestjs/jest/pull/13319))
- `[@jest/core]` Support `--outputFile` option for [`--listTests`](https://jestjs.io/docs/cli#--listtests) ([#14980](https://github.com/jestjs/jest/pull/14980))
- `[@jest/core]` Stringify Errors properly with `--json` flag ([#15329](https://github.com/jestjs/jest/pull/15329))
- `[@jest/core, @jest/test-sequencer]` [**BREAKING**] Exposes `globalConfig` & `contexts` to `TestSequencer` ([#14535](https://github.com/jestjs/jest/pull/14535), & [#14543](https://github.com/jestjs/jest/pull/14543))
- `[jest-each]` Introduce `%$` option to add number of the test to its title ([#14710](https://github.com/jestjs/jest/pull/14710))
- `[@jest/environment]` [**BREAKING**] Remove deprecated `jest.genMockFromModule()` ([#15042](https://github.com/jestjs/jest/pull/15042))
- `[@jest/environment]` [**BREAKING**] Remove unnecessary defensive code ([#15045](https://github.com/jestjs/jest/pull/15045))
- `[jest-environment-jsdom]` [**BREAKING**] Upgrade JSDOM to v22 ([#13825](https://github.com/jestjs/jest/pull/13825))
Expand All @@ -39,15 +41,14 @@
- `[jest-runtime]` Support `import.meta.resolve` ([#14930](https://github.com/jestjs/jest/pull/14930))
- `[jest-runtime]` [**BREAKING**] Make it mandatory to pass `globalConfig` to the `Runtime` constructor ([#15044](https://github.com/jestjs/jest/pull/15044))
- `[jest-runtime]` Add `unstable_unmockModule` ([#15080](https://github.com/jestjs/jest/pull/15080))
- `[jest-runtime]` Add `onGenerateMock` transformer callback for auto generated callbacks ([#15433](https://github.com/jestjs/jest/pull/15433))
- `[@jest/schemas]` Upgrade `@sinclair/typebox` to v0.34 ([#15450](https://github.com/jestjs/jest/pull/15450))
- `[@jest/types]` `test.each()`: Accept a readonly (`as const`) table properly ([#14565](https://github.com/jestjs/jest/pull/14565))
- `[@jest/types]` Improve argument type inference passed to `test` and `describe` callback functions from `each` tables ([#14920](https://github.com/jestjs/jest/pull/14920))
- `[jest-snapshot]` [**BREAKING**] Add support for [Error causes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) in snapshots ([#13965](https://github.com/facebook/jest/pull/13965))
- `[jest-snapshot]` Support Prettier 3 ([#14566](https://github.com/facebook/jest/pull/14566))
- `[@jest/util-snapshot]` Extract utils used by tooling from `jest-snapshot` into its own package ([#15095](https://github.com/facebook/jest/pull/15095))
- `[pretty-format]` [**BREAKING**] Do not render empty string children (`''`) in React plugin ([#14470](https://github.com/facebook/jest/pull/14470))
- `[jest-each]` Introduce `%$` option to add number of the test to its title ([#14710](https://github.com/jestjs/jest/pull/14710))
- `[jest-runtime]` Add `onGenerateMock` transformer callback for auto generated callbacks ([#15433](https://github.com/jestjs/jest/pull/15433))

### Fixes

Expand Down
49 changes: 49 additions & 0 deletions packages/jest-core/src/lib/__tests__/serializeToJSON.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import serializeToJSON from '../serializeToJSON';

// populate an object with all basic JavaScript datatypes
const object = {
chillness: 100,
flaws: null,
hopOut: {
atThe: 'after party',
when: new Date('2000-07-14'),
},
i: ['pull up'],
location: undefined,
ok: true,
species: 'capybara',
weight: 9.5,
};

it('serializes regular objects like JSON.stringify', () => {
expect(serializeToJSON(object)).toEqual(JSON.stringify(object));
});

it('serializes errors', () => {
const objectWithError = {
...object,
error: new Error('too cool'),
};
const withError = serializeToJSON(objectWithError);
const withoutError = JSON.stringify(objectWithError);

expect(withoutError).not.toEqual(withError);

expect(withError).toContain('"message":"too cool"');
expect(withError).toContain('"name":"Error"');
expect(withError).toContain('"stack":"Error:');

expect(JSON.parse(withError)).toMatchObject({
error: {
message: 'too cool',
name: 'Error',
},
});
});
37 changes: 37 additions & 0 deletions packages/jest-core/src/lib/serializeToJSON.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {isNativeError} from 'node:util/types';

/**
* When we're asked to give a JSON output with the --json flag or otherwise,
* some data we need to return don't serialize well with a basic
* `JSON.stringify`, particularly Errors returned in `.openHandles`.
*
* This function handles the extended serialization wanted above.
*/
export default function serializeToJSON(
value: unknown,
space?: string | number,
): string {
return JSON.stringify(
value,
(_, value) => {
// There might be more in Error, but pulling out just the message, name,
// and stack should be good enough
if (isNativeError(value)) {
return {
message: value.message,
name: value.name,
stack: value.stack,
};
}
return value;
},
space,
);
}
11 changes: 4 additions & 7 deletions packages/jest-core/src/runJest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import collectNodeHandles, {
type HandleCollectionResult,
} from './collectHandles';
import getNoTestsFoundMessage from './getNoTestsFoundMessage';
import serializeToJSON from './lib/serializeToJSON';
import runGlobalHook from './runGlobalHook';
import type {Filter, TestRunData} from './types';

Expand Down Expand Up @@ -111,21 +112,17 @@ const processResults = async (
runResults = await processor(runResults);
}
if (isJSON) {
const jsonString = serializeToJSON(formatTestResults(runResults));
if (outputFile) {
const cwd = tryRealpath(process.cwd());
const filePath = path.resolve(cwd, outputFile);

fs.writeFileSync(
filePath,
`${JSON.stringify(formatTestResults(runResults))}\n`,
);
fs.writeFileSync(filePath, `${jsonString}\n`);
outputStream.write(
`Test results written to: ${path.relative(cwd, filePath)}\n`,
);
} else {
process.stdout.write(
`${JSON.stringify(formatTestResults(runResults))}\n`,
);
process.stdout.write(`${jsonString}\n`);
}
}

Expand Down

0 comments on commit afc0cfb

Please sign in to comment.