Repository: FormidableLabs/urql
Pull request #199 (2019-02-22 16:10:44)

Change when fetchOptions factory is executed and how headers are merged


Patch:
diff --git a/src/client.ts b/src/client.ts
index 15a85ce6..533889eb 100755
--- a/src/client.ts
+++ b/src/client.ts
@@ -46,7 +46,7 @@ export const createClient = (opts: ClientOptions) => new Client(opts);
 export class Client {
   // These are variables derived from ClientOptions
   url: string;
-  fetchOptions: RequestInit;
+  fetchOptions?: RequestInit | (() => RequestInit);
   exchange: Exchange;
 
   // These are internals to be used to keep track of operations
@@ -57,11 +57,7 @@ export class Client {
 
   constructor(opts: ClientOptions) {
     this.url = opts.url;
-
-    this.fetchOptions =
-      typeof opts.fetchOptions === 'function'
-        ? opts.fetchOptions()
-        : opts.fetchOptions || {};
+    this.fetchOptions = opts.fetchOptions;
 
     // This subject forms the input of operations; executeOperation may be
     // called to dispatch a new operation on the subject
diff --git a/src/exchanges/fetch.ts b/src/exchanges/fetch.ts
index 411c5ffa..35437aab 100755
--- a/src/exchanges/fetch.ts
+++ b/src/exchanges/fetch.ts
@@ -52,16 +52,26 @@ const createFetchSource = (operation: Operation) => {
         ? new AbortController()
         : undefined;
 
+    const { context } = operation;
+
+    const extraOptions =
+      typeof context.fetchOptions === 'function'
+        ? context.fetchOptions()
+        : context.fetchOptions || {};
+
     const fetchOptions = {
       body: JSON.stringify({
         query: print(operation.query),
         variables: operation.variables,
       }),
-      headers: { 'Content-Type': 'application/json' },
       method: 'POST',
+      ...extraOptions,
+      headers: {
+        'content-type': 'application/json',
+        ...extraOptions.headers,
+      },
       signal:
         abortController !== undefined ? abortController.signal : undefined,
-      ...operation.context.fetchOptions,
     };
 
     executeFetch(operation, fetchOptions).then(result => {
diff --git a/src/types.ts b/src/types.ts
index 52561503..696ac2dd 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -26,7 +26,7 @@ export interface GraphQLRequest {
 /** Additional metadata passed to [exchange]{@link Exchange} functions. */
 export interface OperationContext {
   [key: string]: any;
-  fetchOptions?: RequestInit;
+  fetchOptions?: RequestInit | (() => RequestInit);
   requestPolicy: RequestPolicy;
   url: string;
 }


Test patch:
diff --git a/src/__snapshots__/client.test.ts.snap b/src/__snapshots__/client.test.ts.snap
index f15a65f4..30f757e4 100644
--- a/src/__snapshots__/client.test.ts.snap
+++ b/src/__snapshots__/client.test.ts.snap
@@ -10,7 +10,7 @@ Client {
   "executeMutation": [Function],
   "executeQuery": [Function],
   "executeSubscription": [Function],
-  "fetchOptions": Object {},
+  "fetchOptions": undefined,
   "operations$": [Function],
   "reexecuteOperation": [Function],
   "results$": [Function],
diff --git a/src/__snapshots__/context.test.ts.snap b/src/__snapshots__/context.test.ts.snap
index ac40de0b..277618e7 100644
--- a/src/__snapshots__/context.test.ts.snap
+++ b/src/__snapshots__/context.test.ts.snap
@@ -23,7 +23,7 @@ Object {
       "executeMutation": [Function],
       "executeQuery": [Function],
       "executeSubscription": [Function],
-      "fetchOptions": Object {},
+      "fetchOptions": undefined,
       "operations$": [Function],
       "reexecuteOperation": [Function],
       "results$": [Function],
@@ -38,7 +38,7 @@ Object {
       "executeMutation": [Function],
       "executeQuery": [Function],
       "executeSubscription": [Function],
-      "fetchOptions": Object {},
+      "fetchOptions": undefined,
       "operations$": [Function],
       "reexecuteOperation": [Function],
       "results$": [Function],
@@ -72,7 +72,7 @@ Object {
       "executeMutation": [Function],
       "executeQuery": [Function],
       "executeSubscription": [Function],
-      "fetchOptions": Object {},
+      "fetchOptions": undefined,
       "operations$": [Function],
       "reexecuteOperation": [Function],
       "results$": [Function],
@@ -87,7 +87,7 @@ Object {
       "executeMutation": [Function],
       "executeQuery": [Function],
       "executeSubscription": [Function],
-      "fetchOptions": Object {},
+      "fetchOptions": undefined,
       "operations$": [Function],
       "reexecuteOperation": [Function],
       "results$": [Function],
diff --git a/src/client.test.ts b/src/client.test.ts
index 5133ac51..8f4c6727 100755
--- a/src/client.test.ts
+++ b/src/client.test.ts
@@ -20,21 +20,6 @@ describe('createClient', () => {
 
     expect(c).toMatchSnapshot();
   });
-
-  describe('args', () => {
-    describe('fetchOptions', () => {
-      const fetchOptions = jest.fn(() => ({}));
-
-      it('function is executed', () => {
-        createClient({
-          url,
-          fetchOptions: fetchOptions as any,
-        });
-
-        expect(fetchOptions).toBeCalled();
-      });
-    });
-  });
 });
 
 const query = {
diff --git a/src/exchanges/__snapshots__/fetch.test.ts.snap b/src/exchanges/__snapshots__/fetch.test.ts.snap
index 25c266d8..e1a16d3a 100644
--- a/src/exchanges/__snapshots__/fetch.test.ts.snap
+++ b/src/exchanges/__snapshots__/fetch.test.ts.snap
@@ -231,8 +231,16 @@ Object {
   "error": undefined,
   "operation": Object {
     "context": Object {
-      "fetchOptions": Object {
-        "method": "POST",
+      "fetchOptions": [MockFunction] {
+        "calls": Array [
+          Array [],
+        ],
+        "results": Array [
+          Object {
+            "isThrow": false,
+            "value": Object {},
+          },
+        ],
       },
       "requestPolicy": "cache-first",
       "url": "http://localhost:3000/graphql",
diff --git a/src/exchanges/fetch.test.ts b/src/exchanges/fetch.test.ts
index 8df7f860..da12529c 100755
--- a/src/exchanges/fetch.test.ts
+++ b/src/exchanges/fetch.test.ts
@@ -46,13 +46,22 @@ it('returns response data from fetch', async () => {
     json: jest.fn().mockResolvedValue(response),
   });
 
+  const fetchOptions = jest.fn().mockReturnValue({});
+
   const data = await pipe(
-    fromValue(queryOperation),
+    fromValue({
+      ...queryOperation,
+      context: {
+        ...queryOperation.context,
+        fetchOptions,
+      },
+    }),
     fetchExchange(exchangeArgs),
     toPromise
   );
 
   expect(data).toMatchSnapshot();
+  expect(fetchOptions).toHaveBeenCalled();
 });
 
 it('returns error data from fetch', async () => {