Skip to content

Commit 29b8671

Browse files
authored
Allow returning non-serializable values from waitFor (#732)
1 parent 2244265 commit 29b8671

4 files changed

Lines changed: 52 additions & 26 deletions

File tree

.changeset/proud-spies-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'pleasantest': minor
3+
---
4+
5+
Allow returning non-serializable values from `waitFor`

jest.config.cjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
module.exports = {
2+
// See https://jestjs.io/docs/configuration/#prettierpath-string -> "Prettier version 3 is not supported!"
3+
// Blocked by https://github.com/prettier/prettier-synchronized/issues/4#issuecomment-1649355749
4+
// and https://github.com/jestjs/jest/pull/14311#issuecomment-1649358074
5+
prettierPath: null,
26
testEnvironment: 'node',
37
moduleNameMapper: {
48
'^pleasantest$': '<rootDir>/dist/cjs/index.cjs',

src/pptr-testing-library.ts

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -247,22 +247,12 @@ export interface WaitForOptions {
247247
mutationObserverOptions?: MutationObserverInit;
248248
}
249249

250-
interface WaitFor {
251-
<T>(
252-
page: Page,
253-
asyncHookTracker: AsyncHookTracker,
254-
cb: () => T | Promise<T>,
255-
{ onTimeout, container, ...opts }: WaitForOptions,
256-
wrappedFunction: (...args: any) => any,
257-
): Promise<T>;
258-
}
259-
260-
export const waitFor: WaitFor = async (
261-
page,
262-
asyncHookTracker,
263-
cb,
264-
{ onTimeout, container, ...opts },
265-
wrappedFunction,
250+
export const waitFor = async <T>(
251+
page: Page,
252+
asyncHookTracker: AsyncHookTracker,
253+
cb: () => T | Promise<T>,
254+
{ onTimeout, container, ...opts }: WaitForOptions,
255+
wrappedFunction: (...args: any) => any,
266256
) =>
267257
asyncHookTracker.addHook(async () => {
268258
const { port } = await createClientRuntimeServer();
@@ -272,7 +262,10 @@ export const waitFor: WaitFor = async (
272262
// So we need a unique name for each variable
273263
const browserFuncName = `pleasantest_waitFor_${waitForCounter}`;
274264

275-
await page.exposeFunction(browserFuncName, cb);
265+
let returnValue: T | undefined;
266+
await page.exposeFunction(browserFuncName, async () => {
267+
returnValue = await cb();
268+
});
276269

277270
const evalResult = await page.evaluateHandle(
278271
// Using new Function to avoid babel transpiling the import
@@ -282,8 +275,8 @@ export const waitFor: WaitFor = async (
282275
`return import("http://localhost:${port}/@pleasantest/dom-testing-library")
283276
.then(async ({ waitFor }) => {
284277
try {
285-
const result = await waitFor(${browserFuncName}, { ...opts, container })
286-
return { success: true, result }
278+
await waitFor(${browserFuncName}, { ...opts, container })
279+
return { success: true }
287280
} catch (error) {
288281
if (/timed out in waitFor/i.test(error.message)) {
289282
// Leave out stack trace so the stack trace is given from Node
@@ -298,12 +291,11 @@ export const waitFor: WaitFor = async (
298291
container,
299292
);
300293
const wasSuccessful = await evalResult.evaluate((r) => r.success);
301-
const result = await evalResult.evaluate((r) =>
302-
r.success
303-
? r.result
304-
: { message: r.result.message, stack: r.result.stack },
305-
);
306-
if (wasSuccessful) return result;
294+
if (wasSuccessful) return returnValue as T;
295+
const result = await evalResult.evaluate((r) => ({
296+
message: r.result.message,
297+
stack: r.result.stack,
298+
}));
307299
const err = new Error(result.message);
308300
if (result.stack) err.stack = result.stack;
309301
else removeFuncFromStackTrace(err, asyncHookTracker.addHook);

tests/wait-for.test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,29 @@ test(
2525
}),
2626
);
2727

28+
test(
29+
'Returned non-serializable values',
30+
withBrowser(async ({ utils, page, waitFor }) => {
31+
await utils.runJS(`
32+
setTimeout(() => {
33+
document.title = 'hallo'
34+
}, 100)
35+
`);
36+
// At first the title won't be set to hallo
37+
// Because it waits 100ms before it sets it
38+
expect(await page.title()).not.toEqual('hallo');
39+
const imNotSerializable = Symbol('test');
40+
const waitForCallback = jest.fn(async () => {
41+
expect(await page.title()).toEqual('hallo');
42+
return imNotSerializable;
43+
});
44+
const returnedValue = await waitFor(waitForCallback);
45+
expect(returnedValue).toBe(imNotSerializable);
46+
expect(await page.title()).toEqual('hallo');
47+
expect(waitForCallback).toHaveBeenCalled();
48+
}),
49+
);
50+
2851
test(
2952
'Throws error with timeout',
3053
withBrowser(async ({ waitFor }) => {
@@ -40,7 +63,9 @@ test(
4063
tests/wait-for.test.ts
4164
4265
throw new Error('something bad happened');
43-
^"
66+
^
67+
-------------------------------------------------------
68+
dist/cjs/index.cjs"
4469
`);
4570

4671
// If the callback function never resolves (or takes too long to resolve),

0 commit comments

Comments
 (0)