Skip to content

Commit

Permalink
✨ feat(core): Add createCacheForWalletSetupFunction function (#955)
Browse files Browse the repository at this point in the history
  • Loading branch information
duckception authored Oct 26, 2023
1 parent 3f5b549 commit e5bceee
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 2 deletions.
10 changes: 10 additions & 0 deletions packages/core/environment.d.ts
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 packages/core/src/utils/createCacheForWalletSetupFunction.ts
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 packages/core/test/utils/createCacheForWalletSetupFunction.test.ts
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()
})
})
3 changes: 2 additions & 1 deletion packages/core/tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"sourceMap": true,
"declarationMap": true
},
"include": ["src"]
"include": ["src"],
"files": ["environment.d.ts"]
}
3 changes: 2 additions & 1 deletion packages/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"include": [
"src",
"test"
]
],
"files": ["environment.d.ts"]
}

0 comments on commit e5bceee

Please sign in to comment.