() => {

        let comp: SettingsComponent;
        let fixture: ComponentFixture<SettingsComponent>;
        let mockAuth: any;
        let mockPrincipal: any;

        beforeEach(async(() => {
            TestBed.configureTestingModule({
                imports: [GatewayServiceTestModule],
                declarations: [SettingsComponent],
                providers: [
                ]
            })
            .overrideTemplate(SettingsComponent, '')
            .compileComponents();
        }));

        beforeEach(() => {
            fixture = TestBed.createComponent(SettingsComponent);
            comp = fixture.componentInstance;
            mockAuth = fixture.debugElement.injector.get(AccountService);
            mockPrincipal = fixture.debugElement.injector.get(Principal);
        });

        it('should send the current identity upon save', () => {
            // GIVEN
            const accountValues = {
                firstName: 'John',
                lastName: 'Doe',

                activated: true,
                email: 'john.doe@mail.com',
                langKey: 'en',
                login: 'john'
            };
            mockPrincipal.setResponse(accountValues);

            // WHEN
            comp.settingsAccount = accountValues;
            comp.save();

            // THEN
            expect(mockPrincipal.identitySpy).toHaveBeenCalled();
            expect(mockAuth.saveSpy).toHaveBeenCalledWith(accountValues);
            expect(comp.settingsAccount).toEqual(accountValues);
        });

        it('should notify of success upon successful save', () => {
            // GIVEN
            const accountValues = {
                firstName: 'John',
                lastName: 'Doe'
            };
            mockPrincipal.setResponse(accountValues);

            // WHEN
            comp.save();

            // THEN
            expect(comp.error).toBeNull();
            expect(comp.success).toBe('OK');
        });

        it('should notify of error upon failed save', () => {
            // GIVEN
            mockAuth.saveSpy.and.returnValue(Observable.throw('ERROR'));

            // WHEN
            comp.save();

            // THEN
            expect(comp.error).toEqual('ERROR');
            expect(comp.success).toBeNull();
        });
    }


() => {
            TestBed.configureTestingModule({
                imports: [GatewayServiceTestModule],
                declarations: [SettingsComponent],
                providers: [
                ]
            })
            .overrideTemplate(SettingsComponent, '')
            .compileComponents();
        }


() => {
            fixture = TestBed.createComponent(SettingsComponent);
            comp = fixture.componentInstance;
            mockAuth = fixture.debugElement.injector.get(AccountService);
            mockPrincipal = fixture.debugElement.injector.get(Principal);
        }


() => {
            // GIVEN
            const accountValues = {
                firstName: 'John',
                lastName: 'Doe',

                activated: true,
                email: 'john.doe@mail.com',
                langKey: 'en',
                login: 'john'
            };
            mockPrincipal.setResponse(accountValues);

            // WHEN
            comp.settingsAccount = accountValues;
            comp.save();

            // THEN
            expect(mockPrincipal.identitySpy).toHaveBeenCalled();
            expect(mockAuth.saveSpy).toHaveBeenCalledWith(accountValues);
            expect(comp.settingsAccount).toEqual(accountValues);
        }


() => {
            // GIVEN
            const accountValues = {
                firstName: 'John',
                lastName: 'Doe'
            };
            mockPrincipal.setResponse(accountValues);

            // WHEN
            comp.save();

            // THEN
            expect(comp.error).toBeNull();
            expect(comp.success).toBe('OK');
        }


() => {
            // GIVEN
            mockAuth.saveSpy.and.returnValue(Observable.throw('ERROR'));

            // WHEN
            comp.save();

            // THEN
            expect(comp.error).toEqual('ERROR');
            expect(comp.success).toBeNull();
        }


function checkCacheAndNetworkError(callback: () => any) {
      try {
        callback();
        throw new Error('not reached');
      } catch (thrown) {
        expect(thrown.message).toBe(cacheAndNetworkError);
      }
    }


function makeLink(reject: (reason: any) => any) {
      return mockSingleLink({
        request: { query },
        result: { data: firstFetch },
      }, {
        request: { query },
        result: { data: secondFetch },
      }).setOnError(reject);
    }


function watch(
      query: DocumentNode,
      fetchPolicy: WatchQueryFetchPolicy = "cache-first",
    ): any[] {
      const results: any[] = [];
      const obsQuery = client.watchQuery({
        query,
        fetchPolicy,
      });
      obsQueries.add(obsQuery);
      subs.add(obsQuery.subscribe({
        next(result) {
          results.push(result.data);
        },
      }));
      return results;
    }


function checkLastResult(
      results: any[],
      expectedData: Record<string, any>,
    ) {
      const lastResult = results[results.length - 1];
      expect(lastResult).toEqual(expectedData);
      return lastResult;
    }


function wait(time = 10) {
    return new Promise(resolve => setTimeout(resolve, time));
  }


function clientRoundtrip(
  resolve: (result: any) => any,
  reject: (reason: any) => any,
  query: DocumentNode,
  data: ExecutionResult,
  variables?: any,
  possibleTypes?: PossibleTypesMap,
) {
  const link = mockSingleLink({
    request: { query: cloneDeep(query) },
    result: data,
  }).setOnError(reject);

  const client = new ApolloClient({
    link,
    cache: new InMemoryCache({
      possibleTypes,
    }),
  });

  return client.query({ query, variables }).then(result => {
    expect(result.data).toEqual(data.data);
  }).then(resolve, reject);
}


() => {
    /* tslint:disable */
    const ApolloClientRequire = require('../').ApolloClient;
    /* tslint:enable */

    const client = new ApolloClientRequire({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    expect(client.queryManager).toBeDefined();
    expect(client.cache).toBeDefined();
  }


() => {
    const link = ApolloLink.empty();
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache(),
    });

    expect(client.link).toBeInstanceOf(ApolloLink);
  }


() => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    expect(() => {
      client.query(gql`
        {
          a
        }
      ` as any);
    }).toThrowError(
      'query option is required. You must specify your GraphQL document in the query option.',
    );
    expect(() => {
      client.query({ query: '{ a }' } as any);
    }).toThrowError('You must wrap the query string in a "gql" tag.');
  }


() => {
      client.query(gql`
        {
          a
        }
      ` as any);
    }


() => {
      client.query({ query: '{ a }' } as any);
    }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    return await expect(
      client.mutate({
        query: gql`
          {
            a
          }
        `,
      } as any),
    ).rejects.toThrow(
      'mutation option is required. You must specify your GraphQL document in the mutation option.',
    );
  }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
            __typename
          }
          __typename
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
            __typename: 'Person',
          },
        ],
        __typename: 'People',
      },
    };

    return clientRoundtrip(resolve, reject, query, { data });
  }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
            __typename
          }
          __typename
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
            __typename: 'Person',
          },
        ],
        __typename: 'People',
      },
    };

    const variables = { first: 1 };

    const link = ApolloLink.from([() => Observable.of({ data })]);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    client.query({ query, variables }).then(actualResult => {
      expect(actualResult.data).toEqual(data);
      resolve();
    });
  }


() => Observable.of({ data })


actualResult => {
      expect(actualResult.data).toEqual(data);
      resolve();
    }


(resolve, reject) => {
    const query = gql`
      query stuff(
        $test: Input = { key1: ["value", "value2"], key2: { key3: 4 } }
      ) {
        allStuff(test: $test) {
          people {
            name
          }
        }
      }
    `;

    const result = {
      allStuff: {
        people: [
          {
            name: 'Luke Skywalker',
          },
          {
            name: 'Jabba The Hutt',
          },
        ],
      },
    };

    const variables = {
      test: { key1: ['value', 'value2'], key2: { key3: 4 } },
    };

    const link = mockSingleLink({
      request: { query, variables },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    const basic = client.query({ query, variables }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    });

    const withDefault = client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    });

    return Promise.all([
      basic,
      withDefault,
    ]).then(resolve, reject);
  }


actualResult => {
      expect(actualResult.data).toEqual(result);
    }


(resolve, reject) => {
    const query = gql`
      query people($first: Int = 1) {
        allPeople(first: $first) {
          people {
            name
          }
        }
      }
    `;

    const variables = { first: 1 };
    const override = { first: 2 };

    const result = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const overriddenResult = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
          {
            name: 'Jabba The Hutt',
          },
        ],
      },
    };

    const link = mockSingleLink({
      request: { query, variables },
      result: { data: result },
    }, {
      request: { query, variables: override },
      result: { data: overriddenResult },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    const basic = client.query({ query, variables }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    });

    const withDefault = client.query({ query }).then(actualResult => {
      return expect(actualResult.data).toEqual(result);
    });

    const withOverride = client
      .query({ query, variables: override })
      .then(actualResult => {
        return expect(actualResult.data).toEqual(
          overriddenResult,
        );
      });

    return Promise.all([
      basic,
      withDefault,
      withOverride,
    ]).then(resolve, reject);
  }


actualResult => {
      return expect(actualResult.data).toEqual(result);
    }


actualResult => {
        return expect(actualResult.data).toEqual(
          overriddenResult,
        );
      }


