All files / src test-links.ts

91.36% Statements 74/81
90% Branches 36/40
77.27% Functions 17/22
93.65% Lines 59/63
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 14823x                 23x                                       23x 170x     170x 170x 249x       23x 249x 249x 249x 197x 197x   249x     23x 215x 215x 215x 4x             211x 211x   211x 14x 14x   211x       211x 211x 195x 17x   178x 178x       211x 210x       23x   23x   12x 12x         12x     23x 14x 14x 14x 14x 14x         23x 22x 22x 22x 22x 22x       23x       23x     23x     464x   464x         464x         249x 170x     23x      
import {
  Operation,
  GraphQLRequest,
  ApolloLink,
  FetchResult,
  Observable,
  // Observer,
} from 'apollo-link';
 
import { print } from 'graphql/language/printer';
 
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 {
  private mockedResponsesByKey: { [key: string]: MockedResponse[] } = {};
 
  constructor(mockedResponses: MockedResponse[]) {
    super();
    mockedResponses.forEach(mockedResponse => {
      this.addMockedResponse(mockedResponse);
    });
  }
 
  public addMockedResponse(mockedResponse: MockedResponse) {
    const key = requestToKey(mockedResponse.request);
    let mockedResponses = this.mockedResponsesByKey[key];
    if (!mockedResponses) {
      mockedResponses = [];
      this.mockedResponsesByKey[key] = mockedResponses;
    }
    mockedResponses.push(mockedResponse);
  }
 
  public request(operation: Operation) {
    const key = requestToKey(operation);
    const responses = this.mockedResponsesByKey[key];
    if (!responses || responses.length === 0) {
      throw new Error(
        `No more mocked responses for the query: ${print(
          operation.query,
        )}, variables: ${JSON.stringify(operation.variables)}`,
      );
    }
 
    const original = [...this.mockedResponsesByKey[key]];
    const { result, error, delay, newData } = this.mockedResponsesByKey[key].shift() || ({} as any);
 
    if (newData) {
      original[0].result = newData();
      this.mockedResponsesByKey[key].push(original[0]);
    }
    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): string {
  const queryString = request.query && print(request.query);
 
  const requestKey = {
    variables: request.variables || {},
    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
export function mockSingleLink(...mockedResponses: MockedResponse[]): ApolloLink {
  return new MockLink(mockedResponses);
}
 
export function mockObservableLink(): MockSubscriptionLink {
  return new MockSubscriptionLink();
}