diff --git a/.changeset/fix-webrequest-batch.md b/.changeset/fix-webrequest-batch.md new file mode 100644 index 0000000..e952c1a --- /dev/null +++ b/.changeset/fix-webrequest-batch.md @@ -0,0 +1,5 @@ +--- +'@open-rpc/logs-react': patch +--- + +fix batched request/response parsing in useWebRequest and add tests diff --git a/packages/logs-react/package.json b/packages/logs-react/package.json index 8768b14..e5cddf0 100644 --- a/packages/logs-react/package.json +++ b/packages/logs-react/package.json @@ -27,7 +27,8 @@ "start": "vite", "build:package": "vite build && tsc --emitDeclarationOnly", "clean:package": "rm -rf dist && rm -rf tsconfig.tsbuildinfo", - "lint": "eslint 'src/**/*.{ts,tsx}'" + "lint": "eslint 'src/**/*.{ts,tsx}'", + "test": "vitest run" }, "author": "", "license": "Apache-2.0", @@ -53,7 +54,12 @@ "vite": "6.0.5", "@mui/icons-material": "6.3.1", "@mui/lab": "6.0.0-beta.22", - "@mui/material": "6.3.1" + "@mui/material": "6.3.1", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "16.1.0", + "jsdom": "^26.0.0", + "vitest": "^2.1.8", + "@types/jest": "^29.5.14" }, "dependencies": { "@open-rpc/meta-schema": "^1.14.9", diff --git a/packages/logs-react/src/hooks/useWebRequest.test.tsx b/packages/logs-react/src/hooks/useWebRequest.test.tsx new file mode 100644 index 0000000..75e3426 --- /dev/null +++ b/packages/logs-react/src/hooks/useWebRequest.test.tsx @@ -0,0 +1,62 @@ +import { it, expect, vi } from 'vitest'; +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import useWebRequest from './useWebRequest'; +import { IJSONRPCLog } from '../components/logsReact/logsReact'; + +it('handles batched request and response', async () => { + let history: IJSONRPCLog[] = []; + const onUpdate = (h: IJSONRPCLog[]) => { + history = h; + }; + + let capturedListener: (request: any) => void = () => {}; + const addListener = vi.fn((cb) => { + capturedListener = cb; + }); + const removeListener = vi.fn(); + (global as any).chrome = { + devtools: { + network: { + onRequestFinished: { addListener, removeListener }, + }, + }, + }; + + const TestComp = () => { + const [logs] = useWebRequest(); + React.useEffect(() => { + onUpdate(logs); + }, [logs]); + return null; + }; + + render(); + expect(addListener).toHaveBeenCalled(); + + const req1 = { jsonrpc: '2.0', id: 1, method: 'foo', params: [] }; + const req2 = { jsonrpc: '2.0', id: 2, method: 'bar', params: [] }; + const res1 = { jsonrpc: '2.0', id: 1, result: 'ok1' }; + const res2 = { jsonrpc: '2.0', id: 2, result: 'ok2' }; + + const fakeRequest = { + request: { + url: 'http://test', + postData: { text: JSON.stringify([req1, req2]) }, + }, + startedDateTime: new Date().toISOString(), + time: 5, + getContent: (cb: any) => cb(JSON.stringify([res1, res2])), + }; + + capturedListener(fakeRequest); + + await waitFor(() => { + expect(history.length).toBe(4); + }); + + expect(history[0].method).toBe('foo'); + expect(history[1].method).toBe('bar'); + expect(history[2].method).toBe('foo'); + expect(history[3].method).toBe('bar'); +}); diff --git a/packages/logs-react/src/hooks/useWebRequest.ts b/packages/logs-react/src/hooks/useWebRequest.ts index 8083d2e..3023979 100644 --- a/packages/logs-react/src/hooks/useWebRequest.ts +++ b/packages/logs-react/src/hooks/useWebRequest.ts @@ -49,7 +49,7 @@ const useWebRequest = (): [IJSONRPCLog[], Dispatch] => { const responseObjs: IJSONRPCLog[] = []; // if batched if (requestBodyObj.length) { - for (const [reqObj] of requestBodyObj) { + for (const reqObj of requestBodyObj) { requestObjs.push({ type: 'request', method: reqObj.method, @@ -73,7 +73,7 @@ const useWebRequest = (): [IJSONRPCLog[], Dispatch] => { responseTime.setMilliseconds(responseTime.getMilliseconds() + request.time); // if batched if (responseBodyObj.length) { - for (const [j, resObj] of responseBodyObj) { + responseBodyObj.forEach((resObj, j) => { responseObjs.push({ type: 'response', method: requestBodyObj[j].method, @@ -81,7 +81,7 @@ const useWebRequest = (): [IJSONRPCLog[], Dispatch] => { payload: resObj, batchId: batchIdCount, }); - } + }); batchIdCount += 1; } else { responseObjs.push({ diff --git a/packages/logs-react/src/test/setup.ts b/packages/logs-react/src/test/setup.ts new file mode 100644 index 0000000..7b0828b --- /dev/null +++ b/packages/logs-react/src/test/setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/packages/logs-react/vitest.config.ts b/packages/logs-react/vitest.config.ts new file mode 100644 index 0000000..5fc850c --- /dev/null +++ b/packages/logs-react/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'jsdom', + globals: true, + setupFiles: ['./src/test/setup.ts'], + }, +});