Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial version of jest-worker #4497

Merged
merged 8 commits into from
Oct 4, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
50 changes: 49 additions & 1 deletion packages/jest-worker/src/__tests__/child.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
'use strict';

const mockError = new TypeError('Booo');
const mockExtendedError = new ReferenceError('Booo extended');
const processExit = process.exit;
const processSend = process.send;
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
Expand Down Expand Up @@ -43,6 +44,21 @@ beforeEach(() => {
});
},

fooThrowsNull() {
throw null;
},

fooThrowsANumber() {
throw 412;
},

fooThrowsAnErrorWithExtraProperties() {
mockExtendedError.baz = 123;
mockExtendedError.qux = 456;

throw mockExtendedError;
},

fooThrows() {
throw mockError;
},
Expand Down Expand Up @@ -139,9 +155,40 @@ it('returns results immediately when function is synchronous', () => {
'TypeError',
'Booo',
mockError.stack,
{},
]);

expect(process.send.mock.calls.length).toBe(2);
process.emit('message', [
CHILD_MESSAGE_CALL,
true, // Not really used here, but for flow type purity.
'fooThrowsANumber',
[],
]);

expect(process.send.mock.calls[2][0]).toEqual([
PARENT_MESSAGE_ERROR,
'Number',
void 0,
void 0,
412,
]);

process.emit('message', [
CHILD_MESSAGE_CALL,
true, // Not really used here, but for flow type purity.
'fooThrowsAnErrorWithExtraProperties',
[],
]);

expect(process.send.mock.calls[3][0]).toEqual([
PARENT_MESSAGE_ERROR,
'ReferenceError',
'Booo extended',
mockExtendedError.stack,
{baz: 123, qux: 456},
]);

expect(process.send.mock.calls.length).toBe(4);
});

it('returns results when it gets resolved if function is asynchronous', async () => {
Expand Down Expand Up @@ -178,6 +225,7 @@ it('returns results when it gets resolved if function is asynchronous', async ()
'TypeError',
'Booo',
mockError.stack,
{},
]);

expect(process.send.mock.calls.length).toBe(2);
Expand Down
17 changes: 17 additions & 0 deletions packages/jest-worker/src/__tests__/worker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ it('relates replies to requests, in order', () => {
'TypeError',
'foo',
'TypeError: foo',
{},
]);

expect(callback2.mock.calls[0][0].message).toBe('foo');
Expand All @@ -158,6 +159,7 @@ it('creates error instances for known errors', () => {

const callback1 = jest.fn();
const callback2 = jest.fn();
const callback3 = jest.fn();

// Testing a generic ECMAScript error.
worker.send([CHILD_MESSAGE_CALL, false, 'method', []], callback1);
Expand All @@ -167,6 +169,7 @@ it('creates error instances for known errors', () => {
'TypeError',
'bar',
'TypeError: bar',
{},
]);

expect(callback1.mock.calls[0][0]).toBeInstanceOf(TypeError);
Expand All @@ -182,12 +185,26 @@ it('creates error instances for known errors', () => {
'RandomCustomError',
'bar',
'RandomCustomError: bar',
{},
]);

expect(callback2.mock.calls[0][0]).toBeInstanceOf(Error);
expect(callback2.mock.calls[0][0].message).toBe('bar');
expect(callback2.mock.calls[0][0].type).toBe('RandomCustomError');
expect(callback2.mock.calls[0][0].stack).toBe('RandomCustomError: bar');

// Testing a non-object throw.
worker.send([CHILD_MESSAGE_CALL, false, 'method', []], callback3);

forkInterface.emit('message', [
PARENT_MESSAGE_ERROR,
'Number',
null,
null,
412,
]);

expect(callback3.mock.calls[0][0]).toBe(412);
});

it('throws when the child process returns a strange message', () => {
Expand Down
7 changes: 6 additions & 1 deletion packages/jest-worker/src/child.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,16 @@ function reportError(error: Error) {
throw new Error('Child can only be used on a forked process');
}

if (error == null) {
error = new Error('"null" or "undefined" thrown');
}

process.send([
PARENT_MESSAGE_ERROR,
error.constructor.name,
error.constructor && error.constructor.name,
error.message,
Copy link
Member

Choose a reason for hiding this comment

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

What happens when a string is thrown? throw 'Foo'?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just added a commit to allow this.

error.stack,
typeof error === 'object' ? Object.assign({}, error) : error,
]);
}

Expand Down
9 changes: 5 additions & 4 deletions packages/jest-worker/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export type ChildMessageCall = [
typeof CHILD_MESSAGE_CALL, // type
boolean, // processed
string, // method
Array<any>, // args
$ReadOnlyArray<any>, // args
];

export type ChildMessageEnd = [
Expand All @@ -81,9 +81,10 @@ export type ParentMessageOk = [

export type ParentMessageError = [
typeof PARENT_MESSAGE_ERROR, // type
string, // constructor,
string, // message,
string, // stack,
string, // constructor
string, // message
string, // stack
any, // extra
];

export type ParentMessage = ParentMessageOk | ParentMessageError;
Expand Down
27 changes: 19 additions & 8 deletions packages/jest-worker/src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,25 @@ export default class {
break;

case PARENT_MESSAGE_ERROR:
// Try using a native constructor (e.g. TypeError) first, if it exists.
const NativeCtor = global[response[1]];
const Ctor = typeof NativeCtor === 'function' ? NativeCtor : Error;
const error = new Ctor(response[2]);

// $FlowFixMe: "type" is a custom property.
error.type = response[1];
error.stack = response[3];
let error = response[4];

if ((error != null) && (typeof error === 'object')) {
const extra = error;
const NativeCtor = global[response[1]];
const Ctor = typeof NativeCtor === 'function' ? NativeCtor : Error;

error = new Ctor(response[2]);
// $FlowFixMe: adding custom properties to errors.
error.type = response[1];
error.stack = response[3];

for (const key in extra) {
if (extra.hasOwnProperty(key)) {
// $FlowFixMe: adding custom properties to errors.
error[extra] = key;
}
}
}

callback.call(this, error, null);
break;
Expand Down