Skip to content

Commit

Permalink
Setup testing framework vitest (#28)
Browse files Browse the repository at this point in the history
* feat: added vitest harness and initial tests

* feat: added coverage reporting

* feat: add tests to workflow

* chore: readd tsconfig

* chore: changeset

* fix: testing workflow

* chore: cleanup logs
  • Loading branch information
alexlwn123 committed Sep 20, 2024
1 parent 51c326d commit 779e924
Show file tree
Hide file tree
Showing 10 changed files with 1,215 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/itchy-swans-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fedimint/core-web': patch
---

Set up vitest testing framework
22 changes: 22 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,25 @@ jobs:

- name: Check types
run: pnpm typecheck

test:
name: Test
needs: lint
runs-on: ubuntu-latest

steps:
- name: Clone repository
uses: actions/checkout@v4

- name: Install dependencies
uses: ./.github/actions/install-deps

- name: Setup Playwright
run: pnpm exec playwright install

- name: Run Tests
uses: nick-fields/retry@v3
with:
command: pnpm test
max_attempts: 3
timeout_seconds: 180
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@ tsconfig.tsbuildinfo
.env.development.local
.env.test.local
.env.production.local
.envrc
.envrc
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

__screenshots__
15 changes: 14 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,30 @@
"changeset:prepublish": "pnpm run build",
"version": "changeset version",
"typecheck": "pnpm run --r --parallel typecheck",
"coverage": "vitest run --coverage",
"test": "pnpm run test:headless",
"test:coverage": "vitest run --coverage",
"test:headless": "vitest",
"test:ui": "vitest --browser.headless=false --ui",
"format": "prettier --write .",
"watch": "pnpm run --r --parallel --filter \"./packages/**\" watch"
},
"devDependencies": {
"@changesets/cli": "^2.27.7",
"@types/bun": "^1.1.1",
"@types/node": "^20.14.8",
"@vitest/browser": "^2.1.1",
"@vitest/coverage-v8": "^2.1.1",
"@vitest/ui": "^2.1.1",
"glob": "^10.3.12",
"happy-dom": "^15.7.4",
"playwright": "^1.47.1",
"prettier": "^3.3.3",
"sherif": "^0.8.4",
"simple-git-hooks": "^2.11.1",
"typescript": "5.5.2"
"typescript": "5.5.2",
"vite-plugin-wasm": "^3.3.0",
"vitest": "^2.1.1"
},
"packageManager": "pnpm@9.4.0",
"engines": {
Expand Down
76 changes: 76 additions & 0 deletions packages/core-web/src/FedimintWallet.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { test, expect, vi } from 'vitest'
import { FedimintWallet } from './FedimintWallet'
import { beforeAll } from 'vitest'

let randomTestingId: string
let wallet: FedimintWallet
// Testnet
const TESTING_FEDERATION =
'fed11qgqrgvnhwden5te0v9k8q6rp9ekh2arfdeukuet595cr2ttpd3jhq6rzve6zuer9wchxvetyd938gcewvdhk6tcqqysptkuvknc7erjgf4em3zfh90kffqf9srujn6q53d6r056e4apze5cw27h75'

beforeAll(() => {
randomTestingId = Math.random().toString(36).substring(2, 15)
wallet = new FedimintWallet()
expect(wallet).toBeDefined()

// Cleanup after all tests
return async () => {
// clear up browser resources
await wallet.cleanup()
// remove the wallet db
indexedDB.deleteDatabase(randomTestingId)
// swap out the randomTestingId for a new one, to avoid raciness
randomTestingId = Math.random().toString(36).substring(2, 15)
}
})

test('initial open & join', async () => {
expect(wallet).toBeDefined()
expect(wallet.isOpen()).toBe(false)
// On initial open, it should return false
// because no federations have been joined
await expect(wallet.open(randomTestingId)).resolves.toBe(false)
await expect(
wallet.joinFederation(TESTING_FEDERATION, randomTestingId),
).resolves.toBeUndefined()
expect(wallet.isOpen()).toBe(true)
await expect(wallet.waitForOpen()).resolves.toBeUndefined()
})

test('Error on open & join if wallet is already open', async () => {
expect(wallet).toBeDefined()
expect(wallet.isOpen()).toBe(true)

// Test opening an already open wallet
try {
await wallet.open(randomTestingId)
} catch (error) {
expect(error).toBeInstanceOf(Error)
expect((error as Error).message).toBe(
'The FedimintWallet is already open. You can only call `FedimintWallet.open on closed clients.`',
)
}

// Test joining federation on an already open wallet
try {
await wallet.joinFederation(TESTING_FEDERATION, randomTestingId)
} catch (error) {
expect(error).toBeInstanceOf(Error)
expect((error as Error).message).toBe(
'The FedimintWallet is already open. You can only call `FedimintWallet.joinFederation` on closed clients.',
)
}
})
test('getConfig', async () => {
expect(wallet).toBeDefined()
expect(wallet.isOpen()).toBe(true)
const config = await wallet.getConfig()
expect(config).toBeDefined()
})

test('empty getBalance', async () => {
expect(wallet).toBeDefined()
expect(wallet.isOpen()).toBe(true)
await expect(wallet.waitForOpen()).resolves.toBeUndefined()
await expect(wallet.getBalance()).resolves.toEqual(0)
})
24 changes: 16 additions & 8 deletions packages/core-web/src/FedimintWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const DEFAULT_CLIENT_NAME = 'fm-default' as const
export class FedimintWallet {
private worker: Worker | null = null
private initPromise: Promise<void> | null = null
private openPromise: Promise<void>
private openPromise: Promise<void> | null = null
private resolveOpen: () => void = () => {}
private _isOpen: boolean = false
private requestCounter: number = 0
Expand All @@ -33,7 +33,7 @@ export class FedimintWallet {
}

async waitForOpen() {
if (this._isOpen) return
if (this._isOpen) return Promise.resolve()
return this.openPromise
}

Expand Down Expand Up @@ -62,8 +62,11 @@ export class FedimintWallet {
// Setup
initialize() {
if (this.initPromise) return this.initPromise
this.worker = new Worker(new URL('./worker.js', import.meta.url))
this.worker = new Worker(new URL('worker.js?worker', import.meta.url), {
type: 'module',
})
this.worker.onmessage = this.handleWorkerMessage.bind(this)
// TODO: HANDLE RETURNED INIT
this.initPromise = this.sendSingleMessage('init')
return this.initPromise
}
Expand Down Expand Up @@ -100,13 +103,16 @@ export class FedimintWallet {
// TODO: Determine if this should be safe or throw
if (this._isOpen)
throw new Error(
'Failed to Join Federation. You have already joined a federation, and you can only join one federation per wallet.',
'The FedimintWallet is already open. You can only call `FedimintWallet.joinFederation` on closed clients.',
)
const response = await this.sendSingleMessage('join', {
inviteCode,
clientName,
})
if (response.success) this._isOpen = true
if (response.success) {
this._isOpen = true
this.resolveOpen()
}
}

/**
Expand Down Expand Up @@ -223,7 +229,7 @@ export class FedimintWallet {
})
}

private async _rpcSingle<Response extends JSONValue = JSONValue>(
private _rpcSingle<Response extends JSONValue = JSONValue>(
module: ModuleKind,
method: string,
body: JSONValue,
Expand Down Expand Up @@ -271,7 +277,7 @@ export class FedimintWallet {
'mint',
'subscribe_reissue_external_notes',
{ operation_id: operationId },
(res) => onSuccess(res),
onSuccess,
onError,
)

Expand Down Expand Up @@ -333,8 +339,10 @@ export class FedimintWallet {
async cleanup() {
this.worker?.terminate()
this.worker = null
this.openPromise = Promise.resolve()
this.openPromise = null
this.initPromise = null
this.requestCallbacks.clear()
this._isOpen = false
}

isOpen() {
Expand Down
5 changes: 5 additions & 0 deletions packages/core-web/src/worker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// Web Worker for fedimint-client-wasm to run in the browser

// HACK: Fixes vitest browser runner
globalThis.__vitest_browser_runner__ = { wrapDynamicImport: (foo) => foo() }

let WasmClient = null
let client = null

Expand Down Expand Up @@ -76,3 +79,5 @@ self.onmessage = async (event) => {
})
}
}

self.postMessage({ type: 'init', data: {} })
Loading

0 comments on commit 779e924

Please sign in to comment.