diff --git a/src/System/Router/Utils/__tests__/renderToStream.jest.tsx b/src/System/Router/Utils/__tests__/renderToStream.jest.tsx index 814a5aaa282..5176af8c736 100644 --- a/src/System/Router/Utils/__tests__/renderToStream.jest.tsx +++ b/src/System/Router/Utils/__tests__/renderToStream.jest.tsx @@ -15,6 +15,7 @@ describe("renderToStream", () => { const res = ({ statusCode: 0, setHeader: jest.fn(), + res: { write: jest.fn(), end: jest.fn() }, } as unknown) as ArtsyResponse const sheet = ({ @@ -109,7 +110,7 @@ describe("renderToStream", () => { const jsx =
Timeout Test
renderToStream({ jsx, sheet, res }) - jest.advanceTimersByTime(5000) + jest.advanceTimersByTime(10000) // stream timeout expect(mockAbort).toHaveBeenCalled() jest.useRealTimers() @@ -161,7 +162,7 @@ describe("renderToStream", () => { const stream = renderToStream({ jsx, sheet, res }) - stream.write("") + stream.write("") const chunks: string[] = [] stream.on("data", chunk => { @@ -174,7 +175,7 @@ describe("renderToStream", () => { const result = chunks.join("") expect(result).toContain( - 'mock-css
Hello World
' + 'mock-css
Hello World
' ) }) }) diff --git a/src/System/Router/Utils/__tests__/serializeRelayHydrationData.jest.ts b/src/System/Router/Utils/__tests__/serializeRelayHydrationData.jest.ts new file mode 100644 index 00000000000..00a8187da61 --- /dev/null +++ b/src/System/Router/Utils/__tests__/serializeRelayHydrationData.jest.ts @@ -0,0 +1,78 @@ +import { SSRCache } from "react-relay-network-modern-ssr/lib/server" +import { serializeRelayHydrationData } from "System/Router/Utils/serializeRelayHydrationData" +import mockSerialize from "serialize-javascript" + +jest.mock("serialize-javascript", () => jest.fn()) + +describe("serializeRelayHydrationData", () => { + afterEach(() => { + jest.clearAllMocks() + }) + + it("should serialize the relay data correctly", () => { + const mockData = ([ + [ + { + id: 1, + _res: "some-network-response", + data: "value1", + }, + { + id: 2, + _res: "another-response", + data: "value2", + }, + ], + ] as unknown) as SSRCache + + mockSerialize.mockImplementation((data, options) => JSON.stringify(data)) + + const result = serializeRelayHydrationData(mockData) + + expect(mockSerialize).toHaveBeenCalledTimes(2) + expect(mockSerialize).toHaveBeenCalledWith(mockData, { isJSON: true }) + expect(mockSerialize).toHaveBeenCalledWith(JSON.stringify(mockData), { + isJSON: true, + }) + + expect(result).toBe(JSON.stringify(JSON.stringify(mockData))) + expect(mockData[0][0]).not.toHaveProperty("_res") + expect(mockData[0][1]).not.toHaveProperty("_res") + }) + + it("should handle empty data gracefully", () => { + mockSerialize.mockImplementation((data, options) => JSON.stringify(data)) + + const result = serializeRelayHydrationData([]) + + expect(mockSerialize).toHaveBeenCalledTimes(2) + expect(mockSerialize).toHaveBeenCalledWith([], { isJSON: true }) + expect(mockSerialize).toHaveBeenCalledWith(JSON.stringify([]), { + isJSON: true, + }) + + expect(result).toBe(JSON.stringify(JSON.stringify([]))) + }) + + it("should return an empty serialized array when an error occurs", () => { + const mockData = ([ + [ + { + id: 1, + _res: "some-network-response", + data: "value1", + }, + ], + ] as unknown) as SSRCache + + mockSerialize.mockImplementation(() => { + throw new Error("Serialization Error") + }) + + expect(() => { + const result = serializeRelayHydrationData(mockData) + expect(mockSerialize).toHaveBeenCalledTimes(1) + expect(result).toBe(mockSerialize("[]", { isJSON: true })) + }).toThrowError("Serialization Error") + }) +}) diff --git a/src/System/Router/Utils/renderToStream.tsx b/src/System/Router/Utils/renderToStream.tsx index 7337adb5daf..c0163f22a64 100644 --- a/src/System/Router/Utils/renderToStream.tsx +++ b/src/System/Router/Utils/renderToStream.tsx @@ -4,7 +4,7 @@ import { ArtsyResponse } from "Server/middleware/artsyExpress" import { Transform } from "stream" import { ServerStyleSheet } from "styled-components" -const STREAM_TIMEOUT = 5000 +const STREAM_TIMEOUT_MS = 10000 interface RenderToStreamProps { jsx: ReactNode @@ -80,7 +80,7 @@ export const renderToStream = ({ // Abandon and switch to client rendering if enough time passes. streamTimeout = setTimeout(() => { abort() - }, STREAM_TIMEOUT) + }, STREAM_TIMEOUT_MS) return stream } diff --git a/src/System/Router/Utils/serializeRelayHydrationData.tsx b/src/System/Router/Utils/serializeRelayHydrationData.tsx index 75e19bc2be8..161b94f1411 100644 --- a/src/System/Router/Utils/serializeRelayHydrationData.tsx +++ b/src/System/Router/Utils/serializeRelayHydrationData.tsx @@ -2,30 +2,27 @@ import { RelayNetworkLayerResponse } from "react-relay-network-modern" import { SSRCache } from "react-relay-network-modern-ssr/lib/server" import serialize from "serialize-javascript" -export const serializeRelayHydrationData = (initialRelayData: SSRCache) => { +export const serializeRelayHydrationData = ( + initialRelayData: SSRCache = [] +): string => { initialRelayData.forEach(entry => { entry.forEach((item: RelayNetworkLayerResponse) => { - // Clean relay data of problematic data structures - delete item._res + delete item._res // Remove unnecessary relay network data }) }) - let hydrationData - try { - hydrationData = serialize(initialRelayData, { + // Double pass to ensure that the data is serialized correctly + // TODO: Fix this + return serialize(serialize(initialRelayData, { isJSON: true }), { isJSON: true, }) } catch (error) { - hydrationData = "{}" - console.error( "[system/router/serializeRelayHydrationData] Error serializing data:", error ) - } - return serialize(hydrationData || {}, { - isJSON: true, - }) + return serialize("[]", { isJSON: true }) + } }