Skip to content

Commit

Permalink
test(sanity): add toMatchEmissions matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
juice49 committed Feb 5, 2025
1 parent e3287f8 commit 7c02363
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 74 deletions.
1 change: 1 addition & 0 deletions packages/sanity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@
"@types/semver": "^6.2.3",
"@types/tar-fs": "^2.0.1",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/expect": "^3.0.5",
"@vvo/tzdb": "6.137.0",
"babel-plugin-react-compiler": "19.0.0-beta-714736e-20250131",
"blob-polyfill": "^9.0.20240710",
Expand Down
49 changes: 49 additions & 0 deletions packages/sanity/test/matchers/toMatchEmissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {type AsyncExpectationResult, type MatcherState} from '@vitest/expect'
import {firstValueFrom, type OperatorFunction, Subject, toArray} from 'rxjs'

export const NO_EMISSION = Symbol('NO_EMISSION')

type Snapshot<A, B> = [A, B | typeof NO_EMISSION]

interface OperatorFunctionMatchers<Type = unknown> {
/**
* Ensure each entry in the provided array results in the expected value being emitted when piped
* to the observable.
*/
toMatchEmissions: Type extends () => OperatorFunction<infer A, infer B>
? (snapshots: Snapshot<A, B>[]) => Promise<Type>
: never
}

declare module 'vitest' {
interface Assertion<T = any> extends OperatorFunctionMatchers<T> {}
interface AsymmetricMatchersContaining extends OperatorFunctionMatchers {}
}

export async function toMatchEmissions(
this: MatcherState,
createOperator: () => OperatorFunction<unknown, unknown>,
snapshots: [A: unknown, B: unknown][],
): AsyncExpectationResult {
const {equals} = this
const input$ = new Subject()

const expectedEmissions = snapshots
.filter(([, expectedEmission]) => expectedEmission !== NO_EMISSION)
.map(([, expectedEmission]) => expectedEmission)

const emissions$ = input$.pipe(createOperator(), toArray())
const emissions = firstValueFrom(emissions$)

snapshots.forEach(([value]) => input$.next(value))
input$.complete()

const actualEmissions = await emissions

return {
pass: equals(actualEmissions, expectedEmissions),
message: () => 'Observable emissions did not match',
actual: actualEmissions,
expected: expectedEmissions,
}
}
8 changes: 7 additions & 1 deletion packages/sanity/test/setup/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import './clipboardItemPolyfill'
import '@testing-library/jest-dom/vitest'

import {cleanup} from '@testing-library/react'
import {afterEach, beforeEach, vi} from 'vitest'
import {afterEach, beforeEach, expect, vi} from 'vitest'

import {toMatchEmissions} from '../matchers/toMatchEmissions'

expect.extend({
toMatchEmissions,
})

afterEach(() => cleanup())

Expand Down
Loading

0 comments on commit 7c02363

Please sign in to comment.