All files / src test-links.ts

92.78% Statements 90/97
86.54% Branches 45/52
78.26% Functions 18/23
95% Lines 76/80

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 17323x                 23x 23x 23x                                       23x 184x 184x   184x 184x 184x 184x 184x 264x       23x 264x 264x 264x 191x 191x   264x     23x 230x   230x 228x 228x 228x 4x   224x 224x     230x 6x             224x   224x   224x 15x 15x     224x       224x 224x 221x 19x   202x 202x       224x 221x       23x   23x   15x 15x         15x     23x 17x 17x 17x 17x 17x         27x 27x 26x 26x 26x 26x       23x       23x     23x       494x   494x   494x           186x   131x 131x   131x 131x 131x     131x     23x      
import {
  Operation,
  GraphQLRequest,
  ApolloLink,
  FetchResult,
  Observable,
  // Observer,
} from 'apollo-link';
 
import { print } from 'graphql/language/printer';
import { addTypenameToDocument } from 'apollo-utilities';
import { isEqual } from 'lodash';
 
export interface MockedResponse {
  request: GraphQLRequest;
  result?: FetchResult;
  error?: Error;
  delay?: number;
  newData?: () => FetchResult;
}
 
export interface MockedSubscriptionResult {
  result?: FetchResult;
  error?: Error;
  delay?: number;
}
 
export interface MockedSubscription {
  request: GraphQLRequest;
}
 
export class MockLink extends ApolloLink {
  public addTypename: Boolean = true;
  private mockedResponsesByKey: { [key: string]: MockedResponse[] } = {};
 
  constructor(mockedResponses: MockedResponse[], IaddTypename: Boolean = true) {
    super();
    this.addTypename = addTypename;
    Eif (mockedResponses)
      mockedResponses.forEach(mockedResponse => {
        this.addMockedResponse(mockedResponse);
      });
  }
 
  public addMockedResponse(mockedResponse: MockedResponse) {
    const key = requestToKey(mockedResponse.request, this.addTypename);
    let mockedResponses = this.mockedResponsesByKey[key];
    if (!mockedResponses) {
      mockedResponses = [];
      this.mockedResponsesByKey[key] = mockedResponses;
    }
    mockedResponses.push(mockedResponse);
  }
 
  public request(operation: Operation) {
    const key = requestToKey(operation, this.addTypename);
    let responseIndex;
    const response = (this.mockedResponsesByKey[key] || []).find((res, index) => {
      const requestVariables = operation.variables || {};
      const mockedResponseVariables = res.request.variables || {};
      if (!isEqual(requestVariables, mockedResponseVariables)) {
        return false;
      }
      responseIndex = index;
      return true;
    });
 
    if (!response || typeof responseIndex === 'undefined') {
      throw new Error(
        `No more mocked responses for the query: ${print(
          operation.query,
        )}, variables: ${JSON.stringify(operation.variables)}`,
      );
    }
 
    this.mockedResponsesByKey[key].splice(responseIndex, 1);
 
    const { result, error, delay, newData } = response;
 
    if (newData) {
      response.result = newData();
      this.mockedResponsesByKey[key].push(response);
    }
 
    Iif (!result && !error) {
      throw new Error(`Mocked response should contain either result or error: ${key}`);
    }
 
    return new Observable<FetchResult>(observer => {
      let timer = setTimeout(() => {
        if (error) {
          observer.error(error);
        } else {
          Eif (result) observer.next(result);
          observer.complete();
        }
      }, delay ? delay : 0);
 
      return () => {
        clearTimeout(timer);
      };
    });
  }
}
 
export class MockSubscriptionLink extends ApolloLink {
  // private observer: Observer<any>;
  public unsubscribers: any[] = [];
  public setups: any[] = [];
 
  private observer: any;
 
  constructor() {
    super();
  }
 
  public request(_req: any) {
    return new Observable<FetchResult>(observer => {
      this.setups.forEach(x => x());
      this.observer = observer;
      return () => {
        this.unsubscribers.forEach(x => x());
      };
    });
  }
 
  public simulateResult(result: MockedSubscriptionResult) {
    setTimeout(() => {
      const { observer } = this;
      Iif (!observer) throw new Error('subscription torn down');
      if (result.result && observer.next) observer.next(result.result);
      if (result.error && observer.error) observer.error(result.error);
    }, result.delay || 0);
  }
 
  public onSetup(listener: any): void {
    this.setups = this.setups.concat([listener]);
  }
 
  public onUnsubscribe(listener: any): void {
    this.unsubscribers = this.unsubscribers.concat([listener]);
  }
}
 
function requestToKey(request: GraphQLRequest, addTypename: Boolean): string {
  const queryString =
    request.query && print(addTypename ? addTypenameToDocument(request.query) : request.query);
 
  const requestKey = { query: queryString };
 
  return JSON.stringify(requestKey);
}
 
// Pass in multiple mocked responses, so that you can test flows that end up
// making multiple queries to the server
// NOTE: The last arg can optionally be an `addTypename` arg
export function mockSingleLink(...mockedResponses: Array<any>): ApolloLink {
  // to pull off the potential typename. If this isn't a boolean, we'll just set it true later
  let maybeTypename = mockedResponses[mockedResponses.length - 1];
  let mocks = mockedResponses.slice(0, mockedResponses.length - 1);
 
  Eif (typeof maybeTypename !== 'boolean') {
    mocks = mockedResponses;
    maybeTypename = true;
  }
 
  return new MockLink(mocks, maybeTypename);
}
 
export function mockObservableLink(): MockSubscriptionLink {
  return new MockSubscriptionLink();
}