(resolve, reject) => {
    const query = gql`
      query {
        ...QueryFragment
      }

      fragment QueryFragment on Query {
        records {
          id
          name
          __typename
        }
        __typename
      }
    `;

    const data = {
      records: [
        { id: 1, name: 'One', __typename: 'Record' },
        { id: 2, name: 'Two', __typename: 'Record' },
      ],
      __typename: 'Query',
    };

    return clientRoundtrip(resolve, reject, query, { data }, null);
  }


(resolve, reject) => {
    const query = gql`
      query {
        ...QueryFragment
      }

      fragment QueryFragment on Query {
        records {
          id
          name
          __typename
        }
        __typename
      }
    `;

    const data = {
      records: [
        { id: 1, name: 'One', __typename: 'Record' },
        { id: 2, name: 'Two', __typename: 'Record' },
      ],
      __typename: 'Query',
    };

    return clientRoundtrip(resolve, reject, query, { data }, null, {
      Query: ['Record'],
    });
  }


(resolve, reject) => {
    // The fragment should be used after the selected fields for the query.
    // Otherwise, the results aren't merged.
    // see: https://github.com/apollographql/apollo-client/issues/1479
    const query = gql`
      query {
        records {
          id
          __typename
        }
        ...QueryFragment
      }

      fragment QueryFragment on Query {
        records {
          name
          __typename
        }
        __typename
      }
    `;

    const data = {
      records: [
        { id: 1, name: 'One', __typename: 'Record' },
        { id: 2, name: 'Two', __typename: 'Record' },
      ],
      __typename: 'Query',
    };

    return clientRoundtrip(resolve, reject, query, { data }, null, {
      Query: ['Record'],
    });
  }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data },
    }).setOnError(reject);

    const initialState: any = {
      data: {
        ROOT_QUERY: {
          'allPeople({"first":1})': {
            people: [
              {
                name: 'Luke Skywalker',
              },
            ],
          },
        },
        optimistic: [],
      },
    };

    const finalState = assign({}, initialState, {});

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }).restore(
        initialState.data,
      ),
    });

    return client.query({ query }).then(result => {
      expect(result.data).toEqual(data);
      expect(finalState.data).toEqual(
        (client.cache as InMemoryCache).extract(),
      );
    }).then(resolve, reject);
  }


result => {
      expect(result.data).toEqual(data);
      expect(finalState.data).toEqual(
        (client.cache as InMemoryCache).extract(),
      );
    }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data },
    }).setOnError(reject);

    const initialState: any = {
      data: {
        ROOT_QUERY: {
          'allPeople({"first":1})': {
            people: [
              {
                name: 'Luke Skywalker',
              },
            ],
          },
        },
        optimistic: [],
      },
    };

    const finalState = assign({}, initialState, {});

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }).restore(
        initialState.data,
      ),
    });

    return client.query({ query }).then(result => {
      expect(result.data).toEqual(data);
      expect(finalState.data).toEqual(client.extract());
    }).then(resolve, reject);
  }


result => {
      expect(result.data).toEqual(data);
      expect(finalState.data).toEqual(client.extract());
    }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data },
    }).setOnError(reject);

    const initialState: any = {
      data: {
        'ROOT_QUERY.allPeople({"first":"1"}).people.0': {
          name: 'Luke Skywalker',
        },
        'ROOT_QUERY.allPeople({"first":1})': {
          people: [
            {
              type: 'id',
              generated: true,
              id: 'ROOT_QUERY.allPeople({"first":"1"}).people.0',
            },
          ],
        },
        ROOT_QUERY: {
          'allPeople({"first":1})': {
            type: 'id',
            id: 'ROOT_QUERY.allPeople({"first":1})',
            generated: true,
          },
        },
        optimistic: [],
      },
    };

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }).restore(
        initialState.data,
      ),
    });

    expect(client.restore(initialState.data)).toEqual(
      client.cache.restore(initialState.data),
    );

    resolve();
  }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const errors: GraphQLError[] = [
      new GraphQLError('Syntax Error GraphQL request (8:9) Expected Name, found EOF')
    ];

    const link = mockSingleLink({
      request: { query },
      result: { errors },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client.query({ query }).catch((error: ApolloError) => {
      expect(error.graphQLErrors).toEqual(errors);
    }).then(resolve, reject);
  }


(error: ApolloError) => {
      expect(error.graphQLErrors).toEqual(errors);
    }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const errors: GraphQLError[] = [
      new GraphQLError('Syntax Error GraphQL request (8:9) Expected Name, found EOF'),
    ];

    const link = ApolloLink.from([
      () => {
        return new Observable(observer => {
          observer.next({ data, errors });
        });
      },
    ]);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    client.query({ query }).catch((error: ApolloError) => {
      expect(error.graphQLErrors).toEqual(errors);
      resolve();
    });
  }


() => {
        return new Observable(observer => {
          observer.next({ data, errors });
        });
      }


observer => {
          observer.next({ data, errors });
        }


(error: ApolloError) => {
      expect(error.graphQLErrors).toEqual(errors);
      resolve();
    }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const networkError = new Error('Some kind of network error.');

    const link = ApolloLink.from([
      () => {
        return new Observable(_ => {
          throw networkError;
        });
      },
    ]);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    client.query({ query }).catch((error: ApolloError) => {
      expect(error.networkError).toBeDefined();
      expect(error.networkError!.message).toEqual(networkError.message);
      resolve();
    });
  }


() => {
        return new Observable(_ => {
          throw networkError;
        });
      }


_ => {
          throw networkError;
        }


(error: ApolloError) => {
      expect(error.networkError).toBeDefined();
      expect(error.networkError!.message).toEqual(networkError.message);
      resolve();
    }


() => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const link = ApolloLink.from([() => Observable.of({ data }, { data })]);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client.query({ query }).then((result: ExecutionResult) => {
      expect(result.data).toEqual(data);
    });
  }


() => Observable.of({ data }, { data })


(result: ExecutionResult) => {
      expect(result.data).toEqual(data);
    }


(resolve, reject) => {
    const expectedError = new Error('this error should not reach the store');
    const listeners = process.listeners('uncaughtException');
    const oldHandler = listeners[listeners.length - 1];
    const handleUncaught = (e: Error) => {
      console.log(e);
      process.removeListener('uncaughtException', handleUncaught);
      if (typeof oldHandler === 'function')
        process.addListener('uncaughtException', oldHandler);
      if (e === expectedError) {
        resolve();
      } else {
        reject(e);
      }
    };
    process.removeListener('uncaughtException', oldHandler);
    process.addListener('uncaughtException', handleUncaught);

    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    const handle = client.watchQuery({ query });

    handle.subscribe({
      next() {
        throw expectedError;
      },
    });
  }


(e: Error) => {
      console.log(e);
      process.removeListener('uncaughtException', handleUncaught);
      if (typeof oldHandler === 'function')
        process.addListener('uncaughtException', oldHandler);
      if (e === expectedError) {
        resolve();
      } else {
        reject(e);
      }
    }


(resolve, reject) => {
    const expectedError = new Error('this error should not reach the store');
    const listeners = process.listeners('uncaughtException');
    const oldHandler = listeners[listeners.length - 1];
    const handleUncaught = (e: Error) => {
      process.removeListener('uncaughtException', handleUncaught);
      process.addListener('uncaughtException', oldHandler);
      if (e === expectedError) {
        resolve();
      } else {
        reject(e);
      }
    };
    process.removeListener('uncaughtException', oldHandler);
    process.addListener('uncaughtException', handleUncaught);

    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const link = mockSingleLink({
      request: { query },
      result: {},
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    const handle = client.watchQuery({ query });
    handle.subscribe({
      next() {
        reject(new Error('did not expect next to be called'));
      },
      error() {
        throw expectedError;
      },
    });
  }


(e: Error) => {
      process.removeListener('uncaughtException', handleUncaught);
      process.addListener('uncaughtException', oldHandler);
      if (e === expectedError) {
        resolve();
      } else {
        reject(e);
      }
    }


(resolve, reject) => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    const handle = client.watchQuery({ query });

    handle.subscribe({
      next(result) {
        expect(result.data).toEqual(data);
        resolve();
      },
    });
  }


(resolve, reject) => {
    const query = gql`
      query {
        author {
          firstName
          lastName
        }
      }
    `;
    const transformedQuery = gql`
      query {
        author {
          firstName
          lastName
          __typename
        }
      }
    `;

    const result = {
      author: {
        firstName: 'John',
        lastName: 'Smith',
      },
    };
    const transformedResult = {
      author: {
        firstName: 'John',
        lastName: 'Smith',
        __typename: 'Author',
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }, {
      request: { query: transformedQuery },
      result: { data: transformedResult },
    }, false).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: true }),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(transformedResult);
    }).then(resolve, reject);
  }


actualResult => {
      expect(actualResult.data).toEqual(transformedResult);
    }


(resolve, reject) => {
    const query = gql`
      query {
        author {
          firstName
          lastName
        }
      }
    `;
    const transformedQuery = gql`
      query {
        author {
          firstName
          lastName
          __typename
        }
      }
    `;
    const result = {
      author: {
        firstName: 'John',
        lastName: 'Smith',
      },
    };
    const transformedResult = {
      author: {
        firstName: 'John',
        lastName: 'Smith',
        __typename: 'Author',
      },
    };
    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }, {
      request: { query: transformedQuery },
      result: { data: transformedResult },
    }, false).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: true }),
    });

    return client
      .query({ fetchPolicy: 'network-only', query })
      .then(actualResult => {
        expect(actualResult.data).toEqual(transformedResult);
      })
      .then(resolve, reject);
  }


