Skip to content

Commit 12fd347

Browse files
committed
Handle non-serializable expected and actual values in parallel mode
Fixes #212
1 parent 7c31381 commit 12fd347

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

lib/parallel_worker.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ function forwardingReporter(clusterWorker) {
148148

149149
for (const eventName of eventNames) {
150150
reporter[eventName] = function (payload) {
151-
sendIfConnected(clusterWorker, {
151+
const msg = {
152152
type: 'reporterEvent',
153153
eventName,
154154
payload: {
@@ -157,7 +157,18 @@ function forwardingReporter(clusterWorker) {
157157
// Make them globally unique by prepending the worker ID.
158158
id: `${clusterWorker.id}-${payload.id}`
159159
}
160-
});
160+
};
161+
162+
try {
163+
sendIfConnected(clusterWorker, msg);
164+
} catch (e) {
165+
if (e instanceof TypeError) {
166+
msg.payload = fixNonSerializableReporterEvent(payload);
167+
sendIfConnected(clusterWorker, msg);
168+
} else {
169+
throw e;
170+
}
171+
}
161172
};
162173
}
163174

@@ -181,5 +192,29 @@ function sendIfConnected(clusterWorker, msg) {
181192
return false;
182193
}
183194

195+
function fixNonSerializableReporterEvent(payload) {
196+
payload = {...payload};
197+
198+
for (const ak of ['passedExpectations', 'failedExpectations']) {
199+
if (payload[ak]) {
200+
payload[ak] = payload[ak].map(function(expectation) {
201+
expectation = {...expectation};
202+
203+
for (const vk of ['expected', 'actual']) {
204+
try {
205+
JSON.stringify(expectation[vk]);
206+
} catch (ex) {
207+
expectation[vk] = '<not serializable>';
208+
}
209+
}
210+
211+
return expectation;
212+
});
213+
}
214+
}
215+
216+
return payload;
217+
}
218+
184219

185220
module.exports = ParallelWorker;

spec/parallel_worker_spec.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,50 @@ describe('ParallelWorker', function() {
620620
expect(this.clusterWorker.send).toHaveBeenCalledOnceWith({type: 'booted'});
621621
});
622622
}
623+
624+
for (const eventName of ['specDone', 'suiteDone']) {
625+
it(`handles non-serializable expected values in ${eventName}`, async function() {
626+
const env = jasmine.createSpyObj(
627+
'env', ['execute', 'parallelReset', 'addReporter']
628+
);
629+
const loader = jasmine.createSpyObj('loader', ['load']);
630+
loader.load.withArgs('jasmine-core')
631+
.and.returnValue(Promise.resolve(dummyCore(env)));
632+
const jasmineWorker = new ParallelWorker({
633+
loader,
634+
clusterWorker: this.clusterWorker,
635+
process: stubProcess()
636+
});
637+
638+
this.clusterWorker.emit('message', {
639+
type: 'configure',
640+
configuration: {
641+
helpers: [],
642+
}
643+
});
644+
await jasmineWorker.envPromise_;
645+
646+
this.clusterWorker.send.calls.reset();
647+
this.clusterWorker.send.and.callFake(function(msg) {
648+
// Throw if msg is not serializable
649+
JSON.stringify(msg);
650+
});
651+
const notSerializable = BigInt(0);
652+
dispatchRepoterEvent(env, eventName, {
653+
failedExpectations: [{expected: 'ok', actual: notSerializable}],
654+
passedExpectations: [{expected: notSerializable, actual: 'ok'}],
655+
});
656+
657+
expect(this.clusterWorker.send).toHaveBeenCalledWith({
658+
type: 'reporterEvent',
659+
eventName,
660+
payload: jasmine.objectContaining({
661+
failedExpectations: [{expected: 'ok', actual: '<not serializable>'}],
662+
passedExpectations: [{expected: '<not serializable>', actual: 'ok'}],
663+
})
664+
});
665+
});
666+
}
623667
});
624668

625669
it('reports unhandled exceptions that occur between batches', async function() {

0 commit comments

Comments
 (0)