diff --git a/package.json b/package.json index 9e89053..07e447b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oc-client-browser", - "version": "2.1.1", + "version": "2.1.2", "description": "OC browser client", "main": "index.js", "types": "index.d.ts", diff --git a/src/oc-client.js b/src/oc-client.js index 78f00bf..793a46f 100644 --- a/src/oc-client.js +++ b/src/oc-client.js @@ -1,6 +1,12 @@ /* globals __CLIENT_VERSION__, __REGISTERED_TEMPLATES_PLACEHOLDER__, __DEFAULT_RETRY_INTERVAL__, __DEFAULT_RETRY_LIMIT__, __DEFAULT_DISABLE_LOADER__, __DISABLE_LEGACY_TEMPLATES__, __EXTERNALS__, __IMPORTS__ */ import { decode } from "@rdevis/turbo-stream"; +function createErrorFromObject(o) { + const e = new Error(o.message || o); + if (o.stack) e.stack = o.stack; + return Object.assign(e, o.originalError, o); +} + export function createOc(oc) { // If oc client is already inside the page, we do nothing. if (oc.status) { @@ -35,7 +41,6 @@ export function createOc(oc) { let logError = (msg) => console.log(msg); let logInfo = (msg) => ocConf.debug && console.log(msg); let handleFetchResponse = (response) => { - if (!response.ok) throw response; if (response.headers.get("Content-Type") !== "x-text/stream") return response.json(); @@ -276,10 +281,15 @@ export function createOc(oc) { .then((apiResponse) => { if (!options.action) { let response = apiResponse[0].response; - let err = response.error ? response.details || response.error : null; + let err = response.error + ? createErrorFromObject(response.details || response.error) + : null; cb(err, response.data, apiResponse[0]); } else { - cb(null, apiResponse.data); + let err = apiResponse.error + ? createErrorFromObject(apiResponse.details || apiResponse.error) + : null; + cb(err, apiResponse.data); } }) .catch(cb); diff --git a/tests/getData.spec.js b/tests/getData.spec.js index aaa6f06..84ebfa5 100644 --- a/tests/getData.spec.js +++ b/tests/getData.spec.js @@ -200,7 +200,12 @@ test.describe("oc-client : getData", () => { }); // Verify error was passed to callback - expect(errorResult.callbackError).toEqual("details about oups"); + // If callbackError is an Error object, compare its message + const errorMsg = + errorResult.callbackError instanceof Error + ? errorResult.callbackError.message + : errorResult.callbackError; + expect(errorMsg).toEqual("details about oups"); }); test("should call the callback with server.js error if no details are available", async ({ @@ -250,7 +255,11 @@ test.describe("oc-client : getData", () => { }); // Verify error was passed to callback - expect(errorResult.callbackError).toEqual("oups"); + const errorMsg = + errorResult.callbackError instanceof Error + ? errorResult.callbackError.message + : errorResult.callbackError; + expect(errorMsg).toEqual("oups"); }); test("should handle JSON requests correctly", async ({ page }) => { @@ -555,4 +564,52 @@ test.describe("oc-client : getData", () => { // Verify error was passed to callback expect(errorResult.callbackError).toEqual("Network error"); }); + + test("should reject with an Error object containing API error data when network returns 500", async ({ + page, + }) => { + const result = await page.evaluate(async () => { + // Save original fetch + const originalFetch = window.fetch; + // Mock fetch to simulate a 500 error with error object in response + window.fetch = () => { + return Promise.resolve({ + headers: { get: () => null }, + json: () => + Promise.resolve({ + error: "API error", + details: { + foo: "bar", + message: "Something went wrong", + stack: "stacktrace", + }, + }), + }); + }; + try { + await window.oc.getAction({ + component: "test-component", + baseUrl: "http://api", + version: "1.0.0", + action: "do", + }); + return { success: true }; + } catch (err) { + // Restore original fetch + window.fetch = originalFetch; + return { + success: false, + isError: err instanceof Error, + message: err.message, + stack: err.stack, + foo: err.foo, + }; + } + }); + expect(result.success).toBe(false); + expect(result.isError).toBe(true); + expect(result.message).toBe("Something went wrong"); + expect(result.stack).toBe("stacktrace"); + expect(result.foo).toBe("bar"); + }); });