Skip to content

Commit

Permalink
Allow functions to be passed to runJS (#234)
Browse files Browse the repository at this point in the history
  • Loading branch information
gerardo-rodriguez authored Sep 1, 2021
2 parents 009892a + bf53e31 commit 2914882
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/rotten-news-protect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'pleasantest': minor
---

Allow functions to be passed to runJS
33 changes: 31 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,30 @@ const createTab = async ({

await page.goto(`http://localhost:${port}`);

// eslint-disable-next-line @cloudfour/typescript-eslint/ban-types
const functionArgs: Function[] = [];

const runJS: PleasantestUtils['runJS'] = (code, args) =>
asyncHookTracker.addHook(async () => {
await page
.exposeFunction('pleasantest_callFunction', (id, args) =>
functionArgs[id](...args),
)
.catch((error) => {
if (!error.message.includes('already exists')) throw error;
});
// For some reason encodeURIComponent doesn't encode '
const encodedCode = encodeURIComponent(code).replace(/'/g, '%27');
const buildStatus = createBuildStatusTracker();

const argsWithFuncsAsObjs = args?.map((arg) => {
if (typeof arg === 'function') {
const id = functionArgs.push(arg) - 1;
return { isFunction: true, id };
}
return arg;
});

// This uses the testPath as the url so that if there are relative imports
// in the inline code, the relative imports are resolved relative to the test file
const url = `http://localhost:${port}/${testPath}?inline-code=${encodedCode}&build-id=${buildStatus.buildId}`;
Expand All @@ -310,14 +329,24 @@ const createTab = async ({
'...args',
`return import(${JSON.stringify(url)})
.then(async m => {
if (m.default) await m.default(...args)
const argsWithFuncs = args.map(arg => {
if (typeof arg === 'object' && arg && arg.isFunction) {
return async (...args) => {
return await window.pleasantest_callFunction(arg.id, args);
}
}
return arg
})
if (m.default) await m.default(...argsWithFuncs)
})
.catch(e =>
e instanceof Error
? { message: e.message, stack: e.stack }
: e)`,
) as () => any,
...(Array.isArray(args) ? (args as any) : []),
...(Array.isArray(argsWithFuncsAsObjs)
? (argsWithFuncsAsObjs as any)
: []),
);

const errorsFromBuild = buildStatus.complete();
Expand Down
23 changes: 23 additions & 0 deletions tests/utils/runJS.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,29 @@ test(
}),
);

test(
'allows passing functions to runJS',
withBrowser(async ({ utils }) => {
const mockFuncA = jest.fn(() => 5);
const mockFuncB = jest.fn();

await utils.runJS(
`
export default async (mockFuncA, mockFuncB) => {
const val = await mockFuncA('hello world')
if (val !== 5) throw new Error('Did not get return value');
await mockFuncB()
}
`,
[mockFuncA, mockFuncB],
);

expect(mockFuncA).toHaveBeenCalledTimes(1);
expect(mockFuncA).toHaveBeenCalledWith('hello world');
expect(mockFuncB).toHaveBeenCalledTimes(1);
}),
);

test(
'allows passing ElementHandles and serializable values into browser',
withBrowser(async ({ utils, screen }) => {
Expand Down

0 comments on commit 2914882

Please sign in to comment.