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'],
+ },
+});