actualResult => {
        expect(actualResult.data).toEqual(transformedResult);
      }


(resolve, reject) => {
    const mutation = gql`
      mutation {
        starAuthor(id: 12) {
          author {
            __typename
            ...authorDetails
          }
        }
      }

      fragment authorDetails on Author {
        firstName
        lastName
      }
    `;
    const result = {
      starAuthor: {
        author: {
          __typename: 'Author',
          firstName: 'John',
          lastName: 'Smith',
        },
      },
    };
    const link = mockSingleLink({
      request: { query: mutation },
      result: { data: result },
    }).setOnError(reject);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client.mutate({ mutation }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


(resolve, reject) => {
    const query = gql`
      fragment authorDetails on Author {
        firstName
        lastName
      }

      query {
        author {
          __typename
          ...authorDetails
        }
      }
    `;
    const result = {
      author: {
        __typename: 'Author',
        firstName: 'John',
        lastName: 'Smith',
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client
      .query({ fetchPolicy: 'network-only', query })
      .then(actualResult => {
        expect(actualResult.data).toEqual(result);
      })
      .then(resolve, reject);
  }


actualResult => {
        expect(actualResult.data).toEqual(result);
      }


(resolve, reject) => {
    const query = gql`
      query {
        author {
          __typename
          ...authorDetails
          ...moreDetails
        }
      }

      fragment authorDetails on Author {
        firstName
        lastName
      }

      fragment moreDetails on Author {
        address
      }
    `;
    const result = {
      author: {
        __typename: 'Author',
        firstName: 'John',
        lastName: 'Smith',
        address: '1337 10th St.',
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }).setOnError(reject);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


(resolve, reject) => {
    const query = gql`
      query {
        author {
          __typename
          ...authorDetails
        }
      }

      fragment authorDetails on Author {
        firstName
        lastName
      }
    `;
    const result = {
      author: {
        __typename: 'Author',
        firstName: 'John',
        lastName: 'Smith',
      },
    };

    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }).setOnError(reject);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


(resolve, reject) => {
    const query = gql`
      query items {
        items {
          ...ItemFragment
          __typename
        }
      }

      fragment ItemFragment on Item {
        id
        __typename
        ... on ColorItem {
          color
          __typename
        }
      }
    `;
    const result = {
      items: [
        {
          __typename: 'ColorItem',
          id: '27tlpoPeXm6odAxj3paGQP',
          color: 'red',
        },
        {
          __typename: 'MonochromeItem',
          id: '1t3iFLsHBm4c4RjOMdMgOO',
        },
      ],
    };

    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }).setOnError(reject);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({
        possibleTypes: {
          Item: ['ColorItem', 'MonochromeItem'],
        },
      }),
    });
    return client.query({ query }).then((actualResult: any) => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


(actualResult: any) => {
      expect(actualResult.data).toEqual(result);
    }


(resolve, reject) => {
    const query = gql`
      query items {
        items {
          ...ItemFragment
          __typename
        }
      }

      fragment ItemFragment on Item {
        id
        ... on ColorItem {
          color
          __typename
        }
        __typename
      }
    `;
    const result = {
      items: [
        {
          __typename: 'ColorItem',
          id: '27tlpoPeXm6odAxj3paGQP',
          color: 'red',
        },
        {
          __typename: 'MonochromeItem',
          id: '1t3iFLsHBm4c4RjOMdMgOO',
        },
      ],
    };

    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({
        possibleTypes: {
          Item: ['ColorItem', 'MonochromeItem'],
        },
      }),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


(resolve, reject) => {
    const query = gql`
      query items {
        items {
          ...ItemFragment
          __typename
        }
      }

      fragment ItemFragment on Item {
        id
        ... on ColorItem {
          color
          __typename
        }
        __typename
      }
    `;
    const result = {
      items: [
        {
          __typename: 'ColorItem',
          id: '27tlpoPeXm6odAxj3paGQP',
          color: 'red',
        },
        {
          __typename: 'MonochromeItem',
          id: '1t3iFLsHBm4c4RjOMdMgOO',
        },
      ],
    };

    const mutation = gql`
      mutation myMutationName {
        fortuneCookie
      }
    `;
    const mutationResult = {
      fortuneCookie: 'The waiter spit in your food',
    };

    const link = mockSingleLink({
      request: { query },
      result: { data: result },
    }, {
      request: { query: mutation },
      result: { data: mutationResult },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({
        possibleTypes: {
          Item: ['ColorItem', 'MonochromeItem'],
        },
      }),
    });

    const queryUpdaterSpy = jest.fn();
    const queryUpdater = (prev: any) => {
      queryUpdaterSpy();
      return prev;
    };
    const updateQueries = {
      items: queryUpdater,
    };

    const updateSpy = jest.fn();

    const obs = client.watchQuery({ query });

    const sub = obs.subscribe({
      next() {
        client
          .mutate({ mutation, updateQueries, update: updateSpy })
          .then(() => {
            expect(queryUpdaterSpy).toBeCalled();
            expect(updateSpy).toBeCalled();
            sub.unsubscribe();
            resolve();
          })
          .catch(err => {
            reject(err);
          });
      },
      error(err) {
        reject(err);
      },
    });
  }


(prev: any) => {
      queryUpdaterSpy();
      return prev;
    }


() => {
            expect(queryUpdaterSpy).toBeCalled();
            expect(updateSpy).toBeCalled();
            sub.unsubscribe();
            resolve();
          }


err => {
            reject(err);
          }


() => {
    const query = gql`
      query myQueryName {
        fortuneCookie
      }
    `;
    const data = {
      fortuneCookie: 'The waiter spit in your food',
    };
    const link = ApolloLink.from([
      request => {
        expect(request.operationName).toBe('myQueryName');
        return Observable.of({ data });
      },
    ]);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(data);
    });
  }


request => {
        expect(request.operationName).toBe('myQueryName');
        return Observable.of({ data });
      }


actualResult => {
      expect(actualResult.data).toEqual(data);
    }


() => {
    const mutation = gql`
      mutation myMutationName {
        fortuneCookie
      }
    `;
    const data = {
      fortuneCookie: 'The waiter spit in your food',
    };
    const link = ApolloLink.from([
      request => {
        expect(request.operationName).toBe('myMutationName');
        return Observable.of({ data });
      },
    ]);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    return client.mutate({ mutation }).then(actualResult => {
      expect(actualResult.data).toEqual(data);
    });
  }


request => {
        expect(request.operationName).toBe('myMutationName');
        return Observable.of({ data });
      }


(resolve, reject) => {
    const queryDoc = gql`
      query {
        author {
          name
        }
      }
    `;
    const data = {
      author: {
        name: 'Jonas',
      },
    };
    const data2 = {
      author: {
        name: 'Dhaivat',
      },
    };

    // we have two responses for identical queries, and both should be requested.
    // the second one should make it through to the network interface.
    const link = mockSingleLink(
      {
        request: { query: queryDoc },
        result: { data },
        delay: 10,
      },
      {
        request: { query: queryDoc },
        result: { data: data2 },
      },
    ).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
      queryDeduplication: false,
    });

    const q1 = client.query({ query: queryDoc });
    const q2 = client.query({ query: queryDoc });

    // if deduplication happened, result2.data will equal data.
    return Promise.all([q1, q2]).then(([result1, result2]) => {
      expect(result1.data).toEqual(data);
      expect(result2.data).toEqual(data2);
    }).then(resolve, reject);
  }


([result1, result2]) => {
      expect(result1.data).toEqual(data);
      expect(result2.data).toEqual(data2);
    }


(resolve, reject) => {
    const queryDoc = gql`
      query {
        author {
          name
        }
      }
    `;
    const data = {
      author: {
        name: 'Jonas',
      },
    };
    const data2 = {
      author: {
        name: 'Dhaivat',
      },
    };

    // we have two responses for identical queries, but only the first should be requested.
    // the second one should never make it through to the network interface.
    const link = mockSingleLink({
      request: { query: queryDoc },
      result: { data },
      delay: 10,
    }, {
      request: { query: queryDoc },
      result: { data: data2 },
    }).setOnError(reject);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    const q1 = client.query({ query: queryDoc });
    const q2 = client.query({ query: queryDoc });

    // if deduplication didn't happen, result.data will equal data2.
    return Promise.all([q1, q2]).then(([result1, result2]) => {
      expect(result1.data).toEqual(result2.data);
    }).then(resolve, reject);
  }


([result1, result2]) => {
      expect(result1.data).toEqual(result2.data);
    }


