import { fold, isFailure, isInitial, isPending, isSuccess, RemoteData, } from '@devexperts/remote-data-ts' import { Eq } from 'fp-ts/lib/Eq' import { pipe } from 'fp-ts/lib/pipeable' declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace jest { interface Matchers { toBeRemoteInitial: T extends RemoteData ? () => T : never toBeRemotePending: T extends RemoteData ? () => T : never toBeRemoteFailure: T extends RemoteData ? () => T : never toBeRemoteSuccess: T extends RemoteData ? () => T : never toEqualRemoteFailure: T extends RemoteData ? (equalTo: E, eq?: Eq) => T : never toEqualRemoteSuccess: T extends RemoteData ? (equalTo: A, eq?: Eq) => T : never } } } const result = (pass: boolean, received: unknown, expected: string) => ({ pass, message: () => `expected ${received} ${pass ? 'not ' : ''}to be ${expected}`, }) expect.extend({ toBeRemoteInitial: (received: RemoteData) => result(isInitial(received), received, 'a RemoteInitial'), toBeRemotePending: (received: RemoteData) => result(isPending(received), received, 'a RemotePending'), toBeRemoteFailure: (received: RemoteData) => result(isFailure(received), received, 'a RemoteFailure'), toBeRemoteSuccess: (received: RemoteData) => result(isSuccess(received), received, 'a RemoteSuccess'), toEqualRemoteFailure( this: jest.MatcherUtils, received: RemoteData, equalTo: E, eq: Eq = this, ) { const fail = result(false, received, 'a RemoteFailure') return pipe( received, fold( () => fail, () => fail, e => ({ pass: eq.equals(e, equalTo), message: () => `RemoteFailure value mismatch\n${this.utils.diff(equalTo, e)}`, }), () => fail, ), ) }, toEqualRemoteSuccess( this: jest.MatcherUtils, received: RemoteData, equalTo: A, eq: Eq = this, ) { const fail = result(false, received, 'a RemoteSuccess') return pipe( received, fold( () => fail, () => fail, () => fail, e => ({ pass: eq.equals(e, equalTo), message: () => `RemoteSuccess value mismatch\n${this.utils.diff(equalTo, e)}`, }), ), ) }, })