UNPKG

@tevm/test-matchers

Version:

Vite test matchers for Tevm or EVM-related testing in TypeScript.

248 lines (209 loc) 9.85 kB
import type { Assertion } from 'vitest' import { describe, expectTypeOf, it } from 'vitest' import { toBeAddress, toBeHex } from '../matchers/utils/index.js' import { createChainableFromVitest } from './chainable.js' import { type CustomMatchers, testMatchers } from './chainable.spec.js' import type { ChainableAssertion, ChainState, InferredVitestChainableResult, MatcherResult, VitestMatcherConfig, VitestMatcherFunction, } from './types.js' // Import existing chainable matchers from spec const { toBeBigIntChainable, toBeHexChainable, toBeAddressChainable, toPassDownStateChainable, toUsePreviousStateAndBigIntChainable, toResolveToStringChainable, } = testMatchers // Remove the separate asyncMatcher and asyncChainable - use the shared one describe('chainable type system (exhaustive)', () => { it('type: basic configuration inference', () => { // Test real matcher config inference expectTypeOf<typeof toBeBigIntChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toBeBigIntChainable', unknown, false, unknown>> >() expectTypeOf<typeof toBeHexChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toBeHexChainable', unknown, false, unknown>> >() expectTypeOf<typeof toBeAddressChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toBeAddressChainable', unknown, false, unknown>> >() expectTypeOf<typeof toResolveToStringChainable>().toExtend< InferredVitestChainableResult< VitestMatcherConfig<'toResolveToStringChainable', Promise<string>, true, { resolved: boolean }> > >() // Name should be inferred correctly expectTypeOf<typeof toBeBigIntChainable.name>().toEqualTypeOf<'toBeBigIntChainable'>() expectTypeOf<typeof toBeHexChainable.name>().toEqualTypeOf<'toBeHexChainable'>() expectTypeOf<typeof toBeAddressChainable.name>().toEqualTypeOf<'toBeAddressChainable'>() expectTypeOf<typeof toResolveToStringChainable.name>().toEqualTypeOf<'toResolveToStringChainable'>() }) it('type: isAsync flag inference', () => { // Sync matchers should have isAsync: false expectTypeOf<typeof toBeBigIntChainable.isAsync>().toEqualTypeOf<false>() expectTypeOf<typeof toBeHexChainable.isAsync>().toEqualTypeOf<false>() expectTypeOf<typeof toBeAddressChainable.isAsync>().toEqualTypeOf<false>() // Async matcher should have isAsync: true expectTypeOf<typeof toResolveToStringChainable.isAsync>().toEqualTypeOf<true>() }) it('type: method function parameter inference', () => { // Test that method functions exist and are functions expectTypeOf<typeof toBeBigIntChainable.methodFunction>().toBeFunction() expectTypeOf<typeof toBeHexChainable.methodFunction>().toBeFunction() expectTypeOf<typeof toPassDownStateChainable.methodFunction>().toBeFunction() expectTypeOf<typeof toResolveToStringChainable.methodFunction>().toBeFunction() }) it('type: return type inference (sync vs async)', () => { // Sync matchers return Assertion expectTypeOf<ReturnType<typeof toBeBigIntChainable.methodFunction>>().toEqualTypeOf<Assertion>() expectTypeOf<ReturnType<typeof toBeHexChainable.methodFunction>>().toEqualTypeOf<Assertion>() expectTypeOf<ReturnType<typeof toPassDownStateChainable.methodFunction>>().toEqualTypeOf<Assertion>() // Async matchers return ChainableAssertion expectTypeOf<ReturnType<typeof toResolveToStringChainable.methodFunction>>().toExtend<ChainableAssertion>() }) it('type: chain function consistency', () => { // All chain functions should have the same signature expectTypeOf<typeof toBeBigIntChainable.chainFunction>().toBeFunction() expectTypeOf<typeof toBeHexChainable.chainFunction>().toBeFunction() expectTypeOf<typeof toPassDownStateChainable.chainFunction>().toBeFunction() expectTypeOf<typeof toResolveToStringChainable.chainFunction>().toBeFunction() }) it('type: vitest matcher function types', () => { // Test that vitest matcher types are properly structured expectTypeOf<VitestMatcherFunction<unknown, false, unknown>>().toBeFunction() expectTypeOf<VitestMatcherFunction<Promise<string>, true, { resolved: boolean }>>().toBeFunction() // Test specific return type structure expectTypeOf<MatcherResult<{ resolved: boolean }>>().toEqualTypeOf<{ pass: boolean message: () => string actual?: unknown expected?: unknown state?: { resolved: boolean } }>() }) it('type: chain state structure', () => { // Test ChainState type structure with real state types type TestState = { a: unknown; b: unknown; originalValue: unknown } expectTypeOf<ChainState<bigint, TestState>>().toEqualTypeOf<{ chainedFrom: string | undefined previousPassed: boolean | undefined previousValue: bigint | undefined previousState: TestState | undefined previousArgs: readonly unknown[] | undefined }>() // Test that ChainState can be used with different types expectTypeOf<ChainState<string, { resolved: boolean }>>().toEqualTypeOf<{ chainedFrom: string | undefined previousPassed: boolean | undefined previousValue: string | undefined previousState: { resolved: boolean } | undefined previousArgs: readonly unknown[] | undefined }>() }) it('type: real world matcher inference', () => { // Test that real matchers are properly typed expectTypeOf<typeof toBeBigIntChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toBeBigIntChainable', unknown, false, unknown>> >() expectTypeOf<typeof toBeHexChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toBeHexChainable', unknown, false, unknown>> >() expectTypeOf<typeof toBeAddressChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toBeAddressChainable', unknown, false, unknown>> >() expectTypeOf<typeof toResolveToStringChainable>().toExtend< InferredVitestChainableResult< VitestMatcherConfig<'toResolveToStringChainable', Promise<string>, true, { resolved: boolean }> > >() }) it('type: state-aware matchers', () => { // Test state passing matchers from spec expectTypeOf<typeof toPassDownStateChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toPassDownStateChainable', unknown, false, any>> >() expectTypeOf<typeof toUsePreviousStateAndBigIntChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'toUsePreviousStateAndBigIntChainable', unknown, false, any>> >() }) it('type: utility types exist and work', () => { // Test that ChainState is properly generic and has the right properties expectTypeOf<ChainState<string, { resolved: boolean }>>().toHaveProperty('previousValue') expectTypeOf<ChainState<string, { resolved: boolean }>>().toHaveProperty('previousState') expectTypeOf<ChainState<string, { resolved: boolean }>>().toHaveProperty('chainedFrom') }) it('type: custom matchers interface', () => { // Test that CustomMatchers interface is properly defined expectTypeOf<CustomMatchers>().toHaveProperty('toBeBigIntChainable') expectTypeOf<CustomMatchers>().toHaveProperty('toBeHexChainable') expectTypeOf<CustomMatchers>().toHaveProperty('toBeAddressChainable') expectTypeOf<CustomMatchers>().toHaveProperty('toPassDownStateChainable') expectTypeOf<CustomMatchers>().toHaveProperty('toUsePreviousStateAndBigIntChainable') expectTypeOf<CustomMatchers>().toHaveProperty('toResolveToStringChainable') }) it('type: negative test cases (should not compile)', () => { // These test cases document what should NOT work // @ts-expect-error - cannot use wrong received type const wrongReceived: VitestMatcherFunction<number, false> = (_received: string) => ({ pass: true, message: () => '', }) // @ts-expect-error - cannot use wrong async flag const wrongAsync: VitestMatcherFunction<number, false> = async (_received: number) => ({ pass: true, message: () => '', }) // @ts-expect-error - async matcher must return Promise const asyncWithoutPromise: VitestMatcherFunction<number, true> = (_received: number) => ({ pass: true, message: () => '', }) // Suppress unused variable warnings void wrongReceived void wrongAsync void asyncWithoutPromise }) it('type: conditional return types based on TAsync', () => { // Test that conditional types work correctly type SyncResult = VitestMatcherFunction<unknown, false, unknown> extends VitestMatcherFunction<any, true, any> ? ChainableAssertion : Assertion type AsyncResult = VitestMatcherFunction< Promise<string>, true, { resolved: boolean } > extends VitestMatcherFunction<any, true, any> ? ChainableAssertion : Assertion expectTypeOf<SyncResult>().toEqualTypeOf<Assertion>() expectTypeOf<AsyncResult>().toEqualTypeOf<ChainableAssertion>() }) it('type: createChainableFromVitest function signature', () => { // Test that the creation function itself is properly typed expectTypeOf<typeof createChainableFromVitest>().toBeFunction() // Test that it can accept proper configs with real matchers expectTypeOf<VitestMatcherConfig<'toBeBigInt', unknown, false, unknown>>().toEqualTypeOf<{ readonly name: 'toBeBigInt' readonly vitestMatcher: VitestMatcherFunction<unknown, false, unknown> }>() }) it('type: real matcher functions from utils', () => { // Test that the original vitest matchers are properly typed expectTypeOf<typeof toBeHex>().toBeFunction() expectTypeOf<typeof toBeAddress>().toBeFunction() // Test that they can be used to create chainable matchers const testChainable = createChainableFromVitest({ name: 'testMatcher' as const, vitestMatcher: toBeHex, }) expectTypeOf<typeof testChainable>().toEqualTypeOf< InferredVitestChainableResult<VitestMatcherConfig<'testMatcher', unknown, false, unknown>> >() }) })