apollo-angular
apollo-angular copied to clipboard
ApolloTestingController flushes .watchQuery synchronously but .query and .mutate asynchronously
Intended outcome:
Using ApolloTestingController should work the same for .watchQuery, .query, and .mutate in terms of async vs sync flush expectations. Tests should fail synchronously if an expectation fails in the subscription callback.
The documentation here should work for all three: https://www.apollographql.com/docs/angular/guides/testing/
Actual outcome:
The documentation for testing Apollo states that ApolloTestingController works like HttpTestingController to test network responses by flushing fake data. This is true, http.get and apollo.watchQuery work exactly the same. You can test whether the responses are the expected responses without worrying about asynchronous factors, like using async or fakeAsync or done.
When using apollo.query or apollo.mutate it does not seem to work the same way and results in strange behavior when expectations do fail. Tests actually pass when they shouldn't, instead errors are thrown later after all tests are run without signaling what test caused a failure ("An error was thrown in afterAll").
Result in example: "Chrome 79.0.3945 (Mac OS X 10.15.2): Executed 3 of 3 (2 FAILED) ERROR (0.071 secs / 0.057 secs)"
How to reproduce the issue:
Repository: https://github.com/alchemy-way/angular-apollo-testing-example Stackblitz: can't run unit tests
Run ng test (or npm test) to execute the unit tests via Karma and notice how the query does not fail synchronously like the others.
Versions
"apollo-angular": "1.8.0"
"apollo-angular-link-http": "1.9.0"
"apollo-link": "1.2.11"
"apollo-client": "2.6.0"
"apollo-cache-inmemory": "1.6.0"
"@angular/core": "8.2.14"
"graphql-tag": "2.10.0"
"graphql": "14.5.0"
"typescript": "3.5.3"
"ts-node": "7.0.0"
"karma": "4.1.0",
"karma-jasmine": "2.0.1"
See package.json: https://github.com/alchemy-way/angular-apollo-testing-example/blob/master/package.json
I'm working on v2 with Apollo Client v3 support right now so I'm going to look at the testing stuff too
That's because @apollo/client/core uses Promises for query and mutate methods
This seems to have changed with Angular 9. Our unit tests now fail quite a bit.
I'm having the same problem, ~except for me watchQuery also does not seem to fail (intentionally)~ [edit: I was using the wrong object in the flush call. watchQuery works as expected].
Versions:
"apollo-angular": "1.6.0",
"apollo-angular-link-http": "1.8.0",
"apollo-cache-inmemory": "1.6.2",
"apollo-client": "2.6.3",
"apollo-link": "1.2.12",
"apollo-link-error": "1.1.11"
"@angular/core": "8.2.14",
"graphql": "14.4.1",
"graphql-tag": "2.10.1",
"ts-node": "7.0.0",
"typescript": "3.4.5"
"karma": "4.2.0",
"karma-jasmine": "2.0.1",
This one has just become a problem for us after updating to [email protected].
let user: User | null | undefined;
userService.user$.pipe(tap(console.log)).subscribe(u => (user = u));
const op = apolloController.expectOne(userQuery);
expect(op.operation.variables).toEqual({ userId: EXPECTED_USER.userId });
op.flush({ data: { user: { ...EXPECTED_USER } } });
console.log('assert');
expect(user).toEqual(user);
In the example above, the assert gets logged before the tap(console.log).
The query we're testing is:
this.queryRef = apollo.watchQuery<UserResponse, UserVariables>({
query: userQuery,
variables: { userId },
fetchPolicy: 'network-only',
});
So now I'm guessing everything is async. We're getting around it using fakeAsync:
fakeAsync(() => {
...
tick();
expect(user).toEqual(EXPECTED_USER);
});