UNPKG

11.5 kBJavaScriptView Raw
1import * as i1 from 'apollo-angular';
2import { ApolloModule } from 'apollo-angular';
3import * as i3 from '@apollo/client/core';
4import { ApolloError, Observable, ApolloLink, InMemoryCache } from '@apollo/client/core';
5import * as i0 from '@angular/core';
6import { Injectable, InjectionToken, NgModule, Optional, Inject } from '@angular/core';
7import { print } from 'graphql';
8
9/**
10 * Controller to be injected into tests, that allows for mocking and flushing
11 * of operations.
12 *
13 *
14 */
15class ApolloTestingController {
16}
17
18const isApolloError = (err) => err && err.hasOwnProperty('graphQLErrors');
19class TestOperation {
20 constructor(operation, observer) {
21 this.operation = operation;
22 this.observer = observer;
23 }
24 flush(result) {
25 if (isApolloError(result)) {
26 this.observer.error(result);
27 }
28 else {
29 const fetchResult = result ? Object.assign({}, result) : result;
30 this.observer.next(fetchResult);
31 this.observer.complete();
32 }
33 }
34 flushData(data) {
35 this.flush({
36 data,
37 });
38 }
39 networkError(error) {
40 const apolloError = new ApolloError({
41 networkError: error,
42 });
43 this.flush(apolloError);
44 }
45 graphqlErrors(errors) {
46 this.flush({
47 errors,
48 });
49 }
50}
51
52/**
53 * A testing backend for `Apollo`.
54 *
55 * `ApolloTestingBackend` works by keeping a list of all open operations.
56 * As operations come in, they're added to the list. Users can assert that specific
57 * operations were made and then flush them. In the end, a verify() method asserts
58 * that no unexpected operations were made.
59 */
60class ApolloTestingBackend {
61 constructor() {
62 /**
63 * List of pending operations which have not yet been expected.
64 */
65 this.open = [];
66 }
67 /**
68 * Handle an incoming operation by queueing it in the list of open operations.
69 */
70 handle(op) {
71 return new Observable((observer) => {
72 const testOp = new TestOperation(op, observer);
73 this.open.push(testOp);
74 });
75 }
76 /**
77 * Helper function to search for operations in the list of open operations.
78 */
79 _match(match) {
80 if (typeof match === 'string') {
81 return this.open.filter((testOp) => testOp.operation.operationName === match);
82 }
83 else if (typeof match === 'function') {
84 return this.open.filter((testOp) => match(testOp.operation));
85 }
86 else {
87 if (this.isDocumentNode(match)) {
88 return this.open.filter((testOp) => print(testOp.operation.query) === print(match));
89 }
90 return this.open.filter((testOp) => this.matchOp(match, testOp));
91 }
92 }
93 matchOp(match, testOp) {
94 const variables = JSON.stringify(match.variables);
95 const extensions = JSON.stringify(match.extensions);
96 const sameName = this.compare(match.operationName, testOp.operation.operationName);
97 const sameVariables = this.compare(variables, testOp.operation.variables);
98 const sameQuery = print(testOp.operation.query) === print(match.query);
99 const sameExtensions = this.compare(extensions, testOp.operation.extensions);
100 return sameName && sameVariables && sameQuery && sameExtensions;
101 }
102 compare(expected, value) {
103 const prepare = (val) => typeof val === 'string' ? val : JSON.stringify(val);
104 const received = prepare(value);
105 return !expected || received === expected;
106 }
107 /**
108 * Search for operations in the list of open operations, and return all that match
109 * without asserting anything about the number of matches.
110 */
111 match(match) {
112 const results = this._match(match);
113 results.forEach((result) => {
114 const index = this.open.indexOf(result);
115 if (index !== -1) {
116 this.open.splice(index, 1);
117 }
118 });
119 return results;
120 }
121 /**
122 * Expect that a single outstanding request matches the given matcher, and return
123 * it.
124 *
125 * operations returned through this API will no longer be in the list of open operations,
126 * and thus will not match twice.
127 */
128 expectOne(match, description) {
129 description = description || this.descriptionFromMatcher(match);
130 const matches = this.match(match);
131 if (matches.length > 1) {
132 throw new Error(`Expected one matching operation for criteria "${description}", found ${matches.length} operations.`);
133 }
134 if (matches.length === 0) {
135 throw new Error(`Expected one matching operation for criteria "${description}", found none.`);
136 }
137 return matches[0];
138 }
139 /**
140 * Expect that no outstanding operations match the given matcher, and throw an error
141 * if any do.
142 */
143 expectNone(match, description) {
144 description = description || this.descriptionFromMatcher(match);
145 const matches = this.match(match);
146 if (matches.length > 0) {
147 throw new Error(`Expected zero matching operations for criteria "${description}", found ${matches.length}.`);
148 }
149 }
150 /**
151 * Validate that there are no outstanding operations.
152 */
153 verify() {
154 const open = this.open;
155 if (open.length > 0) {
156 // Show the methods and URLs of open operations in the error, for convenience.
157 const operations = open
158 .map((testOp) => testOp.operation.operationName)
159 .join(', ');
160 throw new Error(`Expected no open operations, found ${open.length}: ${operations}`);
161 }
162 }
163 isDocumentNode(docOrOp) {
164 return !docOrOp.operationName;
165 }
166 descriptionFromMatcher(matcher) {
167 if (typeof matcher === 'string') {
168 return `Match operationName: ${matcher}`;
169 }
170 else if (typeof matcher === 'object') {
171 if (this.isDocumentNode(matcher)) {
172 return `Match DocumentNode`;
173 }
174 const name = matcher.operationName || '(any)';
175 const variables = JSON.stringify(matcher.variables) || '(any)';
176 return `Match operation: ${name}, variables: ${variables}`;
177 }
178 else {
179 return `Match by function: ${matcher.name}`;
180 }
181 }
182}
183ApolloTestingBackend.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
184ApolloTestingBackend.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingBackend });
185i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingBackend, decorators: [{
186 type: Injectable
187 }] });
188
189const APOLLO_TESTING_CACHE = new InjectionToken('apollo-angular/testing cache');
190const APOLLO_TESTING_NAMED_CACHE = new InjectionToken('apollo-angular/testing named cache');
191const APOLLO_TESTING_CLIENTS = new InjectionToken('apollo-angular/testing named clients');
192function addClient(name, op) {
193 op.clientName = name;
194 return op;
195}
196class ApolloTestingModuleCore {
197 constructor(apollo, backend, namedClients, cache, namedCaches) {
198 function createOptions(name, c) {
199 return {
200 link: new ApolloLink((operation) => backend.handle(addClient(name, operation))),
201 cache: c ||
202 new InMemoryCache({
203 addTypename: false,
204 }),
205 };
206 }
207 apollo.create(createOptions('default', cache));
208 if (namedClients && namedClients.length) {
209 namedClients.forEach((name) => {
210 const caches = namedCaches && typeof namedCaches === 'object' ? namedCaches : {};
211 apollo.createNamed(name, createOptions(name, caches[name]));
212 });
213 }
214 }
215}
216ApolloTestingModuleCore.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModuleCore, deps: [{ token: i1.Apollo }, { token: ApolloTestingBackend }, { token: APOLLO_TESTING_CLIENTS, optional: true }, { token: APOLLO_TESTING_CACHE, optional: true }, { token: APOLLO_TESTING_NAMED_CACHE, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
217ApolloTestingModuleCore.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModuleCore, imports: [ApolloModule] });
218ApolloTestingModuleCore.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModuleCore, providers: [
219 ApolloTestingBackend,
220 { provide: ApolloTestingController, useExisting: ApolloTestingBackend },
221 ], imports: [ApolloModule] });
222i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModuleCore, decorators: [{
223 type: NgModule,
224 args: [{
225 imports: [ApolloModule],
226 providers: [
227 ApolloTestingBackend,
228 { provide: ApolloTestingController, useExisting: ApolloTestingBackend },
229 ],
230 }]
231 }], ctorParameters: function () {
232 return [{ type: i1.Apollo }, { type: ApolloTestingBackend }, { type: undefined, decorators: [{
233 type: Optional
234 }, {
235 type: Inject,
236 args: [APOLLO_TESTING_CLIENTS]
237 }] }, { type: i3.ApolloCache, decorators: [{
238 type: Optional
239 }, {
240 type: Inject,
241 args: [APOLLO_TESTING_CACHE]
242 }] }, { type: undefined, decorators: [{
243 type: Optional
244 }, {
245 type: Inject,
246 args: [APOLLO_TESTING_NAMED_CACHE]
247 }] }];
248 } });
249class ApolloTestingModule {
250 static withClients(names) {
251 return {
252 ngModule: ApolloTestingModuleCore,
253 providers: [
254 {
255 provide: APOLLO_TESTING_CLIENTS,
256 useValue: names,
257 },
258 ],
259 };
260 }
261}
262ApolloTestingModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
263ApolloTestingModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModule, imports: [ApolloTestingModuleCore] });
264ApolloTestingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModule, imports: [ApolloTestingModuleCore] });
265i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ApolloTestingModule, decorators: [{
266 type: NgModule,
267 args: [{
268 imports: [ApolloTestingModuleCore],
269 }]
270 }] });
271
272/**
273 * Generated bundle index. Do not edit.
274 */
275
276export { APOLLO_TESTING_CACHE, APOLLO_TESTING_NAMED_CACHE, ApolloTestingController, ApolloTestingModule, TestOperation };
277//# sourceMappingURL=ngApolloTesting.mjs.map