() => {
    const queryDoc = gql`
      query {
        author {
          name
        }
      }
    `;
    const data = {
      author: {
        name: 'Jonas',
      },
    };
    const data2 = {
      author: {
        name: 'Dhaivat',
      },
    };

    // we have two responses for identical queries, but only the first should be requested.
    // the second one should never make it through to the network interface.
    const link = mockSingleLink(
      {
        request: { query: queryDoc },
        result: { data },
        delay: 10,
      },
      {
        request: { query: queryDoc },
        result: { data: data2 },
      },
    );
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
      queryDeduplication: false,
    });

    // Both queries need to be deduplicated, otherwise only one gets tracked
    const q1 = client.query({ query: queryDoc, context: { queryDeduplication: true } });
    const q2 = client.query({ query: queryDoc, context: { queryDeduplication: true } });

    // if deduplication happened, result2.data will equal data.
    return Promise.all([q1, q2]).then(([result1, result2]) => {
      expect(result1.data).toEqual(data);
      expect(result2.data).toEqual(data);
    });
  }


([result1, result2]) => {
      expect(result1.data).toEqual(data);
      expect(result2.data).toEqual(data);
    }


() => {
    const queryDoc = gql`
      query {
        author {
          name
        }
      }
    `;
    const data = {
      author: {
        name: 'Jonas',
      },
    };
    const data2 = {
      author: {
        name: 'Dhaivat',
      },
    };

    // we have two responses for identical queries, and both should be requested.
    // the second one should make it through to the network interface.
    const link = mockSingleLink(
      {
        request: { query: queryDoc },
        result: { data },
        delay: 10,
      },
      {
        request: { query: queryDoc },
        result: { data: data2 },
      },
    );
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    // The first query gets tracked in the dedup logic, the second one ignores it and runs anyways
    const q1 = client.query({ query: queryDoc });
    const q2 = client.query({ query: queryDoc, context: { queryDeduplication: false } });

    // if deduplication happened, result2.data will equal data.
    return Promise.all([q1, q2]).then(([result1, result2]) => {
      expect(result1.data).toEqual(data);
      expect(result2.data).toEqual(data2);
    });
  }


(resolve, reject) => {
    const document: DocumentNode = gql`
      query test1($x: String) {
        test(x: $x)
      }
    `;

    const variables1 = { x: 'Hello World' };
    const variables2 = { x: 'Hello World' };

    let unsubscribed = false;

    const client = new ApolloClient({
      link: new ApolloLink(() => {
        return new Observable(observer => {
          observer.complete();
          return () => {
            unsubscribed = true;
            setTimeout(resolve, 0);
          };
        });
      }),
      cache: new InMemoryCache(),
    });

    const sub1 = client
      .watchQuery({
        query: document,
        variables: variables1,
      })
      .subscribe({});

    const sub2 = client
      .watchQuery({
        query: document,
        variables: variables2,
      })
      .subscribe({});

    sub1.unsubscribe();
    expect(unsubscribed).toBe(false);

    sub2.unsubscribe();
  }


() => {
        return new Observable(observer => {
          observer.complete();
          return () => {
            unsubscribed = true;
            setTimeout(resolve, 0);
          };
        });
      }


observer => {
          observer.complete();
          return () => {
            unsubscribed = true;
            setTimeout(resolve, 0);
          };
        }


() => {
            unsubscribed = true;
            setTimeout(resolve, 0);
          }


() => {
    const query = gql`
      query people {
        name
      }
    `;

    it('errors when returnPartialData is used on query', () => {
      const client = new ApolloClient({
        link: ApolloLink.empty(),
        cache: new InMemoryCache(),
      });
      expect(() => {
        client.query({ query, returnPartialData: true } as QueryOptions);
      }).toThrowError(/returnPartialData/);
    });

    it('errors when returnPartialData is used on watchQuery', () => {
      const client = new ApolloClient({
        link: ApolloLink.empty(),
        cache: new InMemoryCache(),
      });
      expect(() => {
        client.query({ query, returnPartialData: true } as QueryOptions);
      }).toThrowError(/returnPartialData/);
    });
  }


() => {
      const client = new ApolloClient({
        link: ApolloLink.empty(),
        cache: new InMemoryCache(),
      });
      expect(() => {
        client.query({ query, returnPartialData: true } as QueryOptions);
      }).toThrowError(/returnPartialData/);
    }


() => {
        client.query({ query, returnPartialData: true } as QueryOptions);
      }


() => {
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            id
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            id: '1',
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    itAsync('for internal store', (resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,

        cache: new InMemoryCache({
          dataIdFromObject: (obj: { id: any }) => obj.id,
          addTypename: false,
        }),
      });

      return client.query({ query }).then(result => {
        expect(result.data).toEqual(data);
        expect((client.cache as InMemoryCache).extract()['1']).toEqual({
          id: '1',
          name: 'Luke Skywalker',
        });
      }).then(resolve, reject);
    });
  }


(resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,

        cache: new InMemoryCache({
          dataIdFromObject: (obj: { id: any }) => obj.id,
          addTypename: false,
        }),
      });

      return client.query({ query }).then(result => {
        expect(result.data).toEqual(data);
        expect((client.cache as InMemoryCache).extract()['1']).toEqual({
          id: '1',
          name: 'Luke Skywalker',
        });
      }).then(resolve, reject);
    }


(obj: { id: any }) => obj.id


result => {
        expect(result.data).toEqual(data);
        expect((client.cache as InMemoryCache).extract()['1']).toEqual({
          id: '1',
          name: 'Luke Skywalker',
        });
      }


() => {
    const query = gql`
      query number {
        myNumber {
          n
        }
      }
    `;

    const initialData = {
      myNumber: {
        n: 1,
      },
    };
    const networkFetch = {
      myNumber: {
        n: 2,
      },
    };

    const cacheAndNetworkError =
      'The cache-and-network fetchPolicy does not work with client.query, because ' +
      'client.query can only return a single result. Please use client.watchQuery ' +
      'to receive multiple results from the cache and the network, or consider ' +
      'using a different fetchPolicy, such as cache-first or network-only.';

    function checkCacheAndNetworkError(callback: () => any) {
      try {
        callback();
        throw new Error('not reached');
      } catch (thrown) {
        expect(thrown.message).toBe(cacheAndNetworkError);
      }
    }

    // Test that cache-and-network can only be used on watchQuery, not query.
    it('warns when used with client.query', () => {
      const client = new ApolloClient({
        link: ApolloLink.empty(),
        cache: new InMemoryCache(),
      });

      checkCacheAndNetworkError(
        () => client.query({
          query,
          fetchPolicy: 'cache-and-network' as FetchPolicy,
        }),
      );
    });

    it('warns when used with client.query with defaultOptions', () => {
      const client = new ApolloClient({
        link: ApolloLink.empty(),
        cache: new InMemoryCache(),
        defaultOptions: {
          query: {
            fetchPolicy: 'cache-and-network' as FetchPolicy,
          },
        },
      });

      checkCacheAndNetworkError(() => client.query({
        query,
        // This undefined value should be ignored in favor of
        // defaultOptions.query.fetchPolicy.
        fetchPolicy: void 0,
      }));
    });

    itAsync('fetches from cache first, then network', (resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data: networkFetch },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      client.writeQuery({ query, data: initialData });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(initialData);
        } else if (handleCount === 2) {
          expect(result.data).toEqual(networkFetch);
          resolve();
        }
      });
    });

    itAsync('does not fail if cache entry is not present', (resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data: networkFetch },
      }).setOnError(reject);
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        expect(handleCount).toBe(1);
        expect(result.data).toEqual(networkFetch);
        expect(result.loading).toBe(false);
        resolve();
      });
    });

    itAsync('fails if network request fails', (resolve, reject) => {
      const link = mockSingleLink(); // no queries = no replies.
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });

      obs.subscribe({
        error: e => {
          if (!/No more mocked responses/.test(e.message)) {
            reject(e);
          } else {
            resolve();
          }
        },
      });
    });

    itAsync('fetches from cache first, then network and does not have an unhandled error', (resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { errors: [{ message: 'network failure' }] },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      client.writeQuery({ query, data: initialData });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });
      let shouldFail = true;
      process.once('unhandledRejection', rejection => {
        if (shouldFail) reject('promise had an unhandledRejection');
      });
      let count = 0;
      obs.subscribe({
        next: result => {
          expect(result.data).toEqual(initialData);
          expect(result.loading).toBe(true);
          count++;
        },
        error: e => {
          expect(e.message).toMatch(/network failure/);
          expect(count).toBe(1); // make sure next was called.
          setTimeout(() => {
            shouldFail = false;
            resolve();
          }, 0);
        },
      });
    });
  }


() => {
      const client = new ApolloClient({
        link: ApolloLink.empty(),
        cache: new InMemoryCache(),
      });

      checkCacheAndNetworkError(
        () => client.query({
          query,
          fetchPolicy: 'cache-and-network' as FetchPolicy,
        }),
      );
    }


() => client.query({
          query,
          fetchPolicy: 'cache-and-network' as FetchPolicy,
        })


() => {
      const client = new ApolloClient({
        link: ApolloLink.empty(),
        cache: new InMemoryCache(),
        defaultOptions: {
          query: {
            fetchPolicy: 'cache-and-network' as FetchPolicy,
          },
        },
      });

      checkCacheAndNetworkError(() => client.query({
        query,
        // This undefined value should be ignored in favor of
        // defaultOptions.query.fetchPolicy.
        fetchPolicy: void 0,
      }));
    }


() => client.query({
        query,
        // This undefined value should be ignored in favor of
        // defaultOptions.query.fetchPolicy.
        fetchPolicy: void 0,
      })


(resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data: networkFetch },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      client.writeQuery({ query, data: initialData });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(initialData);
        } else if (handleCount === 2) {
          expect(result.data).toEqual(networkFetch);
          resolve();
        }
      });
    }


(handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(initialData);
        } else if (handleCount === 2) {
          expect(result.data).toEqual(networkFetch);
          resolve();
        }
      }


(resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { data: networkFetch },
      }).setOnError(reject);
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        expect(handleCount).toBe(1);
        expect(result.data).toEqual(networkFetch);
        expect(result.loading).toBe(false);
        resolve();
      });
    }


(handleCount, result) => {
        expect(handleCount).toBe(1);
        expect(result.data).toEqual(networkFetch);
        expect(result.loading).toBe(false);
        resolve();
      }


(resolve, reject) => {
      const link = mockSingleLink(); // no queries = no replies.
      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });

      obs.subscribe({
        error: e => {
          if (!/No more mocked responses/.test(e.message)) {
            reject(e);
          } else {
            resolve();
          }
        },
      });
    }


e => {
          if (!/No more mocked responses/.test(e.message)) {
            reject(e);
          } else {
            resolve();
          }
        }


(resolve, reject) => {
      const link = mockSingleLink({
        request: { query },
        result: { errors: [{ message: 'network failure' }] },
      }).setOnError(reject);

      const client = new ApolloClient({
        link,
        cache: new InMemoryCache({ addTypename: false }),
      });

      client.writeQuery({ query, data: initialData });

      const obs = client.watchQuery({
        query,
        fetchPolicy: 'cache-and-network',
      });
      let shouldFail = true;
      process.once('unhandledRejection', rejection => {
        if (shouldFail) reject('promise had an unhandledRejection');
      });
      let count = 0;
      obs.subscribe({
        next: result => {
          expect(result.data).toEqual(initialData);
          expect(result.loading).toBe(true);
          count++;
        },
        error: e => {
          expect(e.message).toMatch(/network failure/);
          expect(count).toBe(1); // make sure next was called.
          setTimeout(() => {
            shouldFail = false;
            resolve();
          }, 0);
        },
      });
    }


rejection => {
        if (shouldFail) reject('promise had an unhandledRejection');
      }


result => {
          expect(result.data).toEqual(initialData);
          expect(result.loading).toBe(true);
          count++;
        }


e => {
          expect(e.message).toMatch(/network failure/);
          expect(count).toBe(1); // make sure next was called.
          setTimeout(() => {
            shouldFail = false;
            resolve();
          }, 0);
        }


() => {
            shouldFail = false;
            resolve();
          }


() => {
    itAsync('are not watching the store or notifying on updates', (resolve, reject) => {
      const query = gql`
        {
          test
        }
      `;
      const data = { test: 'ok' };
      const data2 = { test: 'not ok' };

      const link = mockSingleLink({
        request: { query },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({ link, cache: new InMemoryCache() });

      const obs = client.watchQuery({ query, fetchPolicy: 'cache-first' });

      let handleCalled = false;
      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(data);
          obs.setOptions({ query, fetchPolicy: 'standby' }).then(() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
          });
          setTimeout(() => {
            if (!handleCalled) {
              resolve();
            }
          }, 20);
        }
        if (handleCount === 2) {
          handleCalled = true;
          reject(
            new Error('Handle should never be called on standby query'),
          );
        }
      });
    });

    itAsync('return the current result when coming out of standby', (resolve, reject) => {
      const query = gql`
        {
          test
        }
      `;
      const data = { test: 'ok' };
      const data2 = { test: 'not ok' };

      const link = mockSingleLink({
        request: { query },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({ link, cache: new InMemoryCache() });

      const obs = client.watchQuery({ query, fetchPolicy: 'cache-first' });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(data);
          obs.setOptions({ query, fetchPolicy: 'standby' }).then(() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
            setTimeout(() => {
              obs.setOptions({ query, fetchPolicy: 'cache-first' });
            }, 10);
          });
        }
        if (handleCount === 2) {
          expect(result.data).toEqual(data2);
          resolve();
        }
      });
    });
  }


(resolve, reject) => {
      const query = gql`
        {
          test
        }
      `;
      const data = { test: 'ok' };
      const data2 = { test: 'not ok' };

      const link = mockSingleLink({
        request: { query },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({ link, cache: new InMemoryCache() });

      const obs = client.watchQuery({ query, fetchPolicy: 'cache-first' });

      let handleCalled = false;
      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(data);
          obs.setOptions({ query, fetchPolicy: 'standby' }).then(() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
          });
          setTimeout(() => {
            if (!handleCalled) {
              resolve();
            }
          }, 20);
        }
        if (handleCount === 2) {
          handleCalled = true;
          reject(
            new Error('Handle should never be called on standby query'),
          );
        }
      });
    }


(handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(data);
          obs.setOptions({ query, fetchPolicy: 'standby' }).then(() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
          });
          setTimeout(() => {
            if (!handleCalled) {
              resolve();
            }
          }, 20);
        }
        if (handleCount === 2) {
          handleCalled = true;
          reject(
            new Error('Handle should never be called on standby query'),
          );
        }
      }


() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
          }


() => {
            if (!handleCalled) {
              resolve();
            }
          }


(resolve, reject) => {
      const query = gql`
        {
          test
        }
      `;
      const data = { test: 'ok' };
      const data2 = { test: 'not ok' };

      const link = mockSingleLink({
        request: { query },
        result: { data },
      }).setOnError(reject);

      const client = new ApolloClient({ link, cache: new InMemoryCache() });

      const obs = client.watchQuery({ query, fetchPolicy: 'cache-first' });

      subscribeAndCount(reject, obs, (handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(data);
          obs.setOptions({ query, fetchPolicy: 'standby' }).then(() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
            setTimeout(() => {
              obs.setOptions({ query, fetchPolicy: 'cache-first' });
            }, 10);
          });
        }
        if (handleCount === 2) {
          expect(result.data).toEqual(data2);
          resolve();
        }
      });
    }


(handleCount, result) => {
        if (handleCount === 1) {
          expect(result.data).toEqual(data);
          obs.setOptions({ query, fetchPolicy: 'standby' }).then(() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
            setTimeout(() => {
              obs.setOptions({ query, fetchPolicy: 'cache-first' });
            }, 10);
          });
        }
        if (handleCount === 2) {
          expect(result.data).toEqual(data2);
          resolve();
        }
      }


() => {
            client.writeQuery({ query, data: data2 });
            // this write should be completely ignored by the standby query
            setTimeout(() => {
              obs.setOptions({ query, fetchPolicy: 'cache-first' });
            }, 10);
          }


() => {
              obs.setOptions({ query, fetchPolicy: 'cache-first' });
            }


() => {
    const query = gql`
      query number {
        myNumber {
          n
        }
      }
    `;

    const firstFetch = {
      myNumber: {
        n: 1,
      },
    };
    const secondFetch = {
      myNumber: {
        n: 2,
      },
    };

    function makeLink(reject: (reason: any) => any) {
      return mockSingleLink({
        request: { query },
        result: { data: firstFetch },
      }, {
        request: { query },
        result: { data: secondFetch },
      }).setOnError(reject);
    }

    itAsync('forces the query to rerun', (resolve, reject) => {
      const client = new ApolloClient({
        link: makeLink(reject),
        cache: new InMemoryCache({ addTypename: false }),
      });

      // Run a query first to initialize the store
      return client
        .query({ query })
        // then query for real
        .then(() => client.query({ query, fetchPolicy: 'network-only' }))
        .then(result => {
          expect(result.data).toEqual({ myNumber: { n: 2 } });
        })
        .then(resolve, reject);
    });

    itAsync('can be disabled with ssrMode', (resolve, reject) => {
      const client = new ApolloClient({
        link: makeLink(reject),
        ssrMode: true,
        cache: new InMemoryCache({ addTypename: false }),
      });

      const options: QueryOptions = { query, fetchPolicy: 'network-only' };

      // Run a query first to initialize the store
      return client
        .query({ query })
        // then query for real
        .then(() => client.query(options))
        .then(result => {
          expect(result.data).toEqual({ myNumber: { n: 1 } });
          // Test that options weren't mutated, issue #339
          expect(options).toEqual({
            query,
            fetchPolicy: 'network-only',
          });
        })
        .then(resolve, reject);
    });

    itAsync('can temporarily be disabled with ssrForceFetchDelay', (resolve, reject) => {
      const client = new ApolloClient({
        link: makeLink(reject),
        ssrForceFetchDelay: 100,
        cache: new InMemoryCache({ addTypename: false }),
      });

      // Run a query first to initialize the store
      return client
        .query({ query })
        // then query for real
        .then(() => {
          return client.query({ query, fetchPolicy: 'network-only' });
        })
        .then(async result => {
          expect(result.data).toEqual({ myNumber: { n: 1 } });
          await new Promise(resolve => setTimeout(resolve, 100));
          return client.query({ query, fetchPolicy: 'network-only' });
        })
        .then(result => {
          expect(result.data).toEqual({ myNumber: { n: 2 } });
        })
        .then(resolve, reject);
    });
  }


