You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by am...@apache.org on 2022/02/15 13:59:14 UTC

[couchdb-fauxton] branch main updated: Add pre-fetch function to ajax module (#1335)

This is an automated email from the ASF dual-hosted git repository.

amaranhao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git


The following commit(s) were added to refs/heads/main by this push:
     new f24fe21  Add pre-fetch function to ajax module (#1335)
f24fe21 is described below

commit f24fe2167dc86ef3920c3cc0988170c8ccbab57a
Author: Antonio Maranhao <30...@users.noreply.github.com>
AuthorDate: Tue Feb 15 08:58:09 2022 -0500

    Add pre-fetch function to ajax module (#1335)
    
    The pre-fetch function is executed before every network request
    made by the ajax module. It can be used to run actions before
    fetch() is invoked by Fauxton, even allowing one to  modify
    the original fetch() parameters.
---
 app/core/__tests__/ajax.test.js | 53 +++++++++++++++++++++++++++++-
 app/core/ajax.js                | 71 +++++++++++++++++++++++++++++------------
 2 files changed, 102 insertions(+), 22 deletions(-)

diff --git a/app/core/__tests__/ajax.test.js b/app/core/__tests__/ajax.test.js
index c989a41..ad6e711 100644
--- a/app/core/__tests__/ajax.test.js
+++ b/app/core/__tests__/ajax.test.js
@@ -16,7 +16,10 @@ import {
   get,
   put,
   post,
-  deleteRequest
+  deleteRequest,
+  setPreFetchFn,
+  defaultPreFetch,
+
 } from '../ajax';
 
 describe('Fauxton Ajax', () => {
@@ -209,4 +212,52 @@ describe('Fauxton Ajax', () => {
         });
     });
   });
+
+  describe('pre-fetch function', () => {
+    afterEach(() => {
+      setPreFetchFn(defaultPreFetch);
+    });
+
+    const successResponse = {
+      status: 200,
+      body: {
+        ok: true
+      }
+    };
+    it('by default calls fetch with the same params', () => {
+      fetchMock.postOnce('/testing', successResponse);
+      return post('/testing', JSON.stringify({a: 123}), {extraOption: 'foo'})
+        .then(resp =>{
+          expect(resp.ok).toBeTruthy();
+          expect(fetchMock.lastOptions().extraOption).toEqual('foo');
+        });
+    });
+
+    it('is called and then fetch is called', () => {
+      fetchMock.postOnce('/testing_transformed', successResponse);
+      let prefetchCalled = false;
+      const mockPreFetch = (url, options) => {
+        prefetchCalled = true;
+        return Promise.resolve({url: url + '_transformed', options});
+      };
+      setPreFetchFn(mockPreFetch);
+      return post('/testing', JSON.stringify({a: 123}))
+        .then(resp =>{
+          expect(prefetchCalled).toEqual(true);
+          expect(resp.ok).toBeTruthy();
+          expect(fetchMock.lastOptions().body).toBe('"{\\"a\\":123}"');
+        });
+    });
+
+    it('fails when trying to set an invalid function or null/undefined', () => {
+      const caseNotFunction = () => { setPreFetchFn('not a function'); };
+      expect(caseNotFunction).toThrow();
+      const caseNull = () => { setPreFetchFn(null); };
+      expect(caseNull).toThrow();
+      const caseUndefined = () => { setPreFetchFn(undefined); };
+      expect(caseUndefined).toThrow();
+      const caseInvalidFunction = () => { setPreFetchFn((onlyOneParam) => { return onlyOneParam; }); };
+      expect(caseInvalidFunction).toThrow();
+    });
+  });
 });
diff --git a/app/core/ajax.js b/app/core/ajax.js
index 305d8dc..af5995c 100644
--- a/app/core/ajax.js
+++ b/app/core/ajax.js
@@ -15,6 +15,32 @@ import 'rxjs/add/operator/filter';
 */
 export const fetchObserver = new Subject();
 
+// The default pre-fetch function which simply resolves to the original parameters.
+export function defaultPreFetch(url, options) {
+  return Promise.resolve({url, options});
+}
+
+let _preFetchFn = defaultPreFetch;
+
+/**
+ * setPreFetchFn - sets a 'pre-fetch' function that is executed before each network request
+ * originated from this module, i.e. before fetch() is executed. Any fetch() calls from
+ * outside this module are not affected.
+ *
+ * The provided function will receive the 'url' and 'options' parameters that would be sent to fetch(),
+ * and it is expected to return a Promise that resolves to a {url, options} object.
+ * Once this Promise resolves, fetch() is then executed with the 'url' and 'options' returned by the Promise.
+ * This means, the 'pre-fetch' function can transform the original values before fetch() is called.
+ *
+ * @param {function} fn  The pre-fetch function
+ */
+export const setPreFetchFn = fn => {
+  if (fn && typeof fn === "function" && fn.length === 2) {
+    _preFetchFn = fn;
+  } else {
+    throw new Error('preFetch must be a function that accepts two parameters (url and options) like the native fetch()');
+  }
+};
 
 /**
  * json - The lowlevel fetch request with some basic headers
@@ -29,28 +55,31 @@ export const fetchObserver = new Subject();
  * @return {Promise}
  */
 export const json = (url, method = "GET", opts = {}) => {
-  return fetch(
-    url,
-    defaultsDeep(
-      {},
-      opts,
-      {
-        method,
-        credentials: "include",
-        headers: {
-          accept: "application/json",
-          "Content-Type": "application/json",
-          "Pragma":"no-cache" //Disables cache for IE11
-        },
-        cache: "no-cache"
-      }
-    )
-  ).then(resp => {
-    fetchObserver.next(resp);
-    if (opts.raw) {
-      return resp;
+  const fetchOptions = defaultsDeep(
+    {},
+    opts,
+    {
+      method,
+      credentials: "include",
+      headers: {
+        accept: "application/json",
+        "Content-Type": "application/json",
+        "Pragma":"no-cache" //Disables cache for IE11
+      },
+      cache: "no-cache"
     }
-    return resp.json();
+  );
+  return _preFetchFn(url, fetchOptions).then((result) => {
+    return fetch(
+      result.url,
+      result.options,
+    ).then(resp => {
+      fetchObserver.next(resp);
+      if (opts.raw) {
+        return resp;
+      }
+      return resp.json();
+    });
   });
 };