diff --git a/src/lib/api/contrib/invenio/InvenioSearchApi.js b/src/lib/api/contrib/invenio/InvenioSearchApi.js index 49464673..a42fe95f 100644 --- a/src/lib/api/contrib/invenio/InvenioSearchApi.js +++ b/src/lib/api/contrib/invenio/InvenioSearchApi.js @@ -81,7 +81,7 @@ export class InvenioSearchApi { ); } if (this.responseInterceptor) { - this.http.interceptors.request.use( + this.http.interceptors.response.use( this.responseInterceptor.resolve, this.responseInterceptor.reject ); diff --git a/src/lib/api/contrib/invenio/InvenioSearchApi.test.js b/src/lib/api/contrib/invenio/InvenioSearchApi.test.js index 4e9be2a1..f7d56c34 100644 --- a/src/lib/api/contrib/invenio/InvenioSearchApi.test.js +++ b/src/lib/api/contrib/invenio/InvenioSearchApi.test.js @@ -76,4 +76,36 @@ describe("test InvenioSearchApi class", () => { const request = mockedAxios.history.get[0]; expect(request.url).toBe("/api/records"); }); + + it("should register response interceptors on the response pipeline", async () => { + const responseResolve = jest.fn((response) => response); + const searchApi = new InvenioSearchApi({ + axios: { + url: "/api/records", + }, + invenio: { + requestSerializer: MockedRequestSerializer, + responseSerializer: MockedResponseSerializer, + }, + interceptors: { + response: { + resolve: responseResolve, + reject: (error) => Promise.reject(error), + }, + }, + }); + const mockedAxios = new MockAdapter(searchApi.http); + + const mockedResponse = { hits: [{ result: "1" }] }; + mockedAxios.onAny().reply(200, mockedResponse); + await searchApi.search({ q: "test" }); + + expect(responseResolve).toHaveBeenCalledTimes(1); + expect(responseResolve).toHaveBeenCalledWith( + expect.objectContaining({ + status: 200, + data: mockedResponse, + }) + ); + }); }); diff --git a/src/lib/api/contrib/invenio/InvenioSuggestionApi.js b/src/lib/api/contrib/invenio/InvenioSuggestionApi.js index 23f2ef6f..fe9f149e 100644 --- a/src/lib/api/contrib/invenio/InvenioSuggestionApi.js +++ b/src/lib/api/contrib/invenio/InvenioSuggestionApi.js @@ -58,8 +58,9 @@ class InvenioSuggestionResponseSerializer { export class InvenioSuggestionApi extends InvenioSearchApi { validateConfig(config) { - super.validateConfig(config); - + // the parent `axios` config is already validated by the `InvenioSearchApi` + // constructor via `validateAxiosConfig`, here we only validate the + // suggestion-specific config if (!_hasIn(config, "invenio.suggestions.queryField")) { throw new Error( "InvenioSuggestionApi config: `invenio.suggestions.queryField` is required." @@ -67,12 +68,13 @@ export class InvenioSuggestionApi extends InvenioSearchApi { } if (!_hasIn(config, "invenio.suggestions.responseField")) { throw new Error( - "InvenioSuggestionApi config: `invenio.suggestions.queryField` is responseField." + "InvenioSuggestionApi config: `invenio.suggestions.responseField` is required." ); } } initSerializers(config) { + this.validateConfig(config); const requestSerializerCls = _get( config, "invenio.requestSerializer", diff --git a/src/lib/api/contrib/invenio/InvenioSuggestionApi.test.js b/src/lib/api/contrib/invenio/InvenioSuggestionApi.test.js new file mode 100644 index 00000000..93b12d01 --- /dev/null +++ b/src/lib/api/contrib/invenio/InvenioSuggestionApi.test.js @@ -0,0 +1,64 @@ +/* + * This file is part of React-SearchKit. + * Copyright (C) 2019 CERN. + * + * React-SearchKit is free software; you can redistribute it and/or modify it + * under the terms of the MIT License; see LICENSE file for more details. + */ + +import { InvenioSuggestionApi } from "."; + +describe("test InvenioSuggestionApi class", () => { + it("should throw when `invenio.suggestions.queryField` is missing", () => { + expect( + () => + new InvenioSuggestionApi({ + axios: { + url: "/api/records", + }, + invenio: { + suggestions: { + responseField: "metadata.title", + }, + }, + }) + ).toThrow( + "InvenioSuggestionApi config: `invenio.suggestions.queryField` is required." + ); + }); + + it("should throw when `invenio.suggestions.responseField` is missing", () => { + expect( + () => + new InvenioSuggestionApi({ + axios: { + url: "/api/records", + }, + invenio: { + suggestions: { + queryField: "title", + }, + }, + }) + ).toThrow( + "InvenioSuggestionApi config: `invenio.suggestions.responseField` is required." + ); + }); + + it("should not throw when both suggestion fields are provided", () => { + expect( + () => + new InvenioSuggestionApi({ + axios: { + url: "/api/records", + }, + invenio: { + suggestions: { + queryField: "title", + responseField: "metadata.title", + }, + }, + }) + ).not.toThrow(); + }); +}); diff --git a/src/lib/api/contrib/opensearch/OSSearchApi.js b/src/lib/api/contrib/opensearch/OSSearchApi.js index 1ae4ccc6..978133a4 100644 --- a/src/lib/api/contrib/opensearch/OSSearchApi.js +++ b/src/lib/api/contrib/opensearch/OSSearchApi.js @@ -64,7 +64,7 @@ export class OSSearchApi { ); } if (this.responseInterceptor) { - this.http.interceptors.request.use( + this.http.interceptors.response.use( this.responseInterceptor.resolve, this.responseInterceptor.reject ); diff --git a/src/lib/api/contrib/opensearch/OSSearchApi.test.js b/src/lib/api/contrib/opensearch/OSSearchApi.test.js index d3b7a7d3..4b6c2e29 100644 --- a/src/lib/api/contrib/opensearch/OSSearchApi.test.js +++ b/src/lib/api/contrib/opensearch/OSSearchApi.test.js @@ -76,4 +76,36 @@ describe("test OSSearchApi class", () => { const request = mockedAxios.history.post[0]; expect(request.url).toBe("/api/records"); }); + + it("should register response interceptors on the response pipeline", async () => { + const responseResolve = jest.fn((response) => response); + const searchApi = new OSSearchApi({ + axios: { + url: "/api/records", + }, + os: { + requestSerializer: MockedRequestSerializer, + responseSerializer: MockedResponseSerializer, + }, + interceptors: { + response: { + resolve: responseResolve, + reject: (error) => Promise.reject(error), + }, + }, + }); + const mockedAxios = new MockAdapter(searchApi.http); + + const mockedResponse = { hits: [{ result: "1" }] }; + mockedAxios.onAny().reply(200, mockedResponse); + await searchApi.search({ q: "test" }); + + expect(responseResolve).toHaveBeenCalledTimes(1); + expect(responseResolve).toHaveBeenCalledWith( + expect.objectContaining({ + status: 200, + data: mockedResponse, + }) + ); + }); }); diff --git a/src/lib/state/actions/query.js b/src/lib/state/actions/query.js index 1b331390..013e166f 100644 --- a/src/lib/state/actions/query.js +++ b/src/lib/state/actions/query.js @@ -199,7 +199,7 @@ const updateQueryStateAfterResponse = (response, dispatch, getState, appConfig) // Replace the URL args with the response new query state urlHandlerApi.replace(updatedQueryState); } - delete response.newStateQuery; + delete response.newQueryState; return response; };