@dhau/msw-builders@0.0.35Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
Built and signed on GitHub Actions
Some extra utilities to write MSW GraphQL and rest handlers.
This package works with Node.js, BrowsersIt is unknown whether this package works with Cloudflare Workers, Deno, Bun
JSR Score
76%
Published
3 months ago (0.0.35)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198// Waiting to find new API for graphql variables. Then can remove this. /* eslint-disable @typescript-eslint/no-explicit-any */ import { graphql, GraphQLHandler, HttpResponse, type DefaultBodyType, type GraphQLRequestHandler, type GraphQLVariables, type RequestHandlerOptions, } from "npm:msw@^2.0.4"; import isEqual from "npm:lodash-es@^4.17.21/isEqual.js"; import partial from "npm:lodash-es@^4.17.21/partial.js"; import { diff } from "npm:jest-diff@^29.3.1"; import { GraphQLError } from "npm:graphql@^16.6.0"; import { consoleDebugLog, nullLogger } from "./debug.ts"; type BuilderHandlerOptions = { readonly onCalled?: () => void; }; type HandlerOptions = RequestHandlerOptions & BuilderHandlerOptions; type Options = { readonly url: string; readonly debug?: boolean; readonly defaultRequestHandlerOptions?: RequestHandlerOptions; }; function matchMessage<Variables extends GraphQLVariables = GraphQLVariables>( type: string, name: string, expected: Variables, actual: Variables, ) { const difference = diff(expected, actual); return `${type} ${name} variables differ\n${difference ?? ""}`; } // Copied from msw - can't find how to import it type GraphQLResponseBody<BodyType extends DefaultBodyType> = | { data?: BodyType | null; errors?: readonly Partial<GraphQLError>[] | null; } | null | undefined; type ResultProvider<TQuery extends DefaultBodyType, TVariables> = | GraphQLResponseBody<TQuery> | ((variables: TVariables) => GraphQLResponseBody<TQuery>); type GraphQlHandlersFactory = { mutation: < Query extends Record<string, unknown>, Variables extends GraphQLVariables = GraphQLVariables, >( operationName: Parameters<GraphQLRequestHandler>[0], expectedVariables: Variables, resultProvider: ResultProvider<Query, Variables>, options?: HandlerOptions, ) => GraphQLHandler; operation: < Query extends Record<string, unknown>, Variables extends GraphQLVariables = GraphQLVariables, >( expectedVariables: Variables, resultProvider: ResultProvider<Query, Variables>, options?: HandlerOptions, ) => GraphQLHandler; query: < Query extends Record<string, unknown>, Variables extends GraphQLVariables = GraphQLVariables, >( operationName: Parameters<GraphQLRequestHandler>[0], expectedVariables: Variables, resultProvider: ResultProvider<Query, Variables>, options?: HandlerOptions, ) => GraphQLHandler; }; function createGraphQlHandlersFactory({ url, debug, defaultRequestHandlerOptions, }: Options): GraphQlHandlersFactory { const link = graphql.link(url); const debugLog = debug ? partial(consoleDebugLog, url) : nullLogger; return { mutation: < Query extends Record<string, unknown>, Variables extends GraphQLVariables = GraphQLVariables, >( operationName: Parameters<GraphQLRequestHandler>[0], expectedVariables: Variables, resultProvider: ResultProvider<Query, Variables>, options?: HandlerOptions, ) => { const { onCalled, ...rest } = { ...defaultRequestHandlerOptions, ...options, }; return link.mutation<Query, Variables>( operationName, ({ variables }) => { // TODO: Update variables. Not sure how to operationName them in new msw version if (!isEqual(expectedVariables, variables)) { debugLog( matchMessage( "mutation", String(operationName), expectedVariables, variables, ), ); return undefined; } onCalled?.(); const responseBody = typeof resultProvider === "function" ? resultProvider(variables) : resultProvider; return HttpResponse.json(responseBody); }, rest, ); }, operation: < Query extends Record<string, unknown>, Variables extends GraphQLVariables = GraphQLVariables, >( expectedVariables: Variables, resultProvider: ResultProvider<Query, Variables>, options?: BuilderHandlerOptions, ) => { const { onCalled } = options ?? {}; return link.operation<Query, Variables>(({ variables }) => { if (!isEqual(expectedVariables, variables)) { debugLog( matchMessage( "operation", "(anonymous)", expectedVariables, variables, ), ); return undefined; } onCalled?.(); const responseBody = typeof resultProvider === "function" ? resultProvider(variables) : resultProvider; return HttpResponse.json(responseBody); }); }, query: < Query extends Record<string, unknown>, Variables extends GraphQLVariables = GraphQLVariables, >( operationName: Parameters<GraphQLRequestHandler>[0], expectedVariables: Variables, resultProvider: ResultProvider<Query, Variables>, options?: HandlerOptions, ) => { const { onCalled, ...rest } = { ...defaultRequestHandlerOptions, ...options, }; return link.query<Query, Variables>( operationName, ({ variables }) => { if (!isEqual(expectedVariables, variables)) { debugLog( matchMessage( "query", String(operationName), expectedVariables, variables, ), ); return undefined; } onCalled?.(); const responseBody = typeof resultProvider === "function" ? resultProvider(variables) : resultProvider; return HttpResponse.json(responseBody); }, rest, ); }, }; } export type { GraphQlHandlersFactory }; export { createGraphQlHandlersFactory };