-
-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ feat(core): Add
createCacheForWalletSetupFunction
function (#955)
- Loading branch information
1 parent
3f5b549
commit e5bceee
Showing
5 changed files
with
189 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
declare global { | ||
namespace NodeJS { | ||
interface ProcessEnv { | ||
CI: boolean | ||
HEADLESS: boolean | ||
} | ||
} | ||
} | ||
|
||
export {} |
35 changes: 35 additions & 0 deletions
35
packages/core/src/utils/createCacheForWalletSetupFunction.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { chromium } from 'playwright-core' | ||
import type { WalletSetupFunction } from '../defineWalletSetup' | ||
import { waitForExtensionOnLoadPage } from './waitForExtensionOnLoadPage' | ||
|
||
// Inlining the sleep function here cause this is the ONLY place in the entire codebase where sleep should be used! | ||
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) | ||
|
||
export async function createCacheForWalletSetupFunction( | ||
extensionPath: string, | ||
contextCacheDirPath: string, | ||
walletSetup: WalletSetupFunction | ||
) { | ||
// TODO: Extract & Make a constant. | ||
const browserArgs = [`--disable-extensions-except=${extensionPath}`, `--load-extension=${extensionPath}`] | ||
|
||
if (process.env.HEADLESS) { | ||
browserArgs.push('--headless=new') | ||
} | ||
|
||
const context = await chromium.launchPersistentContext(contextCacheDirPath, { | ||
headless: false, | ||
args: browserArgs | ||
}) | ||
|
||
const extensionPage = await waitForExtensionOnLoadPage(context) | ||
|
||
await walletSetup(context, extensionPage) | ||
|
||
// We sleep here to give the browser enough time to save the context to the disk. | ||
await sleep(3000) // TODO: Extract & Make this timeout configurable. | ||
|
||
await context.close() | ||
|
||
return | ||
} |
140 changes: 140 additions & 0 deletions
140
packages/core/test/utils/createCacheForWalletSetupFunction.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { chromium } from 'playwright-core' | ||
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest' | ||
import { createCacheForWalletSetupFunction } from '../../src/utils/createCacheForWalletSetupFunction' | ||
import * as WaitForExtensionOnLoadPage from '../../src/utils/waitForExtensionOnLoadPage' | ||
|
||
const EXTENSION_PATH = '/tmp/extension' | ||
const CONTEXT_PATH = '/tmp/context' | ||
const EXPECTED_BROWSER_ARGS = [`--disable-extensions-except=${EXTENSION_PATH}`, `--load-extension=${EXTENSION_PATH}`] | ||
const EXPECTED_BROWSER_ARGS_FOR_HEADLESS = [...EXPECTED_BROWSER_ARGS, '--headless=new'] | ||
|
||
vi.mock('playwright-core', async (importOriginal) => { | ||
const actual = await importOriginal() | ||
return { | ||
// biome-ignore lint/suspicious/noExplicitAny: any type here is intentional | ||
...(actual as any), | ||
chromium: { | ||
launchPersistentContext: vi.fn().mockImplementation(async () => { | ||
return { | ||
close: vi.fn() | ||
} | ||
}) | ||
} | ||
} | ||
}) | ||
|
||
vi.mock('../../src/utils/waitForExtensionOnLoadPage', async () => { | ||
return { | ||
waitForExtensionOnLoadPage: vi.fn().mockResolvedValue({ | ||
duck: 'A mock Page full of quacks! 🦆' | ||
}) | ||
} | ||
}) | ||
|
||
describe('createCacheForWalletSetupFunction', () => { | ||
const launchPersistentContextSpy = vi.spyOn(chromium, 'launchPersistentContext') | ||
const walletSetup = vi.fn() | ||
|
||
const runCreateCacheForWalletSetupFunction = async () => { | ||
const promise = createCacheForWalletSetupFunction(EXTENSION_PATH, CONTEXT_PATH, walletSetup) | ||
await vi.runAllTimersAsync() | ||
await promise | ||
} | ||
|
||
afterAll(() => { | ||
vi.resetAllMocks() | ||
}) | ||
|
||
beforeAll(() => { | ||
vi.useFakeTimers() | ||
}) | ||
|
||
afterEach(() => { | ||
vi.clearAllMocks() | ||
}) | ||
|
||
it('calls chrome.launchPersistentContext with correct arguments', async () => { | ||
await runCreateCacheForWalletSetupFunction() | ||
|
||
expect(launchPersistentContextSpy).toHaveBeenCalledOnce() | ||
expect(launchPersistentContextSpy).toHaveBeenCalledWith(CONTEXT_PATH, { | ||
headless: false, | ||
args: EXPECTED_BROWSER_ARGS | ||
}) | ||
}) | ||
|
||
it('calls chrome.launchPersistentContext with correct arguments for headless mode', async () => { | ||
vi.stubEnv('HEADLESS', 'true') | ||
|
||
await runCreateCacheForWalletSetupFunction() | ||
|
||
expect(launchPersistentContextSpy).toHaveBeenCalledOnce() | ||
expect(launchPersistentContextSpy).toHaveBeenCalledWith(CONTEXT_PATH, { | ||
headless: false, | ||
args: EXPECTED_BROWSER_ARGS_FOR_HEADLESS | ||
}) | ||
|
||
vi.unstubAllEnvs() | ||
}) | ||
|
||
it('calls waitForExtensionOnLoadPage with correct argument', async () => { | ||
const waitForExtensionOnLoadPageSpy = vi.spyOn(WaitForExtensionOnLoadPage, 'waitForExtensionOnLoadPage') | ||
|
||
await runCreateCacheForWalletSetupFunction() | ||
|
||
expect(waitForExtensionOnLoadPageSpy).toHaveBeenCalledOnce() | ||
|
||
const context = launchPersistentContextSpy.mock.results[0]?.value | ||
expect(waitForExtensionOnLoadPageSpy).toHaveBeenCalledWith(context) | ||
}) | ||
|
||
it('calls walletSetup', async () => { | ||
const waitForExtensionOnLoadPageSpy = vi.spyOn(WaitForExtensionOnLoadPage, 'waitForExtensionOnLoadPage') | ||
|
||
await runCreateCacheForWalletSetupFunction() | ||
|
||
expect(walletSetup).toHaveBeenCalledOnce() | ||
|
||
const context = launchPersistentContextSpy.mock.results[0]?.value | ||
const extensionPage = waitForExtensionOnLoadPageSpy.mock.results[0]?.value | ||
expect(walletSetup).toHaveBeenCalledWith(context, extensionPage) | ||
}) | ||
|
||
it('closes context', async () => { | ||
const closeContext = vi.fn() | ||
// biome-ignore lint/suspicious/noExplicitAny: any type here is intentional | ||
launchPersistentContextSpy.mockResolvedValueOnce({ close: closeContext } as any) | ||
|
||
await runCreateCacheForWalletSetupFunction() | ||
|
||
expect(closeContext).toHaveBeenCalledOnce() | ||
}) | ||
|
||
it('sleeps before closing the context', async () => { | ||
const closeContext = vi.fn() | ||
// biome-ignore lint/suspicious/noExplicitAny: any type here is intentional | ||
launchPersistentContextSpy.mockResolvedValueOnce({ close: closeContext } as any) | ||
|
||
const setTimeoutSpy = vi.spyOn(global, 'setTimeout') | ||
|
||
const promise = createCacheForWalletSetupFunction(EXTENSION_PATH, CONTEXT_PATH, walletSetup) | ||
|
||
// Verify that nothing was run yet. | ||
expect(walletSetup).not.toHaveBeenCalled() | ||
expect(setTimeoutSpy).not.toHaveBeenCalled() | ||
expect(closeContext).not.toHaveBeenCalled() | ||
|
||
// Verify that sleep was triggered between `walletSetup` and `context.close` calls. | ||
await vi.advanceTimersByTimeAsync(100) | ||
expect(walletSetup).toHaveBeenCalledOnce() | ||
expect(setTimeoutSpy).toHaveBeenCalled() | ||
expect(closeContext).not.toHaveBeenCalled() | ||
|
||
// Verify that `context.close` was triggered after the sleep. | ||
await vi.runAllTimersAsync() | ||
await promise | ||
expect(walletSetup).toHaveBeenCalledOnce() | ||
expect(setTimeoutSpy).toHaveBeenCalledOnce() | ||
expect(closeContext).toHaveBeenCalledOnce() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,5 +6,6 @@ | |
"include": [ | ||
"src", | ||
"test" | ||
] | ||
], | ||
"files": ["environment.d.ts"] | ||
} |