fix(web): resolve TypeScript errors in test mocks and knowledge-base page

- Add missing Issue fields (parent_issue_id, acceptance_criteria, etc.) to test mocks
- Fix Agent mock fields to match actual type (runtime_config, owner_id, avatar_url)
- Import vi in test/helpers.tsx and add type annotation for mockAuthValue
- Add non-null assertions for array indexing in knowledge-base markdown renderer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jiayuan Zhang 2026-03-22 11:57:23 +08:00
parent c9285035d1
commit 18cd938e01
5 changed files with 38 additions and 19 deletions

View file

@ -74,6 +74,11 @@ const mockIssue: Issue = {
assignee_id: "user-1",
creator_type: "member",
creator_id: "user-1",
parent_issue_id: null,
acceptance_criteria: [],
context_refs: [],
repository: null,
position: 0,
due_date: "2026-06-01T00:00:00Z",
created_at: "2026-01-15T00:00:00Z",
updated_at: "2026-01-20T00:00:00Z",

View file

@ -62,8 +62,17 @@ vi.mock("../../../lib/api", () => ({
},
}));
const issueDefaults = {
parent_issue_id: null,
acceptance_criteria: [],
context_refs: [],
repository: null,
position: 0,
};
const mockIssues: Issue[] = [
{
...issueDefaults,
id: "issue-1",
workspace_id: "ws-1",
title: "Implement auth",
@ -79,6 +88,7 @@ const mockIssues: Issue[] = [
updated_at: "2026-01-01T00:00:00Z",
},
{
...issueDefaults,
id: "issue-2",
workspace_id: "ws-1",
title: "Design landing page",
@ -94,6 +104,7 @@ const mockIssues: Issue[] = [
updated_at: "2026-01-01T00:00:00Z",
},
{
...issueDefaults,
id: "issue-3",
workspace_id: "ws-1",
title: "Write tests",
@ -210,6 +221,7 @@ describe("IssuesPage", () => {
} as ListIssuesResponse);
const newIssue: Issue = {
...issueDefaults,
id: "issue-new",
workspace_id: "ws-1",
title: "New test issue",

View file

@ -31,15 +31,15 @@ function renderMarkdown(text: string): React.ReactNode[] {
let i = 0;
while (i < lines.length) {
const line = lines[i];
const line = lines[i]!;
// Code block
if (line.startsWith("```")) {
const lang = line.slice(3).trim();
const codeLines: string[] = [];
i++;
while (i < lines.length && !lines[i].startsWith("```")) {
codeLines.push(lines[i]);
while (i < lines.length && !lines[i]!.startsWith("```")) {
codeLines.push(lines[i]!);
i++;
}
i++; // skip closing ```
@ -57,8 +57,8 @@ function renderMarkdown(text: string): React.ReactNode[] {
// Table (simplified: detect | pipes)
if (line.includes("|") && line.trim().startsWith("|")) {
const tableRows: string[] = [];
while (i < lines.length && lines[i].includes("|") && lines[i].trim().startsWith("|")) {
tableRows.push(lines[i]);
while (i < lines.length && lines[i]!.includes("|") && lines[i]!.trim().startsWith("|")) {
tableRows.push(lines[i]!);
i++;
}
// Filter out separator rows (|---|---|)
@ -66,7 +66,7 @@ function renderMarkdown(text: string): React.ReactNode[] {
if (dataRows.length > 0) {
const parseRow = (row: string) =>
row.split("|").filter((c) => c.trim() !== "").map((c) => c.trim());
const header = parseRow(dataRows[0]);
const header = parseRow(dataRows[0]!);
const body = dataRows.slice(1).map(parseRow);
elements.push(
<div key={`table-${i}`} className="my-3 overflow-x-auto">
@ -103,7 +103,7 @@ function renderMarkdown(text: string): React.ReactNode[] {
elements.push(
<h2 key={`h2-${i}`} className="mt-6 mb-2 text-[15px] font-semibold">
{line.slice(3)}
</h2>
</h2>,
);
i++;
continue;
@ -112,14 +112,14 @@ function renderMarkdown(text: string): React.ReactNode[] {
elements.push(
<h3 key={`h3-${i}`} className="mt-4 mb-1.5 text-[14px] font-medium">
{line.slice(4)}
</h3>
</h3>,
);
i++;
continue;
}
// List item
if (line.match(/^- \[[ x]\] /)) {
if (/^- \[[ x]\] /.test(line)) {
const checked = line.includes("[x]");
const text = line.replace(/^- \[[ x]\] /, "");
elements.push(
@ -142,8 +142,8 @@ function renderMarkdown(text: string): React.ReactNode[] {
continue;
}
// Numbered list
if (line.match(/^\d+\. /)) {
const num = line.match(/^(\d+)\. /)![1];
if (/^\d+\. /.test(line)) {
const num = line.match(/^(\d+)\. /)![1]!;
const text = line.replace(/^\d+\. /, "");
elements.push(
<div key={`ol-${i}`} className="flex gap-2 py-0.5 text-[13px] text-foreground/80">
@ -155,7 +155,7 @@ function renderMarkdown(text: string): React.ReactNode[] {
continue;
}
// Empty line
// Empty line — guard is redundant since line is already asserted, but keeps TS happy
if (line.trim() === "") {
elements.push(<div key={`br-${i}`} className="h-2" />);
i++;

View file

@ -72,13 +72,13 @@ const mockAgents: Agent[] = [
id: "agent-1",
workspace_id: "ws-1",
name: "Claude",
avatar_url: null,
status: "idle",
runtime_mode: "cloud",
runtime_config: {},
visibility: "workspace",
max_concurrent_tasks: 3,
description: null,
system_prompt: null,
config: {},
owner_id: null,
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-01T00:00:00Z",
},

View file

@ -1,4 +1,5 @@
import React from "react";
import { vi } from "vitest";
import { render, type RenderOptions } from "@testing-library/react";
import type { User, Workspace, MemberWithUser, Agent } from "@multica/types";
@ -43,20 +44,21 @@ export const mockAgents: Agent[] = [
id: "agent-1",
workspace_id: "ws-1",
name: "Claude Agent",
avatar_url: null,
status: "idle",
runtime_mode: "cloud",
runtime_config: {},
visibility: "workspace",
max_concurrent_tasks: 3,
description: "A test agent",
system_prompt: null,
config: {},
owner_id: null,
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-01T00:00:00Z",
},
];
// Mock auth context value
export const mockAuthValue = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const mockAuthValue: Record<string, any> = {
user: mockUser,
workspace: mockWorkspace,
members: mockMembers,