(resolve, reject) => {
      const client = new ApolloClient({
        link: makeLink(reject),
        cache: new InMemoryCache({ addTypename: false }),
      });

      // Run a query first to initialize the store
      return client
        .query({ query })
        // then query for real
        .then(() => client.query({ query, fetchPolicy: 'network-only' }))
        .then(result => {
          expect(result.data).toEqual({ myNumber: { n: 2 } });
        })
        .then(resolve, reject);
    }


() => client.query({ query, fetchPolicy: 'network-only' })


result => {
          expect(result.data).toEqual({ myNumber: { n: 2 } });
        }


(resolve, reject) => {
      const client = new ApolloClient({
        link: makeLink(reject),
        ssrMode: true,
        cache: new InMemoryCache({ addTypename: false }),
      });

      const options: QueryOptions = { query, fetchPolicy: 'network-only' };

      // Run a query first to initialize the store
      return client
        .query({ query })
        // then query for real
        .then(() => client.query(options))
        .then(result => {
          expect(result.data).toEqual({ myNumber: { n: 1 } });
          // Test that options weren't mutated, issue #339
          expect(options).toEqual({
            query,
            fetchPolicy: 'network-only',
          });
        })
        .then(resolve, reject);
    }


() => client.query(options)


result => {
          expect(result.data).toEqual({ myNumber: { n: 1 } });
          // Test that options weren't mutated, issue #339
          expect(options).toEqual({
            query,
            fetchPolicy: 'network-only',
          });
        }


(resolve, reject) => {
      const client = new ApolloClient({
        link: makeLink(reject),
        ssrForceFetchDelay: 100,
        cache: new InMemoryCache({ addTypename: false }),
      });

      // Run a query first to initialize the store
      return client
        .query({ query })
        // then query for real
        .then(() => {
          return client.query({ query, fetchPolicy: 'network-only' });
        })
        .then(async result => {
          expect(result.data).toEqual({ myNumber: { n: 1 } });
          await new Promise(resolve => setTimeout(resolve, 100));
          return client.query({ query, fetchPolicy: 'network-only' });
        })
        .then(result => {
          expect(result.data).toEqual({ myNumber: { n: 2 } });
        })
        .then(resolve, reject);
    }


() => {
          return client.query({ query, fetchPolicy: 'network-only' });
        }


async result => {
          expect(result.data).toEqual({ myNumber: { n: 1 } });
          await new Promise(resolve => setTimeout(resolve, 100));
          return client.query({ query, fetchPolicy: 'network-only' });
        }


(resolve, reject) => {
    const mutation = gql`
      mutation {
        person {
          firstName
          lastName
        }
      }
    `;
    const data = {
      person: {
        firstName: 'John',
        lastName: 'Smith',
      },
    };
    const networkError = new Error('Some kind of network error.');
    const client = new ApolloClient({
      link: mockSingleLink({
        request: { query: mutation },
        result: { data },
        error: networkError,
      }),
      cache: new InMemoryCache({ addTypename: false }),
    });

    client
      .mutate({ mutation })
      .then(_ => {
        reject(new Error('Returned a result when it should not have.'));
      })
      .catch((error: ApolloError) => {
        expect(error.networkError).toBeDefined();
        expect(error.networkError!.message).toBe(networkError.message);
        resolve();
      });
  }


_ => {
        reject(new Error('Returned a result when it should not have.'));
      }


(error: ApolloError) => {
        expect(error.networkError).toBeDefined();
        expect(error.networkError!.message).toBe(networkError.message);
        resolve();
      }


(resolve, reject) => {
    const mutation = gql`
      mutation {
        newPerson {
          person {
            firstName
            lastName
          }
        }
      }
    `;
    const data = {
      person: {
        firstName: 'John',
        lastName: 'Smith',
      },
    };
    const errors = [new Error('Some kind of GraphQL error.')];
    const client = new ApolloClient({
      link: mockSingleLink({
        request: { query: mutation },
        result: { data, errors },
      }).setOnError(reject),
      cache: new InMemoryCache({ addTypename: false }),
    });
    client
      .mutate({ mutation })
      .then(_ => {
        reject(new Error('Returned a result when it should not have.'));
      })
      .catch((error: ApolloError) => {
        expect(error.graphQLErrors).toBeDefined();
        expect(error.graphQLErrors.length).toBe(1);
        expect(error.graphQLErrors[0].message).toBe(errors[0].message);
        resolve();
      });
  }


(error: ApolloError) => {
        expect(error.graphQLErrors).toBeDefined();
        expect(error.graphQLErrors.length).toBe(1);
        expect(error.graphQLErrors[0].message).toBe(errors[0].message);
        resolve();
      }


(resolve, reject) => {
    const mutation = gql`
      mutation {
        newPerson {
          person {
            firstName
            lastName
          }
        }
      }
    `;
    const data = {
      person: {
        firstName: 'John',
        lastName: 'Smith',
      },
    };
    const errors = [new Error('Some kind of GraphQL error.')];
    const client = new ApolloClient({
      link: mockSingleLink({
        request: { query: mutation },
        result: {
          errors,
          data: {
            newPerson: data,
          },
        },
      }).setOnError(reject),
      cache: new InMemoryCache({ addTypename: false }),
    });
    client
      .mutate({ mutation, errorPolicy: 'all' })
      .then(result => {
        expect(result.errors).toBeDefined();
        expect(result.errors!.length).toBe(1);
        expect(result.errors![0].message).toBe(errors[0].message);
        expect(result.data).toEqual({
          newPerson: data,
        });
        resolve();
      })
      .catch((error: ApolloError) => {
        throw error;
      });
  }


result => {
        expect(result.errors).toBeDefined();
        expect(result.errors!.length).toBe(1);
        expect(result.errors![0].message).toBe(errors[0].message);
        expect(result.data).toEqual({
          newPerson: data,
        });
        resolve();
      }


(error: ApolloError) => {
        throw error;
      }


(resolve, reject) => {
    const mutation = gql`
      mutation {
        newPerson {
          person {
            firstName
            lastName
          }
        }
      }
    `;
    const data = {
      newPerson: {
        person: {
          firstName: 'John',
          lastName: 'Smith',
        },
      },
    };
    const errors = [new Error('Some kind of GraphQL error.')];
    const client = new ApolloClient({
      link: mockSingleLink({
        request: { query: mutation },
        result: { data, errors },
      }).setOnError(reject),
      cache: new InMemoryCache({ addTypename: false }),
    });
    client
      .mutate({ mutation, errorPolicy: 'ignore' })
      .then(result => {
        expect(result.errors).toBeUndefined();
        expect(result.data).toEqual(data);
        resolve();
      })
      .catch((error: ApolloError) => {
        throw error;
      });
  }


result => {
        expect(result.errors).toBeUndefined();
        expect(result.data).toEqual(data);
        resolve();
      }


(resolve, reject) => {
    const mutation = gql`
      mutation {
        newPerson {
          person {
            firstName
            lastName
          }
        }
      }
    `;
    const data = {
      newPerson: {
        person: {
          firstName: 'John',
          lastName: 'Smith',
        },
      },
    };
    const errors = [new Error('Some kind of GraphQL error.')];
    const client = new ApolloClient({
      link: mockSingleLink({
        request: { query: mutation },
        result: { data, errors },
      }).setOnError(reject),
      cache: new InMemoryCache({ addTypename: false }),
    });
    const mutatePromise = client.mutate({
      mutation,
      optimisticResponse: {
        newPerson: {
          person: {
            firstName: 'John*',
            lastName: 'Smith*',
          },
        },
      },
    });

    {
      const { data, optimisticData } = client.cache as any;
      expect(optimisticData).not.toBe(data);
      expect(optimisticData.parent).toBe(data.stump);
      expect(optimisticData.parent.parent).toBe(data);
    }

    mutatePromise
      .then(_ => {
        reject(new Error('Returned a result when it should not have.'));
      })
      .catch((_: ApolloError) => {
        const { data, optimisticData } = client.cache as any;
        expect(optimisticData).toBe(data.stump);
        resolve();
      });
  }


(_: ApolloError) => {
        const { data, optimisticData } = client.cache as any;
        expect(optimisticData).toBe(data.stump);
        resolve();
      }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    // @ts-ignore
    const spy = jest.spyOn(client.queryManager, 'clearStore');
    await client.clearStore();
    expect(spy).toHaveBeenCalled();
  }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    const onClearStore = jest.fn();
    client.onClearStore(onClearStore);

    await client.clearStore();

    expect(onClearStore).toHaveBeenCalled();
  }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    const onClearStore = jest.fn();
    const unsubscribe = client.onClearStore(onClearStore);

    unsubscribe();

    await client.clearStore();
    expect(onClearStore).not.toHaveBeenCalled();
  }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    // @ts-ignore
    const spy = jest.spyOn(client.queryManager, 'clearStore');
    await client.resetStore();
    expect(spy).toHaveBeenCalled();
  }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    const onResetStore = jest.fn();
    client.onResetStore(onResetStore);

    await client.resetStore();

    expect(onResetStore).toHaveBeenCalled();
  }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    const onResetStore = jest.fn();
    const unsubscribe = client.onResetStore(onResetStore);

    unsubscribe();

    await client.resetStore();
    expect(onResetStore).not.toHaveBeenCalled();
  }


