diff --git a/src/app/(dashboard)/dashboard/tools/traffic-inspector/components/TopBarControls.tsx b/src/app/(dashboard)/dashboard/tools/traffic-inspector/components/TopBarControls.tsx
index b2eef480f2..03ff373ee4 100644
--- a/src/app/(dashboard)/dashboard/tools/traffic-inspector/components/TopBarControls.tsx
+++ b/src/app/(dashboard)/dashboard/tools/traffic-inspector/components/TopBarControls.tsx
@@ -27,6 +27,7 @@ interface TopBarControlsProps {
connected: boolean;
total: number;
maxSize?: number;
+ pendingCount?: number;
// session recorder
recording: boolean;
session: SessionInfo | null;
@@ -53,6 +54,7 @@ export function TopBarControls({
connected,
total,
maxSize = 1000,
+ pendingCount = 0,
recording,
session,
elapsed,
@@ -188,6 +190,11 @@ export function TopBarControls({
{total}/{maxSize}
+ {paused && pendingCount > 0 && (
+
+ {t("pausedNewBadge", { count: pendingCount })}
+
+ )}
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 7123a1ccd5..a7025e3c86 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -7488,6 +7488,8 @@
"timingMethod": "Method",
"timingStatus": "Status",
"timingRequestSize": "Request size",
- "timingResponseSize": "Response size"
+ "timingResponseSize": "Response size",
+ "pausedNewBadge": "{count} new",
+ "clearContextFilter": "clear"
}
}
diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json
index 2219e32eb9..ffcf810acc 100644
--- a/src/i18n/messages/pt-BR.json
+++ b/src/i18n/messages/pt-BR.json
@@ -7478,6 +7478,8 @@
"timingMethod": "Método",
"timingStatus": "Status",
"timingRequestSize": "Tamanho da requisição",
- "timingResponseSize": "Tamanho da resposta"
+ "timingResponseSize": "Tamanho da resposta",
+ "pausedNewBadge": "{count} novos",
+ "clearContextFilter": "limpar"
}
}
diff --git a/tests/unit/ui/use-traffic-stream.test.tsx b/tests/unit/ui/use-traffic-stream.test.tsx
index 6959e2cdd1..ce8804fa9b 100644
--- a/tests/unit/ui/use-traffic-stream.test.tsx
+++ b/tests/unit/ui/use-traffic-stream.test.tsx
@@ -3,6 +3,18 @@
*/
import { describe, it, before, after, mock } from "node:test";
import assert from "node:assert/strict";
+import fs from "node:fs";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const HOOK_SRC = fs.readFileSync(
+ path.resolve(
+ __dirname,
+ "../../../src/app/(dashboard)/dashboard/tools/traffic-inspector/hooks/useTrafficStream.ts"
+ ),
+ "utf8"
+);
// Minimal EventEmitter-based mock WebSocket
class MockWebSocket {
@@ -165,4 +177,26 @@ describe("useTrafficStream core logic", () => {
assert.equal(pending.length, 1);
assert.equal(pending[0].id, "3");
});
+
+ it("TrafficStreamState interface includes pendingCount field (R5-9)", () => {
+ assert.ok(
+ HOOK_SRC.includes("pendingCount"),
+ "TrafficStreamState should expose pendingCount"
+ );
+ });
+
+ it("pendingCount increments when paused and new event arrives (R5-9)", () => {
+ // Verify the source contains the setPendingCount call when pushing to pendingRef
+ assert.ok(
+ HOOK_SRC.includes("setPendingCount(pendingRef.current.length)"),
+ "should call setPendingCount when adding to pendingRef"
+ );
+ });
+
+ it("pendingCount resets to 0 on resume (R5-9)", () => {
+ assert.ok(
+ HOOK_SRC.includes("setPendingCount(0)"),
+ "should reset pendingCount to 0 on resume and clear"
+ );
+ });
});