diff --git a/__tests__/pages/utilities/har-file-viewer.test.tsx b/__tests__/pages/utilities/har-file-viewer.test.tsx
new file mode 100644
index 0000000..86f4456
--- /dev/null
+++ b/__tests__/pages/utilities/har-file-viewer.test.tsx
@@ -0,0 +1,101 @@
+import { render, screen, within } from "@testing-library/react";
+import { userEvent } from "@testing-library/user-event";
+import HARFileViewer from "../../../pages/utilities/har-file-viewer";
+
+// Mock HAR file data
+const mockHarData = {
+ log: {
+ entries: [
+ {
+ request: {
+ url: "https://example.com/api/test",
+ method: "GET",
+ headers: [
+ { name: "User-Agent", value: "Mozilla/50" },
+ { name: "Accept", value: "application/json" },
+ ],
+ },
+ response: {
+ status: 200,
+ content: {
+ size: 124,
+ mimeType: "application/json",
+ text: '{"message": "success"}',
+ },
+ headers: [{ name: "Content-Type", value: "application/json" }],
+ },
+ time: 150,
+ startedDateTime: "2023-01-01T00:00:00",
+ },
+ {
+ request: {
+ url: "https://example.com/css/style.css",
+ method: "GET",
+ headers: [{ name: "User-Agent", value: "Mozilla/50" }],
+ },
+ response: {
+ status: 404,
+ content: {
+ size: 248,
+ mimeType: "text/css",
+ text: "body { color: red; }",
+ },
+ headers: [{ name: "Content-Type", value: "text/css" }],
+ },
+ time: 75,
+ startedDateTime: "2023-01-01T00:00:01.000Z",
+ },
+ ],
+ },
+};
+
+describe("HARFileViewer", () => {
+ test("should render the component and display the drop zone text", () => {
+ render();
+
+ expect(screen.getByText("Drop your .har file here")).toBeInTheDocument();
+ });
+
+ test("should list all requests after uploading a har file", async () => {
+ const user = userEvent.setup();
+ render();
+
+ // Create a mock file
+ const file = new File([JSON.stringify(mockHarData)], "test.har", {
+ type: "application/json",
+ });
+
+ // Find the file input and upload the file
+ const fileInput = screen.getByTestId("input");
+ await user.upload(fileInput, file);
+
+ // Wait for the requests to be displayed
+ await screen.findByText("https://example.com/api/test");
+ await screen.findByText("https://example.com/css/style.css");
+ });
+
+ test("should list the status code for every request", async () => {
+ const user = userEvent.setup();
+ render();
+
+ // Create a mock file
+ const file = new File([JSON.stringify(mockHarData)], "test.har", {
+ type: "application/json",
+ });
+
+ // Find the file input and upload the file
+ const fileInput = screen.getByTestId("input");
+ await user.upload(fileInput, file);
+
+ // Get all rows
+ const rows = await screen.findAllByTestId("table-row");
+
+ // For the 1st row, get status code column and verify if its 200
+ const row1 = within(rows[0]).getByTestId("column-status-code");
+ expect(row1).toHaveTextContent("200");
+
+ // For the 2nd row, get status code column and verify if its 404
+ const row2 = within(rows[1]).getByTestId("column-status-code");
+ expect(row2).toHaveTextContent("404");
+ });
+});
diff --git a/jest.setup.ts b/jest.setup.ts
index d0de870..148b93a 100644
--- a/jest.setup.ts
+++ b/jest.setup.ts
@@ -1 +1,13 @@
import "@testing-library/jest-dom";
+
+// There's no official way to mock next/navigation.
+// We just make it no-op for all tests.
+jest.mock("next/navigation", () => ({
+ useRouter: () => ({
+ push: jest.fn(),
+ replace: jest.fn(),
+ back: jest.fn(),
+ forward: jest.fn(),
+ refresh: jest.fn(),
+ }),
+}));
diff --git a/package-lock.json b/package-lock.json
index 41b631d..79df55e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,6 +33,7 @@
"devDependencies": {
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
+ "@testing-library/user-event": "^14.6.1",
"@types/jest": "^29.5.12",
"@types/js-yaml": "^4.0.9",
"@types/node": "^20",
@@ -2890,6 +2891,19 @@
}
}
},
+ "node_modules/@testing-library/user-event": {
+ "version": "14.6.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz",
+ "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ },
+ "peerDependencies": {
+ "@testing-library/dom": ">=7.21.4"
+ }
+ },
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
diff --git a/package.json b/package.json
index a7759ea..c9d8345 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"devDependencies": {
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
+ "@testing-library/user-event": "^14.6.1",
"@types/jest": "^29.5.12",
"@types/js-yaml": "^4.0.9",
"@types/node": "^20",
diff --git a/pages/utilities/har-file-viewer.tsx b/pages/utilities/har-file-viewer.tsx
index 1d99bb0..ee8f2a4 100644
--- a/pages/utilities/har-file-viewer.tsx
+++ b/pages/utilities/har-file-viewer.tsx
@@ -105,6 +105,7 @@ export default function HARFileViewer() {
>
handleFileUpload(event.target.files?.[0])}
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
@@ -287,6 +288,7 @@ const HarTable = ({ entries, activeFilter }: HarTableComponentProps) => {
{filteredAndSortedEntries.map((entry, index) => (
{
>
{entry.request.url}
- |
+ |
{entry.response.status}
|
|