Repository: FormidableLabs/urql
Pull request #139 (2018-11-30 11:10:38)

Maintenance - clean up remaining types, dependencies and libs


Patch:
diff --git a/.travis.yml b/.travis.yml
index 27f19105..9f13d20f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,8 +3,9 @@ dist: trusty
 language: node_js
 
 node_js:
-  - "6"
-  - "8"
+  - '6'
+  - '8'
+  - '10'
 
 # Use container-based Travis infrastructure.
 sudo: false
@@ -19,10 +20,9 @@ cache: yarn
 script:
   # Run tests
   - yarn run lint
-  - yarn run test
-  - yarn run coverage
+  - yarn run test --coverage
   # Upload to coveralls, but don't _fail_ if coveralls is down.
   - cat coverage/lcov.info | node_modules/.bin/coveralls || echo "Coveralls upload failed"
   # Build and check bundlesize
-  - yarn run build-bundles
+  - yarn run build
   - yarn run bundlesize
diff --git a/README.md b/README.md
index 482c8ac8..6ddebbb2 100644
--- a/README.md
+++ b/README.md
@@ -21,8 +21,8 @@ Universal React Query Library
     * [Props](#props)
     * [Render Args](#render-args)
   * [ConnectHOC](#connecthoc)
-  * [query](#query)
-  * [mutation](#mutation)
+  * [createQuery](#createQuery)
+  * [createMutation](#createMutation)
   * [CombinedError](#combinederror)
   * [Exchanges](#exchanges)
 * [Prior Art](#prior-art)
@@ -122,9 +122,9 @@ Now we can use the `mutation` and `query` functions to format them in the way `u
 ```javascript
 const Home = () => (
   <Connect
-    query={query(TodoQuery)}
+    query={createQuery(TodoQuery)}
     mutation={{
-      addTodo: mutation(AddTodo),
+      addTodo: createMutation(AddTodo),
     }}
     children={({ loaded, fetching, refetch, data, error, addTodo }) => {
       //...Your Component
@@ -138,9 +138,9 @@ You can also use functional child style:
 ```javascript
 const Home = () => (
   <Connect
-    query={query(TodoQuery)}
+    query={createQuery(TodoQuery)}
     mutation={{
-      addTodo: mutation(AddTodo),
+      addTodo: createMutation(AddTodo),
     }}
   >
     {({ loaded, fetching, refetch, data, error, addTodo }) => {
@@ -163,12 +163,12 @@ Also, any mutations, because they are named, are also passed into this render pr
 
 As you can see above, the `query` accepts either a single query, or an array of queries. The `mutation` prop accepts an object, with the mutation names as keys.
 
-So why do we use these `query` and `mutation` functions before passing them? Variables, thats why. If you wanted to pass a query with variables, you would construct it like so:
+So why do we use these `createQuery` and `createMutation` functions before passing them? Variables, thats why. If you wanted to pass a query with variables, you would construct it like so:
 
 ```javascript
-import { query } from 'urql';
+import { createQuery } from 'urql';
 
-query(TodoQuery, { myVariable: 5 });
+createQuery(TodoQuery, { myVariable: 5 });
 ```
 
 Similarly, you can pass variables to your mutation. Mutation, however is a bit different, in the sense that it returns a function that you can call with a variable set:
@@ -176,7 +176,7 @@ Similarly, you can pass variables to your mutation. Mutation, however is a bit d
 ```javascript
 import { mutation } from 'urql';
 
-mutation(AddTodo); // No initial variables
+createMutation(AddTodo); // No initial variables
 
 // After you pass 'addTodo' from the render prop to a component:
 
@@ -190,7 +190,7 @@ Normally in `urql`, the cache is aggressively invalidated based upon `__typename
 ```javascript
 const MyComponent = () => (
   <Connect
-    query={query(MyQuery)}
+    query={createQuery(MyQuery)}
     shouldInvalidate={(changedTypenames, typenames, mutationResponse, data) => {
       return data.todos.some(d => d.id === mutationResponse.id);
     }}
@@ -345,7 +345,7 @@ Example:
 
 ```jsx
 <Connect
-  query={query(MyQuery)}
+  query={createQuery(MyQuery)}
   children={({loaded, data}) => {
     return loaded ? <Loading/> : <List data={data.todos}>
   }}
@@ -355,7 +355,7 @@ Example:
 
 <Connect
   mutation={{
-    addTodo: mutation(AddTodo)
+    addTodo: createMutation(AddTodo)
   }}
   children={({ addTodo }) => {
     return <button type="button" onClick={addTodo}>Add Todo</button>
@@ -373,26 +373,26 @@ Example:
 
 ```javascript
 export default ConnectHOC({
-  query: query(TodoQuery)
+  query: createQuery(TodoQuery)
 })(MyComponent);
 
 // or
 
 export default ConnectHOC((props) => {
-  query: query(TodoQuery, { id: props.id })
+  query: createQuery(TodoQuery, { id: props.id })
 })(MyComponent);
 ```
 
-### query
+### createQuery
 
 _(query: string, variables?: object) => {query: string, variables: object}_
 
-`query` is a QueryObject creator.
+`createQuery` is a QueryObject creator.
 
 Example:
 
 ```javascript
-query(
+createQuery(
   `
 query($id: ID!) {
   todos(id: $id) {
@@ -403,16 +403,16 @@ query($id: ID!) {
 );
 ```
 
-### mutation
+### createMutation
 
 _(query: string, variables?: object) => {query: string, variables: object}_
 
-`query` is a MutationObject creator.
+`createMutation` is a MutationObject creator.
 
 Example:
 
 ```javascript
-mutation(
+createMutation(
   `
 mutation($id: ID!) {
   addTodo(id: $id) {
diff --git a/example/src/app/home.tsx b/example/src/app/home.tsx
index fb134d08..1664f2cb 100644
--- a/example/src/app/home.tsx
+++ b/example/src/app/home.tsx
@@ -1,7 +1,7 @@
 /* tslint:disable */
 
 import * as React from 'react';
-import { Connect, query, mutation } from '../../../src/';
+import { Connect, createQuery, createMutation } from '../../../src/';
 import TodoList from './todo-list';
 import TodoForm from './todo-form';
 import Loading from './loading';
@@ -20,10 +20,10 @@ export interface ITodoMutations {
 
 const Home: React.SFC<{}> = () => (
   <Connect
-    query={query(TodoQuery)}
+    query={createQuery(TodoQuery)}
     mutation={{
-      addTodo: mutation(AddTodo),
-      removeTodo: mutation(RemoveTodo),
+      addTodo: createMutation(AddTodo),
+      removeTodo: createMutation(RemoveTodo),
     }}
     children={({ data, mutations, fetching, refetch }) => {
       return (
diff --git a/package.json b/package.json
index a08951a4..48507c44 100644
--- a/package.json
+++ b/package.json
@@ -7,16 +7,15 @@
   "module": "dist/index.mjs",
   "source": "src/index.ts",
   "scripts": {
-    "coverage": "jest --coverage",
+    "build": "npm run build:clean && npm run build:bundle",
+    "build:bundle": "microbundle build --no-sourcemap --target web",
     "build:clean": "rimraf dist",
     "build:ts": "tsc",
-    "build": "npm run build:clean && npm run build:ts",
     "demo:start:graphql-server": "node example/src/server/index.js",
     "demo:start:app": "webpack-dev-server --hot --inline --config \"example/webpack.config.js\"",
     "demo:start": "builder concurrent demo:start:app demo:start:graphql-server",
     "lint": "tslint --project .",
     "test": "jest",
-    "bundle": "microbundle build --no-sourcemap --target web",
     "bundlesize": "bundlesize",
     "prettier": "prettier --write \"{,!(node_modules|custom-typings|types)/**/}*.{js,jsx,ts,tsx,json,md}\"",
     "precommit": "lint-staged"
diff --git a/src/components/index.ts b/src/components/index.ts
index 3c9bd84e..451cf378 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -1,5 +1,5 @@
-export * from './client';
-export * from './connect-hoc';
-export * from './connect';
-export * from './context';
-export * from './provider';
+export { ClientState, ClientProps, UrqlClient } from './client';
+export { ConnectHOC, ConnectHOCProps } from './connect-hoc';
+export { Connect, ConnectProps } from './connect';
+export { ContextConsumer, ContextProvider } from './context';
+export { Provider, ProviderProps } from './provider';
diff --git a/src/components/newClient.tsx b/src/components/newClient.tsx
deleted file mode 100644
index 4e80ffaa..00000000
--- a/src/components/newClient.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import { Component, ReactNode } from 'react';
-import {
-  Client,
-  Query,
-  Mutation,
-  ClientInstance,
-  StreamUpdate,
-} from '../types';
-import { CombinedError } from '../lib';
-
-export interface ClientProps {
-  client: Client;
-  children: (obj: object) => ReactNode;
-  query?: Query;
-  mutation?: {
-    [key: string]: Mutation;
-  };
-}
-
-interface ClientState {
-  client: ClientInstance;
-  fetching: boolean;
-  error: Error | CombinedError | CombinedError[];
-  data: object | object[] | ClientState;
-  mutations: {
-    [key: string]: (vals: any) => void;
-  };
-}
-
-export class UrqlClient extends Component<ClientProps, ClientState> {
-  constructor(props: ClientProps) {
-    super(props);
-
-    this.state = {
-      client: props.client.createInstance({
-        onChange: result => this.onStreamUpdate(result),
-      }),
-      data: null,
-      error: null,
-      fetching: false,
-      mutations: null,
-    };
-
-    this.createMutatorFunctions();
-  }
-
-  public componentDidUpdate(prevProps) {
-    if (prevProps.mutation !== this.props.mutation) {
-      this.createMutatorFunctions();
-    }
-
-    if (prevProps.query !== this.props.query) {
-      this.state.client.executeQuery(this.props.query);
-    }
-  }
-
-  public componentWillUnmount() {
-    this.state.client.unsubscribe();
-  }
-
-  public render() {
-    if (typeof this.props.children !== 'function') {
-      return null;
-    }
-
-    return this.props.children({
-      fetching: this.state.fetching,
-      error: this.state.error,
-      data: this.state.data,
-      mutations: this.state.mutations,
-    });
-  }
-
-  private createMutatorFunctions() {
-    if (this.props.mutation === undefined) {
-      return;
-    }
-
-    let mutations = {};
-
-    Object.keys(this.props.mutation).forEach(key => {
-      mutations = {
-        ...mutations,
-        [key]: (variables: any) =>
-          this.state.client.executeMutation({
-            ...this.props.mutation[key],
-            variables,
-          }),
-      };
-    });
-
-    this.setState({ mutations });
-  }
-
-  private onStreamUpdate(updated: StreamUpdate) {
-    this.setState({
-      fetching: updated.fetching,
-      error: updated.error,
-      data: updated.data,
-    });
-  }
-}
diff --git a/src/exchanges/cache.ts b/src/exchanges/cache.ts
index 47e75424..f2f879be 100755
--- a/src/exchanges/cache.ts
+++ b/src/exchanges/cache.ts
@@ -1,7 +1,7 @@
 import { Subject, Observable, of } from 'rxjs';
 import { tap, map, mergeMap } from 'rxjs/operators';
 import { Operation, ExchangeResult, Exchange } from '../types';
-import { gankTypeNamesFromResponse, formatTypeNames } from '../lib/typenames';
+import { gankTypeNamesFromResponse, formatTypeNames } from '../lib';
 
 export const cacheExchange: Exchange = ({ forward, subject }) => {
   const cache = new Map<string, ExchangeResult>();
diff --git a/src/exchanges/index.ts b/src/exchanges/index.ts
index 5474a456..76196e1c 100644
--- a/src/exchanges/index.ts
+++ b/src/exchanges/index.ts
@@ -1,4 +1,3 @@
 export { cacheExchange } from './cache';
-export * from './dedup';
-export * from './fetch';
-export * from './subscription';
+export { dedupeExchange } from './dedup';
+export { fetchExchange } from './fetch';
diff --git a/src/exchanges/subscription.ts b/src/exchanges/subscription.ts
deleted file mode 100755
index 40e9b147..00000000
--- a/src/exchanges/subscription.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import Observable from 'zen-observable-ts';
-
-import {
-  Exchange,
-  ExchangeResult,
-  Subscription,
-  SubscriptionObserver,
-  Operation,
-} from '../types';
-
-import { CombinedError } from '../lib';
-
-export const subscriptionExchange = (
-  createSubscription: (
-    operation: Operation,
-    subObserver: SubscriptionObserver
-  ) => Subscription,
-  forward: Exchange
-): Exchange => {
-  return operation => {
-    const { operationName } = operation;
-
-    // Forward non-subscription operations
-    if (operationName !== 'subscription') {
-      return forward(operation);
-    }
-
-    // Take over subscription operations and call `createSubscription`
-    return new Observable<ExchangeResult>(observer => {
-      const subObserver: SubscriptionObserver = {
-        error: networkError => {
-          observer.error(new CombinedError({ networkError }));
-        },
-        next: raw => {
-          const result: ExchangeResult = { operation, data: raw.data };
-          if (Array.isArray(raw.errors)) {
-            result.error = new CombinedError({ graphQLErrors: raw.errors });
-          }
-
-          observer.next(result);
-        },
-      };
-
-      const sub = createSubscription(operation, subObserver);
-
-      return () => {
-        sub.unsubscribe();
-      };
-    });
-  };
-};
diff --git a/src/exchanges/subscriptionnew.ts b/src/exchanges/subscriptionnew.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/index.ts b/src/index.ts
index 9e54b464..a9d1b188 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,9 @@
 export { Connect, ConnectHOC, Provider } from './components';
-
-export * from './lib';
+export {
+  CombinedError,
+  createQuery,
+  createMutation,
+  createClient,
+} from './lib';
 export * from './exchanges';
 export * from './types';
diff --git a/src/lib/default-cache.ts b/src/lib/default-cache.ts
deleted file mode 100644
index 2ef749a5..00000000
--- a/src/lib/default-cache.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Cache } from '../types';
-
-export const defaultCache = (store: object): Cache => ({
-  invalidate: hash =>
-    new Promise(resolve => {
-      delete store[hash];
-      resolve(hash);
-    }),
-  invalidateAll: () =>
-    new Promise(resolve => {
-      store = {};
-      resolve();
-    }),
-  read: hash =>
-    new Promise(resolve => {
-      resolve(store[hash] || null);
-    }),
-  update: callback =>
-    new Promise(resolve => {
-      if (typeof callback === 'function') {
-        Object.keys(store).forEach(key => {
-          callback(store, key, store[key]);
-        });
-      }
-      resolve();
-    }),
-  write: (hash, data) =>
-    new Promise(resolve => {
-      store[hash] = data;
-      resolve(hash);
-    }),
-});
diff --git a/src/lib/index.ts b/src/lib/index.ts
index c0d1e844..2ac491f2 100644
--- a/src/lib/index.ts
+++ b/src/lib/index.ts
@@ -1,6 +1,5 @@
-export * from './client';
-export * from './default-cache';
-export * from './error';
-export * from './hash';
-export * from './query';
-export * from './typenames';
+export { createClient } from './client';
+export { CombinedError } from './error';
+export { hashString } from './hash';
+export { createQuery, createMutation } from './query';
+export { formatTypeNames, gankTypeNamesFromResponse } from './typenames';
diff --git a/src/lib/query.ts b/src/lib/query.ts
index 28b1e8d7..1eca06ee 100644
--- a/src/lib/query.ts
+++ b/src/lib/query.ts
@@ -1,10 +1,6 @@
-const createQuery = (q: string, vars?: object) => {
-  return {
-    query: q,
-    variables: vars || {},
-  };
-};
+export const createQuery = (q: string, vars?: any) => ({
+  query: q,
+  variables: vars || {},
+});
 
-export const query = createQuery;
-export const mutation = createQuery;
-export const subscription = createQuery;
+export const createMutation = createQuery;
diff --git a/src/types.ts b/src/types.ts
index 0f44a1f3..e99d2beb 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -2,132 +2,126 @@ import { Observable, Subject } from 'rxjs';
 import { CombinedError } from './lib';
 import { ClientState } from './components';
 
-/** A Graphql query */
+/** A Graphql query. */
 export interface Query {
-  /** Graphql query string */
+  /** Graphql query string. */
   query: string;
-  /** Graphql query variables */
+  /** Graphql query variables. */
   variables?: object;
 }
 
-/** A Graphql mutation */
+/** A Graphql mutation. */
 export type Mutation = Query;
 
-/** A Graphql [query]{@link Query} or [mutation]{@link Mutation} accompanied with metadata */
+/** A Graphql [query]{@link Query} or [mutation]{@link Mutation} accompanied with metadata. */
 export interface Operation extends Query {
-  /** Unique identifier of the operation */
+  /** Unique identifier of the operation. */
   key: string;
-  /** The type of Grapqhql operation being executed */
+  /** The type of Grapqhql operation being executed. */
   operationName: string;
-  /** Additional metadata passed to [exchange]{@link Exchange} functions */
+  /** Additional metadata passed to [exchange]{@link Exchange} functions. */
   context: Record<string, any>;
 }
 
 /** Function responsible for listening for streamed [operations]{@link Operation}. */
 export type Exchange = (
   args: {
-    /** Function to call the next [exchange]{@link Exchange} in the chain */
+    /** Function to call the next [exchange]{@link Exchange} in the chain. */
     forward: ExchangeIO;
+    /** Subject from which the stream of [operations]{@link Operation} is created. */
     subject: Subject<Operation>;
   }
 ) => ExchangeIO;
 
-/** Function responsible for receiving an observable [operation]{@link Operation} and returning a [result]{@link ExchangeResult} */
+/** Function responsible for receiving an observable [operation]{@link Operation} and returning a [result]{@link ExchangeResult}. */
 export type ExchangeIO = (
+  /** A stream of operations. */
   ops$: Observable<Operation>
 ) => Observable<ExchangeResult>;
 
-/** Resulting data from an [operation]{@link Operation} */
+/** Resulting data from an [operation]{@link Operation}. */
 export interface ExchangeResult {
-  /** The operation which has been executed */
+  /** The [operation]{@link Operation} which has been executed. */
   operation: Operation;
-  /** The data returned from the Graphql server */
+  /** The data returned from the Graphql server. */
   data: any;
-  /** Any errors resulting from the operation */
+  /** Any errors resulting from the operation. */
   error?: Error | CombinedError;
 }
 
-/** The arguments for the child function of a connector */
+/** The arguments for the child function of a connector. */
 export interface ChildArgs<M> {
+  /** Whether a dependent GraphQL request is currently being fetched. */
   fetching: ClientState<M>['fetching'];
+  /** Any network or GraphQL errors. */
   error: ClientState<M>['error'];
+  /** The data returned from a GraphQL [query]{@link Query} to the server. */
   data: ClientState<M>['data'];
+  /** A collection of functions for executing pre-specified [mutations]{@link Mutation} */
   mutations: ClientState<M>['mutations'];
+  /** Triger a fetch of the pre-specified [query]{@link Query}. */
   refetch: (noCache?: boolean) => void;
 }
 
-export interface Cache {
-  write: (key: string, data: any) => Promise<any>;
-  read: (key: string) => Promise<any>;
-  invalidate: (key: string) => Promise<any>;
-  invalidateAll: () => Promise<any>;
-  update: (
-    callback: (store: any, key: string, value: any) => void
-  ) => Promise<any>;
-}
-
+/** Options for configuring the URQL [client]{@link Client}. */
 export interface ClientOptions {
+  /** Target endpoint URL such as `https://my-target:8080/graphql`. */
   url: string;
+  /** Any additional options to pass to fetch. */
   fetchOptions?: RequestInit | (() => RequestInit);
+  /** An ordered array of Exchanges. */
   exchanges?: Exchange[];
 }
 
+/** The URQL applicaiton-wide client library. */
 export interface Client {
+  /** Creates a client instance for usage by stateful components. */
   createInstance: (opts: CreateClientInstanceOpts) => ClientInstance;
 }
 
+/** An instance of a [client]{@link Client}. */
 export interface ClientInstance {
+  /** Executes a given query. */
   executeQuery: (query: Query, force?: boolean) => void;
+  /** Executes a given mutation. */
   executeMutation: (mutation: Mutation, force?: boolean) => void;
+  /** Removes any [subscriptions]{@link Subscription} created by the client instance. */
   unsubscribe: () => void;
 }
 
+/** A new response/update from the [client]{@link Client} stream. */
 export interface StreamUpdate {
+  /** Any data returned from a [GraphQL]{@link GraphQL} query. */
   data?: ExchangeResult['data'];
+  /** Any errors returned from a [GraphQL]{@link GraphQL} query. */
   error?: ExchangeResult['error'];
+  /** Indicator of whether a query is being executed. */
   fetching: boolean;
 }
 
+/** Arguments for creating a client instance. */
 export interface CreateClientInstanceOpts {
+  /** A callback function for when changes occur. */
   onChange: (data: StreamUpdate) => any;
 }
 
+/** An error from the GraphQL client. */
 export interface GraphQLError {
   message?: string;
 }
 
-export enum ClientEventType {
-  RefreshAll = 'RefreshAll',
-  CacheKeysInvalidated = 'CacheKeysInvalidated',
-}
-
-export interface EventFn {
-  (type: ClientEventType.RefreshAll, payload: void): void;
-  (type: ClientEventType.CacheKeysInvalidated, payload: string[]): void;
-}
-
 // Adapted from: https://github.com/graphql/graphql-js/blob/ae5b163d2e6c124107fa0971f6d838c8a7d29f51/src/execution/execute.js#L105-L114<Paste>
 export interface ExecutionResult {
   errors?: Error[];
   data?: any;
 }
 
+/** A [query]{@link Query} or [mutation]{@link Mutation} with additional metadata for use during transmission. */
 export interface Operation extends Query {
+  /** A unique identifier. */
   key: string;
+  /** The type of operation. */
   operationName: string;
+  /** Additional request-related information. */
   context: Record<string, any>;
 }
-
-export interface Query {
-  query: string;
-  variables?: object;
-}
-
-export interface SubscriptionObserver {
-  next: (IExecutionResult) => void;
-  error: (Error) => void;
-}
-
-export interface Subscription {
-  unsubscribe: () => void;
-}


Test patch:
diff --git a/src/exchanges/subscription.test.ts b/src/exchanges/subscription.test.ts
deleted file mode 100755
index a2876566..00000000
--- a/src/exchanges/subscription.test.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import { Operation } from '../types';
-import { subscriptionExchange } from './subscription';
-import { CombinedError } from '../lib';
-
-describe('subscriptionExchange', () => {
-  beforeEach(() => {
-    jest.resetAllMocks();
-    jest.clearAllMocks();
-    jest.restoreAllMocks();
-  });
-
-  it('ignores non-subscription operations', () => {
-    const forward = jest.fn() as any;
-    const createSubscription = jest.fn() as any;
-    const exchange = subscriptionExchange(createSubscription, forward);
-
-    exchange(({
-      operationName: 'query',
-    } as any) as Operation);
-
-    expect(createSubscription).not.toHaveBeenCalled();
-    expect(forward).toHaveBeenCalled();
-  });
-
-  it('creates a continuous exchange observable with a sub-observer', done => {
-    const exOperation = ({
-      key: 'test',
-      operationName: 'subscription',
-    } as any) as Operation;
-
-    const next = jest.fn();
-    const error = jest.fn();
-    const unsubscribe = jest.fn();
-
-    const createSubscription = (operation, observer) => {
-      expect(operation).toBe(exOperation);
-      expect(observer.next).toBeTruthy();
-      expect(observer.error).toBeTruthy();
-
-      setTimeout(() => {
-        const inputA = { data: 'test' };
-        expect(next).not.toHaveBeenCalled();
-        observer.next(inputA);
-
-        // Inputs are passed through with their data
-        expect(next).toHaveBeenLastCalledWith({
-          ...inputA,
-          operation: expect.any(Object),
-        });
-
-        const inputB = { errors: ['test error'] };
-        observer.next(inputB);
-
-        // Errors on data are "packaged up" in CombinedError
-        expect(next).toHaveBeenLastCalledWith({
-          data: undefined,
-          error: new CombinedError({ graphQLErrors: ['test error'] }),
-          operation: expect.any(Object),
-        });
-
-        expect(error).not.toHaveBeenCalled();
-
-        const inputErr = new Error('test');
-        observer.error(inputErr);
-        // Error emissions are "packaged up" as CombinedError
-        expect(error).toHaveBeenCalledWith(
-          new CombinedError({ networkError: inputErr })
-        );
-
-        done();
-      });
-
-      return { unsubscribe };
-    };
-
-    const exchange = subscriptionExchange(createSubscription, null);
-
-    exchange(exOperation).subscribe({
-      error,
-      next,
-    });
-  });
-
-  it('passes up the unsubscribe into the user’s returned subscription', () => {
-    const exOperation = ({
-      key: 'test',
-      operationName: 'subscription',
-    } as any) as Operation;
-
-    const unsubscribe = jest.fn();
-    const createSubscription = () => ({ unsubscribe });
-    const exchange = subscriptionExchange(createSubscription, null);
-
-    exchange(exOperation)
-      .subscribe(() => {
-        throw new Error('Should not be called');
-      })
-      .unsubscribe();
-
-    expect(unsubscribe).toHaveBeenCalled();
-  });
-});
diff --git a/src/lib/default-cache.test.ts b/src/lib/default-cache.test.ts
deleted file mode 100644
index b486887f..00000000
--- a/src/lib/default-cache.test.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { defaultCache } from './default-cache';
-
-describe('defaultCache', () => {
-  beforeEach(() => {
-    jest.resetAllMocks();
-    jest.clearAllMocks();
-    jest.restoreAllMocks();
-  });
-
-  it('should provide a valid cache by default', done => {
-    const store = { test: 5 };
-    const cache = defaultCache(store);
-
-    Promise.all([
-      cache.invalidateAll(),
-      cache.read('test'),
-      cache.write('test', 5),
-      cache.read('test'),
-      cache.update((acc, key) => {
-        if (key === 'test') {
-          acc[key] = 6;
-        }
-      }),
-      cache.update(null),
-      cache.read('test'),
-      cache.invalidate('test'),
-      cache.read('test'),
-    ]).then(d => {
-      expect(d).toEqual([
-        undefined,
-        null,
-        'test',
-        5,
-        undefined,
-        undefined,
-        6,
-        'test',
-        null,
-      ]);
-
-      done();
-    });
-  });
-});
diff --git a/src/lib/query.test.ts b/src/lib/query.test.ts
index 0ec1eaf8..d6b459b0 100644
--- a/src/lib/query.test.ts
+++ b/src/lib/query.test.ts
@@ -1,13 +1,13 @@
-import { query } from './query';
+import { createQuery } from './query';
 
 describe('query / mutation / subscription', () => {
   it('should return a valid query object', () => {
-    const val = query(`{ todos { id } }`);
+    const val = createQuery(`{ todos { id } }`);
     expect(val).toMatchObject({ query: `{ todos { id } }`, variables: {} });
   });
 
   it('should return a valid query object with variables', () => {
-    const val = query(`{ todos { id } }`, { test: 5 });
+    const val = createQuery(`{ todos { id } }`, { test: 5 });
     expect(val).toMatchObject({
       query: `{ todos { id } }`,
       variables: { test: 5 },