1import { uuid } from 'expo-modules-core';
2import gql from 'graphql-tag';
3
4jest.mock('@react-native-async-storage/async-storage', () => ({
5  setItem: jest.fn(() => new Promise((resolve) => resolve(null))),
6  getItem: jest.fn(() => new Promise((resolve) => resolve(null))),
7  removeItem: jest.fn(() => new Promise((resolve) => resolve(null))),
8}));
9
10jest.mock('@react-native-community/netinfo');
11
12describe('User Authentication Flow', () => {
13  let Store;
14  let SessionActions;
15
16  let originalFetch;
17
18  beforeEach(async () => {
19    originalFetch = global.fetch;
20    global.fetch = jest.fn();
21
22    Store = require('../../redux/Store').default;
23    SessionActions = require('../../redux/SessionActions').default;
24
25    await Store.dispatch(SessionActions.signOut());
26  });
27
28  afterEach(() => {
29    global.fetch = originalFetch;
30    originalFetch = null;
31
32    jest.restoreAllMocks();
33    jest.resetModules();
34  });
35
36  it(`logs in and stores session tokens correctly`, async () => {
37    const { sessionSecret } = { sessionSecret: uuid.v4() };
38
39    // store session token
40    await Store.dispatch(SessionActions.setSession({ sessionSecret }));
41
42    // retrieve session token
43    const state = Store.getState();
44    const retrievedSession = state.session;
45
46    // make sure the retrieved token is the same as the one we originally received
47    expect(sessionSecret).toBeDefined();
48    expect(sessionSecret).toBe(retrievedSession.sessionSecret);
49  });
50
51  it(`performs authenticated GraphQL queries`, async () => {
52    const ApolloClient = require('../ApolloClient').default;
53    const apolloLinkRequest = jest.spyOn(ApolloClient.link, 'request');
54
55    const { sessionSecret } = { sessionSecret: uuid.v4() };
56
57    // store session token
58    await Store.dispatch(SessionActions.setSession({ sessionSecret }));
59
60    _setFakeHttpResponse(
61      JSON.stringify({
62        data: {
63          app: {
64            __typename: 'AppQuery',
65            all: [
66              { __typename: 'App', id: '2c28de10-a2cd-11e6-b8ce-59d1587e6774' },
67              { __typename: 'App', id: '0d4823c0-37fb-11e7-9c45-89e7ab918dda' },
68            ],
69          },
70        },
71      })
72    );
73
74    try {
75      await ApolloClient.query({
76        query: gql`
77          {
78            app {
79              all(limit: 2, filter: NEW, sort: TOP) {
80                id
81              }
82            }
83          }
84        `,
85        variables: null,
86      });
87    } finally {
88      ApolloClient.resetStore();
89    }
90
91    // expect the query to be authenticated
92    expect(apolloLinkRequest).toHaveBeenCalledTimes(1);
93    const operation = apolloLinkRequest.mock.calls[0][0];
94    expect(operation.getContext().headers).toMatchObject({
95      'expo-session': sessionSecret,
96    });
97  });
98});
99
100function _setFakeHttpResponse(responseText) {
101  global.fetch.mockReturnValue(
102    Promise.resolve({
103      async text() {
104        return responseText;
105      },
106    })
107  );
108}
109