async () => {
    const delay = (time: number) => new Promise(r => setTimeout(r, time));

    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    let count = 0;
    const onResetStoreOne = jest.fn(async () => {
      expect(count).toEqual(0);
      await delay(10).then(() => count++);
      expect(count).toEqual(1);
    });

    const onResetStoreTwo = jest.fn(async () => {
      expect(count).toEqual(0);
      await delay(11).then(() => count++);
      expect(count).toEqual(2);
    });

    client.onResetStore(onResetStoreOne);
    client.onResetStore(onResetStoreTwo);

    expect(count).toEqual(0);
    await client.resetStore();
    expect(count).toEqual(2);
  }


(time: number) => new Promise(r => setTimeout(r, time))


r => setTimeout(r, time)


async () => {
      expect(count).toEqual(0);
      await delay(10).then(() => count++);
      expect(count).toEqual(1);
    }


() => count++


async () => {
      expect(count).toEqual(0);
      await delay(11).then(() => count++);
      expect(count).toEqual(2);
    }


async (resolve, reject) => {
    const delay = (time: number) => new Promise(r => setTimeout(r, time));

    const query = gql`
      query {
        author {
          firstName
          lastName
        }
      }
    `;

    const data = {
      author: {
        __typename: 'Author',
        firstName: 'John',
        lastName: 'Smith',
      },
    };

    const data2 = {
      author: {
        __typename: 'Author',
        firstName: 'Joe',
        lastName: 'Joe',
      },
    };

    const link = ApolloLink.from([
      new ApolloLink(
        () =>
          new Observable(observer => {
            observer.next({ data });
            observer.complete();
            return;
          }),
      ),
    ]);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache(),
    });

    let count = 0;
    const onResetStoreOne = jest.fn(async () => {
      expect(count).toEqual(0);
      await delay(10).then(() => count++);
      expect(count).toEqual(1);
    });

    const onResetStoreTwo = jest.fn(async () => {
      expect(count).toEqual(0);
      await delay(11).then(() => count++);
      expect(count).toEqual(2);
      expect(client.readQuery({ query })).toBe(null);
      client.cache.writeQuery({ query, data: data2 });
    });

    client.onResetStore(onResetStoreOne);
    client.onResetStore(onResetStoreTwo);

    let called = false;
    const next = jest.fn(d => {
      if (called) {
        expect(onResetStoreOne).toHaveBeenCalled();
      } else {
        expect(d.data).toEqual(data);
        called = true;
      }
    });

    client
      .watchQuery<any>({
        query,
        notifyOnNetworkStatusChange: false,
      })
      .subscribe({
        next,
        error: reject,
        complete: reject,
      });

    expect(count).toEqual(0);
    await client.resetStore();
    expect(count).toEqual(2);
    //watchQuery should only receive data twice
    expect(next).toHaveBeenCalledTimes(2);

    resolve();
  }


() =>
          new Observable(observer => {
            observer.next({ data });
            observer.complete();
            return;
          })


observer => {
            observer.next({ data });
            observer.complete();
            return;
          }


async () => {
      expect(count).toEqual(0);
      await delay(11).then(() => count++);
      expect(count).toEqual(2);
      expect(client.readQuery({ query })).toBe(null);
      client.cache.writeQuery({ query, data: data2 });
    }


d => {
      if (called) {
        expect(onResetStoreOne).toHaveBeenCalled();
      } else {
        expect(d.data).toEqual(data);
        called = true;
      }
    }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    // @ts-ignore
    const spy = jest.spyOn(client.queryManager, 'reFetchObservableQueries');
    await client.reFetchObservableQueries();
    expect(spy).toHaveBeenCalled();
  }


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    const spy = jest.spyOn(client['queryManager'], 'refetchQueries');
    spy.mockImplementation(() => new Map);

    const options = { include: ['Author1'] };
    await client.refetchQueries(options);

    expect(spy).toHaveBeenCalledWith(options);
  }


() => new Map


async () => {
    const client = new ApolloClient({
      link: ApolloLink.empty(),
      cache: new InMemoryCache(),
    });

    // @ts-ignore
    const spy = jest.spyOn(client.queryManager, 'getObservableQueries');
    await client.getObservableQueries();
    expect(spy).toHaveBeenCalled();
  }


(resolve, reject) => {
    const link = ApolloLink.from([
      () =>
        new Observable(x => {
          x.error(new Error('Uh oh!'));
          return;
        }),
    ]);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    const handle = client.watchQuery({
      query: gql`
        query {
          a
          b
          c
        }
      `,
    });

    handle.subscribe({
      error(error) {
        expect(error.message).toBe('Uh oh!');
        resolve();
      },
    });
  }


() =>
        new Observable(x => {
          x.error(new Error('Uh oh!'));
          return;
        })


x => {
          x.error(new Error('Uh oh!'));
          return;
        }


