UNPKG

18 kBSource Map (JSON)View Raw
1{"version":3,"sources":["../../testing/src/controller.ts","../../testing/src/operation.ts","../../testing/src/backend.ts","../../testing/src/module.ts"],"names":["isApolloError","err","hasOwnProperty","TestOperation","operation","observer","this","prototype","flush","result","error","next","complete","flushData","data","networkError","apolloError","ApolloError","graphqlErrors","errors","ApolloTestingBackend","open","handle","op","_this","LinkObservable","testOp","push","_match","match","filter","operationName","isDocumentNode","print","query","matchOp","variables","JSON","stringify","extensions","sameName","compare","sameVariables","sameQuery","sameExtensions","expected","value","val","received","results","forEach","index","indexOf","splice","expectOne","description","descriptionFromMatcher","matches","length","Error","expectNone","verify","operations","map","join","docOrOp","matcher","name","Injectable","APOLLO_TESTING_CACHE","InjectionToken","APOLLO_TESTING_NAMED_CACHE","APOLLO_TESTING_CLIENTS","apollo","backend","namedClients","cache","namedCaches","createOptions","c","link","ApolloLink","clientName","addClient","InMemoryCache","addTypename","create","caches","createNamed","NgModule","args","providers","provide","ApolloTestingController","useExisting","Apollo","Optional","type","Inject","ApolloCache","decorators","ApolloTestingModule","withClients","names","ngModule","ApolloTestingModuleCore","useValue","imports"],"mappings":"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","sourcesContent":["import {DocumentNode} from 'graphql';\n\nimport {TestOperation, Operation} from './operation';\n\nexport type MatchOperationFn = (op: Operation) => boolean;\nexport type MatchOperation =\n | string\n | DocumentNode\n | Operation\n | MatchOperationFn;\n\n/**\n * Controller to be injected into tests, that allows for mocking and flushing\n * of operations.\n *\n *\n */\nexport abstract class ApolloTestingController {\n /**\n * Search for operations that match the given parameter, without any expectations.\n */\n public abstract match(match: MatchOperation): TestOperation[];\n\n /**\n * Expect that a single has been made which matches the given URL, and return its\n * mock.\n *\n * If no such has been made, or more than one such has been made, fail with an\n * error message including the given description, if any.\n */\n public abstract expectOne(\n operationName: string,\n description?: string,\n ): TestOperation;\n\n /**\n * Expect that a single has been made which matches the given parameters, and return\n * its mock.\n *\n * If no such has been made, or more than one such has been made, fail with an\n * error message including the given description, if any.\n */\n public abstract expectOne(op: Operation, description?: string): TestOperation;\n\n /**\n * Expect that a single has been made which matches the given predicate function, and\n * return its mock.\n *\n * If no such has been made, or more than one such has been made, fail with an\n * error message including the given description, if any.\n */\n public abstract expectOne(\n matchFn: MatchOperationFn,\n description?: string,\n ): TestOperation;\n\n /**\n * Expect that a single has been made which matches the given condition, and return\n * its mock.\n *\n * If no such has been made, or more than one such has been made, fail with an\n * error message including the given description, if any.\n */\n public abstract expectOne(\n match: MatchOperation,\n description?: string,\n ): TestOperation;\n\n /**\n * Expect that no operations have been made which match the given URL.\n *\n * If a matching has been made, fail with an error message including the given\n * description, if any.\n */\n public abstract expectNone(operationName: string, description?: string): void;\n\n /**\n * Expect that no operations have been made which match the given parameters.\n *\n * If a matching has been made, fail with an error message including the given\n * description, if any.\n */\n public abstract expectNone(op: Operation, description?: string): void;\n\n /**\n * Expect that no operations have been made which match the given predicate function.\n *\n * If a matching has been made, fail with an error message including the given\n * description, if any.\n */\n public abstract expectNone(\n matchFn: MatchOperationFn,\n description?: string,\n ): void;\n\n /**\n * Expect that no operations have been made which match the given condition.\n *\n * If a matching has been made, fail with an error message including the given\n * description, if any.\n */\n public abstract expectNone(match: MatchOperation, description?: string): void;\n\n /**\n * Verify that no unmatched operations are outstanding.\n *\n * If any operations are outstanding, fail with an error message indicating which operations were not\n * handled.\n */\n public abstract verify(): void;\n}\n","import {\n ApolloError,\n Operation as LinkOperation,\n FetchResult,\n} from '@apollo/client/core';\nimport {GraphQLError, ExecutionResult} from 'graphql';\nimport {Observer} from 'rxjs';\n\nconst isApolloError = (err: any): err is ApolloError =>\n err && err.hasOwnProperty('graphQLErrors');\n\nexport type Operation = LinkOperation & {\n clientName: string;\n};\n\nexport class TestOperation<T = {[key: string]: any}> {\n constructor(\n public operation: Operation,\n private observer: Observer<FetchResult<T>>,\n ) {}\n\n public flush(result: ExecutionResult | ApolloError): void {\n if (isApolloError(result)) {\n this.observer.error(result);\n } else {\n this.observer.next(result as FetchResult<T>);\n this.observer.complete();\n }\n }\n\n public flushData(data: {[key: string]: any} | null): void {\n this.flush({\n data,\n });\n }\n\n public networkError(error: Error): void {\n const apolloError = new ApolloError({\n networkError: error,\n });\n\n this.flush(apolloError);\n }\n\n public graphqlErrors(errors: GraphQLError[]): void {\n this.flush({\n errors,\n });\n }\n}\n","import {Injectable} from '@angular/core';\nimport {Observer} from 'rxjs';\nimport {FetchResult, Observable as LinkObservable} from '@apollo/client/core';\nimport {print, DocumentNode} from 'graphql';\n\nimport {ApolloTestingController, MatchOperation} from './controller';\nimport {TestOperation, Operation} from './operation';\n\n/**\n * A testing backend for `Apollo`.\n *\n * `ApolloTestingBackend` works by keeping a list of all open operations.\n * As operations come in, they're added to the list. Users can assert that specific\n * operations were made and then flush them. In the end, a verify() method asserts\n * that no unexpected operations were made.\n */\n@Injectable()\nexport class ApolloTestingBackend implements ApolloTestingController {\n /**\n * List of pending operations which have not yet been expected.\n */\n private open: TestOperation[] = [];\n\n /**\n * Handle an incoming operation by queueing it in the list of open operations.\n */\n public handle(op: Operation): LinkObservable<FetchResult> {\n return new LinkObservable((observer: Observer<any>) => {\n const testOp = new TestOperation(op, observer);\n this.open.push(testOp);\n });\n }\n\n /**\n * Helper function to search for operations in the list of open operations.\n */\n private _match(match: MatchOperation): TestOperation[] {\n if (typeof match === 'string') {\n return this.open.filter(\n (testOp) => testOp.operation.operationName === match,\n );\n } else if (typeof match === 'function') {\n return this.open.filter((testOp) => match(testOp.operation));\n } else {\n if (this.isDocumentNode(match)) {\n return this.open.filter(\n (testOp) => print(testOp.operation.query) === print(match),\n );\n }\n\n return this.open.filter((testOp) => this.matchOp(match, testOp));\n }\n }\n\n private matchOp(match: Operation, testOp: TestOperation): boolean {\n const variables = JSON.stringify(match.variables);\n const extensions = JSON.stringify(match.extensions);\n\n const sameName = this.compare(\n match.operationName,\n testOp.operation.operationName,\n );\n const sameVariables = this.compare(variables, testOp.operation.variables);\n\n const sameQuery = print(testOp.operation.query) === print(match.query);\n\n const sameExtensions = this.compare(\n extensions,\n testOp.operation.extensions,\n );\n\n return sameName && sameVariables && sameQuery && sameExtensions;\n }\n\n private compare(expected?: string, value?: Object | string): boolean {\n const prepare = (val: any) =>\n typeof val === 'string' ? val : JSON.stringify(val);\n const received = prepare(value);\n\n return !expected || received === expected;\n }\n\n /**\n * Search for operations in the list of open operations, and return all that match\n * without asserting anything about the number of matches.\n */\n public match(match: MatchOperation): TestOperation[] {\n const results = this._match(match);\n\n results.forEach((result) => {\n const index = this.open.indexOf(result);\n if (index !== -1) {\n this.open.splice(index, 1);\n }\n });\n return results;\n }\n\n /**\n * Expect that a single outstanding request matches the given matcher, and return\n * it.\n *\n * operations returned through this API will no longer be in the list of open operations,\n * and thus will not match twice.\n */\n public expectOne(match: MatchOperation, description?: string): TestOperation {\n description = description || this.descriptionFromMatcher(match);\n const matches = this.match(match);\n if (matches.length > 1) {\n throw new Error(\n `Expected one matching operation for criteria \"${description}\", found ${matches.length} operations.`,\n );\n }\n if (matches.length === 0) {\n throw new Error(\n `Expected one matching operation for criteria \"${description}\", found none.`,\n );\n }\n return matches[0];\n }\n\n /**\n * Expect that no outstanding operations match the given matcher, and throw an error\n * if any do.\n */\n public expectNone(match: MatchOperation, description?: string): void {\n description = description || this.descriptionFromMatcher(match);\n const matches = this.match(match);\n if (matches.length > 0) {\n throw new Error(\n `Expected zero matching operations for criteria \"${description}\", found ${matches.length}.`,\n );\n }\n }\n\n /**\n * Validate that there are no outstanding operations.\n */\n public verify(): void {\n const open = this.open;\n\n if (open.length > 0) {\n // Show the methods and URLs of open operations in the error, for convenience.\n const operations = open\n .map((testOp) => testOp.operation.operationName)\n .join(', ');\n throw new Error(\n `Expected no open operations, found ${open.length}: ${operations}`,\n );\n }\n }\n\n private isDocumentNode(\n docOrOp: DocumentNode | Operation,\n ): docOrOp is DocumentNode {\n return !(docOrOp as Operation).operationName;\n }\n\n private descriptionFromMatcher(matcher: MatchOperation): string {\n if (typeof matcher === 'string') {\n return `Match operationName: ${matcher}`;\n } else if (typeof matcher === 'object') {\n if (this.isDocumentNode(matcher)) {\n return `Match DocumentNode`;\n }\n\n const name = matcher.operationName || '(any)';\n const variables = JSON.stringify(matcher.variables) || '(any)';\n\n return `Match operation: ${name}, variables: ${variables}`;\n } else {\n return `Match by function: ${matcher.name}`;\n }\n }\n}\n","import {Apollo} from 'apollo-angular';\nimport {\n ApolloLink,\n Operation as LinkOperation,\n InMemoryCache,\n ApolloCache,\n} from '@apollo/client/core';\nimport {NgModule, InjectionToken, Inject, Optional} from '@angular/core';\n\nimport {ApolloTestingController} from './controller';\nimport {ApolloTestingBackend} from './backend';\nimport {Operation} from './operation';\n\nexport type NamedCaches = Record<string, ApolloCache<any> | undefined | null>;\n\nexport const APOLLO_TESTING_CACHE = new InjectionToken<ApolloCache<any>>(\n 'apollo-angular/testing cache',\n);\n\nexport const APOLLO_TESTING_NAMED_CACHE = new InjectionToken<NamedCaches>(\n 'apollo-angular/testing named cache',\n);\n\nexport const APOLLO_TESTING_CLIENTS = new InjectionToken<string[]>(\n 'apollo-angular/testing named clients',\n);\n\nfunction addClient(name: string, op: LinkOperation): Operation {\n (op as Operation).clientName = name;\n\n return op as Operation;\n}\n\n@NgModule({\n providers: [\n ApolloTestingBackend,\n {provide: ApolloTestingController, useExisting: ApolloTestingBackend},\n ],\n})\nexport class ApolloTestingModuleCore {\n constructor(\n apollo: Apollo,\n backend: ApolloTestingBackend,\n @Optional()\n @Inject(APOLLO_TESTING_CLIENTS)\n namedClients?: string[],\n @Optional()\n @Inject(APOLLO_TESTING_CACHE)\n cache?: ApolloCache<any>,\n @Optional()\n @Inject(APOLLO_TESTING_NAMED_CACHE)\n namedCaches?: any, // FIX: using NamedCaches here makes ngc fail\n ) {\n function createOptions(name: string, c?: ApolloCache<any> | null) {\n return {\n link: new ApolloLink((operation) =>\n backend.handle(addClient(name, operation)),\n ),\n cache:\n c ||\n new InMemoryCache({\n addTypename: false,\n }),\n };\n }\n\n apollo.create(createOptions('default', cache));\n\n if (namedClients && namedClients.length) {\n namedClients.forEach((name) => {\n const caches =\n namedCaches && typeof namedCaches === 'object' ? namedCaches : {};\n\n apollo.createNamed(name, createOptions(name, caches[name]));\n });\n }\n }\n}\n\n@NgModule({\n imports: [ApolloTestingModuleCore],\n})\nexport class ApolloTestingModule {\n static withClients(names: string[]) {\n return {\n ngModule: ApolloTestingModuleCore,\n providers: [\n {\n provide: APOLLO_TESTING_CLIENTS,\n useValue: names,\n },\n ],\n };\n }\n}\n"]}
\No newline at end of file