Merge remote-tracking branch 'github/dev'
# Conflicts: # apps/api/src/vehicles/vehicles.service.spec.ts # apps/web/src/routes/dashboard.tsx
This commit is contained in:
6
.fusion/agents/agent-08d09be5-runlogs-run-4660e391.jsonl
Normal file
6
.fusion/agents/agent-08d09be5-runlogs-run-4660e391.jsonl
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{"timestamp":"2026-05-11T08:32:21.057Z","taskId":"","text":"I'll process","type":"text","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:21.650Z","taskId":"","text":" the pending message and","type":"text","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:22.226Z","taskId":"","text":" check for any ambient work","type":"text","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:22.936Z","taskId":"","text":" to do.\n\n","type":"text","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:26.150Z","taskId":"","text":"fn_read_messages","type":"tool","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:26.152Z","taskId":"","text":"fn_read_messages","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Messages (1):\\n[unread] [id: msg-383b984c] [from: agent:agent-c5dd19c0] Ack — I’ll treat FN-109 → FN-110 → FN-118 as the current visible VIN multi-match design/implementation/review chain and will ping you if any missing FN-071-era copy/state/a11y detail surfaces. (5/11/2026, 6:53:22 AM)\"}],\"details\":{\"messages\":[{\"id\":\"msg-383b984c\",\"fromId\":\"agent-c5dd19c0\",\"fromType\":\"agent\",\"toId\":\"agent-08d09be5\",\"toType\":\"agent\",\"content\":\"Ack — I’ll treat FN-109 → FN-110 → FN-118 as the current visible VIN multi-match design/implementation/review chain and will ping you if any missing FN-071-era copy/state/a11y detail surfaces.\",\"type\":\"agent-to-agent\",\"read\":false,\"metadata\":{\"replyTo\":{\"messageId\":\"msg-aa8af67a\"}},\"createdAt\":\"2026-05-11T06:53:22.554Z\",\"updatedAt\":\"2026-05-11T06:53:22.554Z\"}]}}","agent":"executor"}
|
||||||
2
.fusion/agents/agent-08d09be5-runlogs-run-66909f3d.jsonl
Normal file
2
.fusion/agents/agent-08d09be5-runlogs-run-66909f3d.jsonl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{"timestamp":"2026-05-11T09:56:46.105Z","taskId":"","text":"fn_read_messages","type":"tool","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:46.106Z","taskId":"","text":"fn_read_messages","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Messages (1):\\n[unread] [id: msg-383b984c] [from: agent:agent-c5dd19c0] Ack — I’ll treat FN-109 → FN-110 → FN-118 as the current visible VIN multi-match design/implementation/review chain and will ping you if any missing FN-071-era copy/state/a11y detail surfaces. (5/11/2026, 6:53:22 AM)\"}],\"details\":{\"messages\":[{\"id\":\"msg-383b984c\",\"fromId\":\"agent-c5dd19c0\",\"fromType\":\"agent\",\"toId\":\"agent-08d09be5\",\"toType\":\"agent\",\"content\":\"Ack — I’ll treat FN-109 → FN-110 → FN-118 as the current visible VIN multi-match design/implementation/review chain and will ping you if any missing FN-071-era copy/state/a11y detail surfaces.\",\"type\":\"agent-to-agent\",\"read\":false,\"metadata\":{\"replyTo\":{\"messageId\":\"msg-aa8af67a\"}},\"createdAt\":\"2026-05-11T06:53:22.554Z\",\"updatedAt\":\"2026-05-11T06:53:22.554Z\"}]}}","agent":"executor"}
|
||||||
4
.fusion/agents/agent-403a540b-runlogs-run-665bfcc8.jsonl
Normal file
4
.fusion/agents/agent-403a540b-runlogs-run-665bfcc8.jsonl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{"timestamp":"2026-05-11T09:56:24.759Z","taskId":"","text":"fn_read_messages","type":"tool","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:24.765Z","taskId":"","text":"fn_read_messages","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Messages (1):\\n[unread] [id: msg-f43c3406] [from: agent:agent-b5f64135] Ambient backend scan added FN-136 as a payment-critical follow-up to FN-100: `POST /payments/iyzico/callback` appears to be behind global AuthGuard (no `@Public()`), so provider callbacks may be rejected; making it public needs signature/token verification + idempotency. No code changes made. (5/11/2026, 6:53:44 AM)\"}],\"details\":{\"messages\":[{\"id\":\"msg-f43c3406\",\"fromId\":\"agent-b5f64135\",\"fromType\":\"agent\",\"toId\":\"agent-403a540b\",\"toType\":\"agent\",\"content\":\"Ambient backend scan added FN-136 as a payment-critical follow-up to FN-100: `POST /payments/iyzico/callback` appears to be behind global AuthGuard (no `@Public()`), so provider callbacks may be rejected; making it public needs signature/token verification + idempotency. No code changes made.\",\"type\":\"agent-to-agent\",\"read\":false,\"createdAt\":\"2026-05-11T06:53:44.055Z\",\"updatedAt\":\"2026-05-11T06:53:44.055Z\"}]}}","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:43.375Z","taskId":"","text":"fn_task_show","type":"tool","detail":"FN-136","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:43.459Z","taskId":"","text":"fn_task_show","type":"tool_error","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Task FN-136 not found\"}],\"details\":{}}","agent":"custom"}
|
||||||
4
.fusion/agents/agent-403a540b-runlogs-run-a5ece7fb.jsonl
Normal file
4
.fusion/agents/agent-403a540b-runlogs-run-a5ece7fb.jsonl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{"timestamp":"2026-05-11T08:32:27.478Z","taskId":"","text":"fn_read_messages","type":"tool","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:27.479Z","taskId":"","text":"fn_read_messages","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Messages (1):\\n[unread] [id: msg-f43c3406] [from: agent:agent-b5f64135] Ambient backend scan added FN-136 as a payment-critical follow-up to FN-100: `POST /payments/iyzico/callback` appears to be behind global AuthGuard (no `@Public()`), so provider callbacks may be rejected; making it public needs signature/token verification + idempotency. No code changes made. (5/11/2026, 6:53:44 AM)\"}],\"details\":{\"messages\":[{\"id\":\"msg-f43c3406\",\"fromId\":\"agent-b5f64135\",\"fromType\":\"agent\",\"toId\":\"agent-403a540b\",\"toType\":\"agent\",\"content\":\"Ambient backend scan added FN-136 as a payment-critical follow-up to FN-100: `POST /payments/iyzico/callback` appears to be behind global AuthGuard (no `@Public()`), so provider callbacks may be rejected; making it public needs signature/token verification + idempotency. No code changes made.\",\"type\":\"agent-to-agent\",\"read\":false,\"createdAt\":\"2026-05-11T06:53:44.055Z\",\"updatedAt\":\"2026-05-11T06:53:44.055Z\"}]}}","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:40.253Z","taskId":"","text":"fn_task_show","type":"tool","detail":"FN-136","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:40.327Z","taskId":"","text":"fn_task_show","type":"tool_error","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Task FN-136 not found\"}],\"details\":{}}","agent":"custom"}
|
||||||
11
.fusion/agents/agent-851fc17d-runlogs-run-3a98b1b7.jsonl
Normal file
11
.fusion/agents/agent-851fc17d-runlogs-run-3a98b1b7.jsonl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{"timestamp":"2026-05-11T08:32:25.142Z","taskId":"","text":"I'll","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:25.863Z","taskId":"","text":" scan for","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:26.401Z","taskId":"","text":" any recent project activity or issues","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:27.217Z","taskId":"","text":" that need attention","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:27.718Z","taskId":"","text":".\n\n","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:29.217Z","taskId":"","text":"fn_task_list","type":"tool","detail":"triage","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:29.269Z","taskId":"","text":"fn_task_list","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Planning (50):\\n FN-095 Investigate Fusion task board persistence/visibility mismatch\\n FN-096 Audit and fix hardcoded/ASCII Turkish UI copy in admin web r…\\n FN-098 UX/a11y copy cleanup: replace generic decorative SVG labels …\\n FN-106 QA coverage gap: establish a baseline frontend regression/E2…\\n FN-108 Reconcile duplicate task-board inconsistency follow-ups: dai…\\n FN-109 Designer follow-up: write a compact UX/i18n copy spec for VI…\\n FN-111 CPO product brief for FN-101 payment funnel completion analy…\\n FN-114 Frontend follow-up: audit and fix hardcoded/ASCII Turkish la…\\n FN-115 QA coverage gap: add unit tests for shared package schemas/u…\\n FN-118 Designer/QA follow-up after FN-110: review the implemented V… [deps: FN-110]\\n ... and 40 more\"}],\"details\":{\"count\":53}}","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:31.079Z","taskId":"","text":"Let me check for any urgent product issues","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:31.716Z","taskId":"","text":" that might need immediate attention.\n\n","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:32.741Z","taskId":"","text":"fn_task_list","type":"tool","detail":"in-progress","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:32.753Z","taskId":"","text":"fn_task_list","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"\"}],\"details\":{\"count\":53}}","agent":"custom"}
|
||||||
9
.fusion/agents/agent-851fc17d-runlogs-run-dd8a840f.jsonl
Normal file
9
.fusion/agents/agent-851fc17d-runlogs-run-dd8a840f.jsonl
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{"timestamp":"2026-05-11T09:56:21.527Z","taskId":"","text":"I'll start by checking for any messages and then review the","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:22.099Z","taskId":"","text":" current project state to determine the","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:22.657Z","taskId":"","text":" next action.\n\n","type":"text","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:23.752Z","taskId":"","text":"fn_read_messages","type":"tool","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:23.753Z","taskId":"","text":"fn_read_messages","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"No messages\"}],\"details\":{}}","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:32.510Z","taskId":"","text":"fn_task_list","type":"tool","detail":"todo","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:32.592Z","taskId":"","text":"fn_task_list","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"\"}],\"details\":{\"count\":1}}","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:41.646Z","taskId":"","text":"fn_task_list","type":"tool","detail":"in-progress","agent":"custom"}
|
||||||
|
{"timestamp":"2026-05-11T09:56:41.648Z","taskId":"","text":"fn_task_list","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"\"}],\"details\":{\"count\":1}}","agent":"custom"}
|
||||||
4
.fusion/agents/agent-9e7809e2-runlogs-run-6bc31239.jsonl
Normal file
4
.fusion/agents/agent-9e7809e2-runlogs-run-6bc31239.jsonl
Normal file
File diff suppressed because one or more lines are too long
14
.fusion/agents/agent-9e7809e2-runlogs-run-b0a21869.jsonl
Normal file
14
.fusion/agents/agent-9e7809e2-runlogs-run-b0a21869.jsonl
Normal file
File diff suppressed because one or more lines are too long
2
.fusion/agents/agent-b5f64135-runlogs-run-345d5f21.jsonl
Normal file
2
.fusion/agents/agent-b5f64135-runlogs-run-345d5f21.jsonl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{"timestamp":"2026-05-11T08:32:33.614Z","taskId":"","text":"fn_read_messages","type":"tool","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:33.615Z","taskId":"","text":"fn_read_messages","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"Messages (1):\\n[unread] [id: msg-f16ba506] [from: agent:agent-9e7809e2] Ack, thanks for keeping FN-117 scoped. I confirmed FN-128 exists for optional @sase/ui smoke coverage and created FN-142 as a QA-only follow-up to review the shared/config package test gate once FN-117 reaches review. (5/11/2026, 6:54:37 AM)\"}],\"details\":{\"messages\":[{\"id\":\"msg-f16ba506\",\"fromId\":\"agent-9e7809e2\",\"fromType\":\"agent\",\"toId\":\"agent-b5f64135\",\"toType\":\"agent\",\"content\":\"Ack, thanks for keeping FN-117 scoped. I confirmed FN-128 exists for optional @sase/ui smoke coverage and created FN-142 as a QA-only follow-up to review the shared/config package test gate once FN-117 reaches review.\",\"type\":\"agent-to-agent\",\"read\":false,\"metadata\":{\"replyTo\":{\"messageId\":\"msg-b24c2517\"}},\"createdAt\":\"2026-05-11T06:54:37.100Z\",\"updatedAt\":\"2026-05-11T06:54:37.100Z\"}]}}","agent":"executor"}
|
||||||
4
.fusion/agents/agent-b5f64135-runlogs-run-d3d3191a.jsonl
Normal file
4
.fusion/agents/agent-b5f64135-runlogs-run-d3d3191a.jsonl
Normal file
File diff suppressed because one or more lines are too long
13
.fusion/agents/agent-c5dd19c0-runlogs-run-3702ae74.jsonl
Normal file
13
.fusion/agents/agent-c5dd19c0-runlogs-run-3702ae74.jsonl
Normal file
File diff suppressed because one or more lines are too long
5
.fusion/agents/agent-c5dd19c0-runlogs-run-50290bed.jsonl
Normal file
5
.fusion/agents/agent-c5dd19c0-runlogs-run-50290bed.jsonl
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{"timestamp":"2026-05-11T08:32:23.338Z","taskId":"","text":"\n","type":"text","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:28.874Z","taskId":"","text":"fn_read_messages","type":"tool","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:28.875Z","taskId":"","text":"fn_task_list","type":"tool","detail":"in-progress","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:28.876Z","taskId":"","text":"fn_read_messages","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"No messages\"}],\"details\":{}}","agent":"executor"}
|
||||||
|
{"timestamp":"2026-05-11T08:32:28.954Z","taskId":"","text":"fn_task_list","type":"tool_result","detail":"{\"content\":[{\"type\":\"text\",\"text\":\"\"}],\"details\":{\"count\":53}}","agent":"executor"}
|
||||||
@@ -385,25 +385,27 @@ describe("VehiclesService", () => {
|
|||||||
where: vi.fn().mockReturnValue({
|
where: vi.fn().mockReturnValue({
|
||||||
orderBy: vi.fn().mockReturnValue({
|
orderBy: vi.fn().mockReturnValue({
|
||||||
limit: vi.fn().mockReturnValue({
|
limit: vi.fn().mockReturnValue({
|
||||||
offset: vi.fn().mockReturnValue(vehicleList)
|
offset: vi.fn().mockReturnValue(vehicleList),
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
|
});
|
||||||
|
const { service } = createService({
|
||||||
|
select: vi.fn().mockReturnValue({
|
||||||
|
from: vi.fn().mockReturnValue({
|
||||||
|
innerJoin: vi.fn().mockReturnValue({
|
||||||
|
where: vi.fn().mockReturnValue({
|
||||||
|
orderBy: vi.fn().mockReturnValue({
|
||||||
|
limit: vi.fn().mockReturnValue({
|
||||||
|
offset: vi.fn().mockReturnValue(vehicleList),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
const { service } = createService({select: vi.fn().mockReturnValue({
|
|
||||||
from: vi.fn().mockReturnValue({
|
|
||||||
innerJoin: vi.fn().mockReturnValue({
|
|
||||||
where: vi.fn().mockReturnValue({
|
|
||||||
orderBy: vi.fn().mockReturnValue({
|
|
||||||
limit: vi.fn().mockReturnValue({
|
|
||||||
offset: vi.fn().mockReturnValue(vehicleList)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})});
|
|
||||||
|
|
||||||
const result = await service.getHistory("u1", 1, 20);
|
const result = await service.getHistory("u1", 1, 20);
|
||||||
expect(result).toEqual(vehicleList);
|
expect(result).toEqual(vehicleList);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"locked": "This brand is not in your plan",
|
"locked": "This brand is not in your plan",
|
||||||
"upgradeCta": "Upgrade Plan",
|
"upgradeCta": "Upgrade Plan",
|
||||||
"loadingModels": "Loading models...",
|
"loadingModels": "Loading models...",
|
||||||
"tabSasetr": "Sase.Tr",
|
"tabSasetr": "SASE",
|
||||||
"tabPl24": "Pl24",
|
"tabPl24": "Pl24",
|
||||||
"tabPcat": "Pcat",
|
"tabPcat": "Pcat",
|
||||||
"tabEmex": "Emex",
|
"tabEmex": "Emex",
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"locked": "Bu marka planınızda yok",
|
"locked": "Bu marka planınızda yok",
|
||||||
"upgradeCta": "Planını Yükselt",
|
"upgradeCta": "Planını Yükselt",
|
||||||
"loadingModels": "Modeller yükleniyor...",
|
"loadingModels": "Modeller yükleniyor...",
|
||||||
"tabSasetr": "Sase.Tr",
|
"tabSasetr": "SASE",
|
||||||
"tabPl24": "Pl24",
|
"tabPl24": "Pl24",
|
||||||
"tabPcat": "Pcat",
|
"tabPcat": "Pcat",
|
||||||
"tabEmex": "Emex",
|
"tabEmex": "Emex",
|
||||||
|
|||||||
115
apps/web/src/routes/__tests__/index.test.tsx
Normal file
115
apps/web/src/routes/__tests__/index.test.tsx
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* Regression tests for landing page VIN decode analytics events.
|
||||||
|
*
|
||||||
|
* These tests verify that the correct PostHog events are captured on
|
||||||
|
* successful VIN decode and on error conditions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
||||||
|
import { BrowserRouter } from "react-router-dom";
|
||||||
|
import { vi } from "vitest";
|
||||||
|
|
||||||
|
// Mock the PostHog capture function
|
||||||
|
vi.mock("@/lib/posthog", () => ({
|
||||||
|
capture: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock the API client used for VIN decode
|
||||||
|
vi.mock("@/lib/api-client", () => ({
|
||||||
|
api: {
|
||||||
|
post: vi.fn(),
|
||||||
|
},
|
||||||
|
ApiError: class ApiError extends Error {
|
||||||
|
constructor(message: string, public code?: string, public status?: number) {
|
||||||
|
super(message);
|
||||||
|
this.name = "ApiError";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock the auth store to simulate a logged‑in user
|
||||||
|
vi.mock("@/stores/auth.store", () => {
|
||||||
|
const actual = vi.importActual("@/stores/auth.store");
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
useAuthStore: {
|
||||||
|
getState: vi.fn(),
|
||||||
|
subscribe: vi.fn(() => vi.fn()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mock navigation to avoid real router side‑effects
|
||||||
|
vi.mock("@tanstack/react-router", async () => {
|
||||||
|
const actual = await vi.importActual<any>("@tanstack/react-router");
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
useNavigate: () => vi.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
import { HomePage } from "@/routes/index"; // Exported component
|
||||||
|
import { capture } from "@/lib/posthog";
|
||||||
|
import { api, ApiError } from "@/lib/api-client";
|
||||||
|
import { useAuthStore } from "@/stores/auth.store";
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
(useAuthStore.getState as any).mockReturnValue({
|
||||||
|
user: { id: "user-1" },
|
||||||
|
isLoading: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("captures vin_decode_success on successful decode", async () => {
|
||||||
|
(api.post as any).mockResolvedValue({ id: "test-vehicle-id" });
|
||||||
|
|
||||||
|
render(
|
||||||
|
<BrowserRouter>
|
||||||
|
<HomePage />
|
||||||
|
</BrowserRouter>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const input = screen.getByPlaceholderText(/Örnek:/i);
|
||||||
|
fireEvent.change(input, { target: { value: "WVWZZZ1JZ3W597935" } });
|
||||||
|
const button = screen.getByRole("button", { name: /Ara/i });
|
||||||
|
fireEvent.click(button);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(capture).toHaveBeenCalledWith(
|
||||||
|
"vin_decode_success",
|
||||||
|
expect.objectContaining({
|
||||||
|
vin: "WVWZZZ1JZ3W597935",
|
||||||
|
source: "landing",
|
||||||
|
vehicle_id: "test-vehicle-id",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("captures vin_decode_error on API error", async () => {
|
||||||
|
const error = new ApiError("Invalid VIN", "INVALID", 400);
|
||||||
|
(api.post as any).mockRejectedValue(error);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<BrowserRouter>
|
||||||
|
<HomePage />
|
||||||
|
</BrowserRouter>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const input = screen.getByPlaceholderText(/Örnek:/i);
|
||||||
|
fireEvent.change(input, { target: { value: "INVALIDVIN1234567" } });
|
||||||
|
const button = screen.getByRole("button", { name: /Ara/i });
|
||||||
|
fireEvent.click(button);
|
||||||
|
|
||||||
|
await waitFor(async () => {
|
||||||
|
expect(capture).toHaveBeenCalledWith(
|
||||||
|
"vin_decode_error",
|
||||||
|
expect.objectContaining({
|
||||||
|
vin: "INVALIDVIN1234567",
|
||||||
|
source: "landing",
|
||||||
|
error: "Invalid VIN",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -18,9 +18,9 @@ function AuthLayout() {
|
|||||||
<div className="flex justify-center pt-6">
|
<div className="flex justify-center pt-6">
|
||||||
<Link
|
<Link
|
||||||
to="/"
|
to="/"
|
||||||
className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
|
className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground tracking-wider"
|
||||||
>
|
>
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ function AboutPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ function BlogPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -366,8 +366,8 @@ function BlogPostPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ function ContactPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -272,8 +272,8 @@ function DashboardLayout() {
|
|||||||
className={`flex h-16 items-center border-b border-border ${collapsed ? "justify-center px-2" : "justify-between px-4"}`}
|
className={`flex h-16 items-center border-b border-border ${collapsed ? "justify-center px-2" : "justify-between px-4"}`}
|
||||||
>
|
>
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
<Link to="/" className="text-xl font-bold tracking-tight">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
@@ -405,7 +405,7 @@ function DashboardLayout() {
|
|||||||
/>
|
/>
|
||||||
<aside className="absolute left-0 top-0 flex h-full w-64 flex-col bg-background shadow-lg">
|
<aside className="absolute left-0 top-0 flex h-full w-64 flex-col bg-background shadow-lg">
|
||||||
<div className="flex h-16 items-center justify-between border-b border-border px-4">
|
<div className="flex h-16 items-center justify-between border-b border-border px-4">
|
||||||
<span className="text-xl font-bold">Sase.tr</span>
|
<span className="text-xl font-bold tracking-wider">SASE</span>
|
||||||
<Button variant="ghost" size="icon" onClick={() => setMobileOpen(false)}>
|
<Button variant="ghost" size="icon" onClick={() => setMobileOpen(false)}>
|
||||||
<X className="size-4" />
|
<X className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ function DemoPage() {
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<header className="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
|
<header className="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
|
||||||
<div className="mx-auto flex h-16 max-w-5xl items-center justify-between px-4 sm:px-6">
|
<div className="mx-auto flex h-16 max-w-5xl items-center justify-between px-4 sm:px-6">
|
||||||
<Link to="/" className="text-xl font-bold tracking-tight">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -558,8 +558,8 @@ export function HomePage() {
|
|||||||
{/* ─── 1. STICKY HEADER ─────────────────────────────────────────── */}
|
{/* ─── 1. STICKY HEADER ─────────────────────────────────────────── */}
|
||||||
<header className="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
|
<header className="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
|
||||||
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6">
|
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6">
|
||||||
<Link to="/" className="text-xl font-bold tracking-tight">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Desktop nav */}
|
{/* Desktop nav */}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ function KvkkPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ function PricingPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ function PrivacyPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ function TermsPage() {
|
|||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||||
<Link to="/" className="text-xl font-bold">
|
<Link to="/" className="text-xl font-bold tracking-wider">
|
||||||
Sase.tr
|
SASE
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Link to="/login">
|
<Link to="/login">
|
||||||
|
|||||||
@@ -18,5 +18,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src", "vite-env.d.ts"],
|
"include": ["src", "vite-env.d.ts"],
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist", "**/__tests__/**", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user