(resolve, reject) => {
    const query: DocumentNode = gql`
      query somethingelse {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = { allPeople: { people: [{ name: 'Luke Skywalker' }] } };
    const dataTwo = { allPeople: { people: [{ name: 'Princess Leia' }] } };
    const link = mockSingleLink(
      { request: { query }, result: { data } },
      { request: { query }, error: new Error('This is an error!') },
      { request: { query }, result: { data: dataTwo } }
    );
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({ addTypename: false }),
    });

    let count = 0;
    const noop = () => null;

    const observable = client.watchQuery({
      query,
      notifyOnNetworkStatusChange: true,
    });

    let subscription: any = null;

    const observerOptions = {
      next(result: any) {
        try {
          switch (count++) {
            case 0:
              if (!result.data!.allPeople) {
                reject('Should have data by this point');
                break;
              }
              // First result is loaded, run a refetch to get the second result
              // which is an error.
              expect(result.loading).toBeFalsy();
              expect(result.networkStatus).toBe(7);
              expect(result.data!.allPeople).toEqual(
                data.allPeople,
              );
              setTimeout(() => {
                observable.refetch().then(() => {
                  reject('Expected error value on first refetch.');
                }, noop);
              }, 0);
              break;
            case 1:
              // Waiting for the second result to load
              expect(result.loading).toBeTruthy();
              expect(result.networkStatus).toBe(4);
              break;
            // case 2 is handled by the error callback
            case 3:
              expect(result.loading).toBeTruthy();
              expect(result.networkStatus).toBe(4);
              expect(result.errors).toBeFalsy();
              break;
            case 4:
              // Third result's data is loaded
              expect(result.loading).toBeFalsy();
              expect(result.networkStatus).toBe(7);
              expect(result.errors).toBeFalsy();
              if (!result.data) {
                reject('Should have data by this point');
                break;
              }
              expect(result.data.allPeople).toEqual(
                dataTwo.allPeople,
              );
              resolve();
              break;
            default:
              throw new Error('Unexpected fall through');
          }
        } catch (e) {
          reject(e);
        }
      },
      error(error: Error) {
        expect(count++).toBe(2);
        expect(error.message).toBe('This is an error!');

        subscription.unsubscribe();

        const lastError = observable.getLastError();
        expect(lastError).toBeInstanceOf(ApolloError);
        expect(lastError!.networkError).toEqual(error);

        const lastResult = observable.getLastResult();
        expect(lastResult).toBeTruthy();
        expect(lastResult!.loading).toBe(false);
        expect(lastResult!.networkStatus).toBe(8);

        observable.resetLastResults();
        subscription = observable.subscribe(observerOptions);

        // The error arrived, run a refetch to get the third result
        // which should now contain valid data.
        setTimeout(() => {
          observable.refetch().catch(() => {
            reject('Expected good data on second refetch.');
          });
        }, 0);
      },
    };

    subscription = observable.subscribe(observerOptions);
  }


() => {
                observable.refetch().then(() => {
                  reject('Expected error value on first refetch.');
                }, noop);
              }


() => {
                  reject('Expected error value on first refetch.');
                }


() => {
          observable.refetch().catch(() => {
            reject('Expected good data on second refetch.');
          });
        }


() => {
            reject('Expected good data on second refetch.');
          }


(resolve, reject) => {
    const query = gql`
      query {
        posts {
          foo
          __typename
        }
      }
    `;
    const errors: GraphQLError[] = [
        new GraphQLError('Cannot query field "foo" on type "Post".')
    ];
    const link = mockSingleLink({
      request: { query },
      result: { errors },
    }).setOnError(reject);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache(),
    });

    return client.query({ query }).catch(err => {
      expect(err.message).toBe(
        'Cannot query field "foo" on type "Post".',
      );
    }).then(resolve, reject);
  }


err => {
      expect(err.message).toBe(
        'Cannot query field "foo" on type "Post".',
      );
    }


(resolve, reject) => {
    const query = gql`
      query {
        todos {
          id
          name
          description
          __typename
        }
      }
    `;
    const result = {
      data: {
        todos: [
          {
            id: '1',
            name: 'Todo 1',
            price: 100,
            __typename: 'Todo',
          },
        ],
      },
    };

    const link = mockSingleLink({
      request: { query },
      result,
    }).setOnError(reject);
    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({
        // Passing an empty map enables the warning:
        possibleTypes: {},
      }),
    });

    return client.query({ query }).then(({ data }) => {
      expect(data).toEqual(result.data);
    }).then(resolve, reject);
  }


({ data }) => {
      expect(data).toEqual(result.data);
    }


(resolve, reject) => {
    const query = gql`
      {
        books(skip: 0, limit: 2) @connection(key: "abc") {
          name
        }
      }
    `;

    const transformedQuery = gql`
      {
        books(skip: 0, limit: 2) {
          name
          __typename
        }
      }
    `;

    const result = {
      books: [
        {
          name: 'abcd',
          __typename: 'Book',
        },
      ],
    };

    const link = mockSingleLink({
      request: { query: transformedQuery },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache(),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


(resolve, reject) => {
    const query = gql`
      {
        books(skip: 0, limit: 2) {
          name
        }
      }
    `;

    const transformedQuery = gql`
      {
        books(skip: 0, limit: 2) {
          name
          __typename
        }
      }
    `;

    const result = {
      books: [
        {
          name: 'abcd',
          __typename: 'Book',
        },
      ],
    };

    const link = mockSingleLink({
      request: { query: transformedQuery },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({
        typePolicies: {
          Query: {
            fields: {
              books: {
                keyArgs: () => "abc",
              },
            },
          },
        },
      }),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


() => "abc"


(resolve, reject) => {
    const query = gql`
      {
        books(skip: 0, limit: 2) @connection(key: "books") {
          name
        }
      }
    `;

    const transformedQuery = gql`
      {
        books(skip: 0, limit: 2) {
          name
          __typename
        }
      }
    `;

    const result = {
      books: [
        {
          name: 'abcd',
          __typename: 'Book',
        },
      ],
    };

    const link = mockSingleLink({
      request: { query: transformedQuery },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache(),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
    }).then(resolve, reject);
  }


(resolve, reject) => {
    const query = gql`
      {
        books(skip: 0, limit: 2) @connection(key: "abc") {
          name
        }
      }
    `;

    const transformedQuery = gql`
      {
        books(skip: 0, limit: 2) {
          name
          __typename
        }
      }
    `;

    const result = {
      books: [
        {
          name: 'abcd',
          __typename: 'Book',
        },
      ],
    };

    const link = mockSingleLink({
      request: { query: transformedQuery },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache(),
    });

    return client.query({ query }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
      expect((client.cache as InMemoryCache).extract()).toMatchSnapshot();
    }).then(resolve, reject);
  }


actualResult => {
      expect(actualResult.data).toEqual(result);
      expect((client.cache as InMemoryCache).extract()).toMatchSnapshot();
    }


(resolve, reject) => {
    const query = gql`
      query books($order: string) {
        books(skip: 0, limit: 2, order: $order)
          @connection(key: "abc", filter: ["order"]) {
          name
        }
      }
    `;
    const transformedQuery = gql`
      query books($order: string) {
        books(skip: 0, limit: 2, order: $order) {
          name
          __typename
        }
      }
    `;

    const result = {
      books: [
        {
          name: 'abcd',
          __typename: 'Book',
        },
      ],
    };

    const variables = { order: 'popularity' };

    const link = mockSingleLink({
      request: { query: transformedQuery, variables },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache(),
    });

    return client.query({ query, variables }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
      expect((client.cache as InMemoryCache).extract()).toMatchSnapshot();
    }).then(resolve, reject);
  }


(resolve, reject) => {
    const query = gql`
      query books($order: string) {
        books(skip: 0, limit: 2, order: $order) {
          name
        }
      }
    `;
    const transformedQuery = gql`
      query books($order: string) {
        books(skip: 0, limit: 2, order: $order) {
          name
          __typename
        }
      }
    `;

    const result = {
      books: [
        {
          name: 'abcd',
          __typename: 'Book',
        },
      ],
    };

    const variables = { order: 'popularity' };

    const link = mockSingleLink({
      request: { query: transformedQuery, variables },
      result: { data: result },
    }).setOnError(reject);

    const client = new ApolloClient({
      link,
      cache: new InMemoryCache({
        typePolicies: {
          Query: {
            fields: {
              books: {
                keyArgs: ["order"],
              }
            }
          }
        }
      }),
    });

    return client.query({ query, variables }).then(actualResult => {
      expect(actualResult.data).toEqual(result);
      expect((client.cache as InMemoryCache).extract()).toMatchSnapshot();
    }).then(resolve, reject);
  }


async (resolve, reject) => {
    const aVar = makeVar(123);
    const bVar = makeVar("asdf");
    const cache: InMemoryCache = new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            a() {
              return aVar();
            },
            b() {
              return bVar();
            },
          },
        },
      },
    });

    const client = new ApolloClient({ cache });

    const obsQueries = new Set<ObservableQuery<any>>();
    const subs = new Set<ObservableSubscription>();
    function watch(
      query: DocumentNode,
      fetchPolicy: WatchQueryFetchPolicy = "cache-first",
    ): any[] {
      const results: any[] = [];
      const obsQuery = client.watchQuery({
        query,
        fetchPolicy,
      });
      obsQueries.add(obsQuery);
      subs.add(obsQuery.subscribe({
        next(result) {
          results.push(result.data);
        },
      }));
      return results;
    }

    const aResults = watch(gql`{ a }`);
    const bResults = watch(gql`{ b }`);
    const abResults = watch(gql`{ a b }`);

    await wait();

    function checkLastResult(
      results: any[],
      expectedData: Record<string, any>,
    ) {
      const lastResult = results[results.length - 1];
      expect(lastResult).toEqual(expectedData);
      return lastResult;
    }

    checkLastResult(aResults, { a: 123 });
    const bAsdf = checkLastResult(bResults, { b: "asdf" });
    checkLastResult(abResults, { a: 123, b: "asdf" });

    aVar(aVar() + 111);
    await wait();

    const a234 = checkLastResult(aResults, { a: 234 });
    expect(checkLastResult(bResults, { b: "asdf" })).toBe(bAsdf);
    checkLastResult(abResults, { a: 234, b: "asdf" });

    bVar(bVar().toUpperCase());
    await wait();

    expect(checkLastResult(aResults, { a: 234 })).toBe(a234);
    checkLastResult(bResults, { b: "ASDF" });
    checkLastResult(abResults, { a: 234, b: "ASDF" });

    aVar(aVar() + 222);
    bVar("oyez");
    await wait();

    const a456 = checkLastResult(aResults, { a: 456 });
    const bOyez = checkLastResult(bResults, { b: "oyez" });
    const a456bOyez = checkLastResult(abResults, { a: 456, b: "oyez" });

    // Since the ObservableQuery skips results that are the same as the
    // previous result, and nothing is actually changing about the
    // ROOT_QUERY.a field, clear previous results to give the invalidated
    // results a chance to be delivered.
    obsQueries.forEach(obsQuery => obsQuery.resetLastResults());
    await wait();
    // Verify that resetting previous results did not trigger the delivery
    // of any new results, by itself.
    expect(checkLastResult(aResults, a456)).toBe(a456);
    expect(checkLastResult(bResults, bOyez)).toBe(bOyez);
    expect(checkLastResult(abResults, a456bOyez)).toBe(a456bOyez);

    // Now invalidate the ROOT_QUERY.a field.
    client.cache.evict({ fieldName: "a" });
    await wait();

    expect(checkLastResult(aResults, a456)).toBe(a456);
    expect(checkLastResult(bResults, bOyez)).toBe(bOyez);
    expect(checkLastResult(abResults, a456bOyez)).toBe(a456bOyez);

    const cQuery = gql`{ c }`;
    // Passing cache-only as the fetchPolicy allows the { c: "see" }
    // result to be delivered even though networkStatus is still loading.
    const cResults = watch(cQuery, "cache-only");

    // Now try writing directly to the cache, rather than calling
    // client.writeQuery.
    client.cache.writeQuery({
      query: cQuery,
      data: {
        c: "see",
      },
    });
    await wait();

    checkLastResult(aResults, a456);
    checkLastResult(bResults, bOyez);
    checkLastResult(abResults, a456bOyez);
    checkLastResult(cResults, { c: "see" });

    cache.modify({
      fields: {
        c(value) {
          expect(value).toBe("see");
          return "saw";
        },
      },
    });
    await wait();

    checkLastResult(aResults, a456);
    checkLastResult(bResults, bOyez);
    checkLastResult(abResults, a456bOyez);
    checkLastResult(cResults, { c: "saw" });

    client.cache.evict({ fieldName: "c" });
    await wait();

    checkLastResult(aResults, a456);
    checkLastResult(bResults, bOyez);
    checkLastResult(abResults, a456bOyez);
    expect(checkLastResult(cResults, {}));

    expect(aResults).toEqual([
      { a: 123 },
      { a: 234 },
      { a: 456 },
    ]);

    expect(bResults).toEqual([
      { b: "asdf" },
      { b: "ASDF" },
      { b: "oyez" },
    ]);

    expect(abResults).toEqual([
      { a: 123, b: "asdf" },
      { a: 234, b: "asdf" },
      { a: 234, b: "ASDF" },
      { a: 456, b: "oyez" },
    ]);

    expect(cResults).toEqual([
      {},
      { c: "see" },
      { c: "saw" },
      {},
    ]);

    subs.forEach(sub => sub.unsubscribe());

    resolve();
  }


obsQuery => obsQuery.resetLastResults()


resolve => setTimeout(resolve, time)