Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,15 @@ vi.mock("antd", () => {

Form.useForm = () => [formMock];

const Select = ({ children, onChange, ...props }: { children?: any; onChange?: (value: string) => void }) =>
const Select = ({ children, onChange, options, ...props }: { children?: any; onChange?: (value: string) => void; options?: Array<{ value: string; label: string }> }) =>
React.createElement(
"select",
{
...props,
onChange: (event: any) => onChange?.(event.target.value),
},
children,
options?.map((opt: any) => React.createElement("option", { key: opt.value, value: opt.value }, opt.label)),
);

Select.Option = ({ children, ...props }: { children?: any }) =>
Expand Down Expand Up @@ -238,6 +239,16 @@ vi.mock("../key_team_helpers/fetch_available_models_team_key", () => ({
getModelDisplayName: (model: string) => model,
}));

vi.mock("@/app/(dashboard)/hooks/tags/useTags", () => ({
useTags: vi.fn().mockReturnValue({
data: [
{ name: "production", description: "Prod tag", models: [], created_at: "2026-01-01", updated_at: "2026-01-01" },
{ name: "staging", description: "Staging tag", models: [], created_at: "2026-01-01", updated_at: "2026-01-01" },
],
isLoading: false,
}),
}));
Comment on lines +242 to +250
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Mock shape doesn't match TagListResponse

TagListResponse is defined as Record<string, Tag> — an object keyed by tag name — but the mock returns data as a plain array:

// Actual shape returned by the real API
{ "production": { name: "production", ... }, "staging": { name: "staging", ... } }

// What the mock returns
[{ name: "production", ... }, { name: "staging", ... }]

The test passes today because Object.values() happens to work on arrays too (returning the elements), so the component's mapping logic produces the same result. However, the mock inaccurately represents the real response, which means any future branch that checks the shape of tagsData (e.g. Array.isArray, key access, Object.keys) would behave differently under test than in production.

Consider updating the mock to match the real Record<string, Tag> shape:

Suggested change
vi.mock("@/app/(dashboard)/hooks/tags/useTags", () => ({
useTags: vi.fn().mockReturnValue({
data: [
{ name: "production", description: "Prod tag", models: [], created_at: "2026-01-01", updated_at: "2026-01-01" },
{ name: "staging", description: "Staging tag", models: [], created_at: "2026-01-01", updated_at: "2026-01-01" },
],
isLoading: false,
}),
}));
vi.mock("@/app/(dashboard)/hooks/tags/useTags", () => ({
useTags: vi.fn().mockReturnValue({
data: {
production: { name: "production", description: "Prod tag", models: [], created_at: "2026-01-01", updated_at: "2026-01-01" },
staging: { name: "staging", description: "Staging tag", models: [], created_at: "2026-01-01", updated_at: "2026-01-01" },
},
isLoading: false,
}),
}));

Rule Used: # Code Review Rule: Mock Test Integrity

What:... (source)


vi.mock("@/app/(dashboard)/hooks/projects/useProjects", () => ({
useProjects: vi.fn().mockReturnValue({ data: [], isLoading: false }),
}));
Expand Down Expand Up @@ -525,4 +536,19 @@ describe("CreateKey", () => {
expect(formStateRef.current["organization_id"]).toBe("org-1");
});
});

describe("tags dropdown", () => {
it("should populate tags dropdown with options from useTags hook", async () => {
renderWithProviders(<CreateKey {...defaultProps} />);

act(() => {
fireEvent.click(screen.getByRole("button", { name: /create new key/i }));
});

await waitFor(() => {
expect(screen.getByText("production")).toBeInTheDocument();
expect(screen.getByText("staging")).toBeInTheDocument();
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { keyKeys } from "@/app/(dashboard)/hooks/keys/useKeys";
import { useOrganizations } from "@/app/(dashboard)/hooks/organizations/useOrganizations";
import { useProjects } from "@/app/(dashboard)/hooks/projects/useProjects";
import { useTags } from "@/app/(dashboard)/hooks/tags/useTags";
import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
import { formatNumberWithCommas } from "@/utils/dataUtils";
Expand Down Expand Up @@ -165,8 +166,12 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey, autoOp
const { data: organizations, isLoading: isOrganizationsLoading } = useOrganizations();
const { data: projects, isLoading: isProjectsLoading } = useProjects();
const { data: uiSettingsData } = useUISettings();
const { data: tagsData } = useTags();
const enableProjectsUI = Boolean(uiSettingsData?.values?.enable_projects_ui);
const disableCustomApiKeys = Boolean(uiSettingsData?.values?.disable_custom_api_keys);
const tagOptions = tagsData
? Object.values(tagsData).map((tag) => ({ value: tag.name, label: tag.name }))
: [];
const queryClient = useQueryClient();
const [form] = Form.useForm();
const [isModalVisible, setIsModalVisible] = useState(false);
Expand All @@ -175,7 +180,6 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey, autoOp
const [userModels, setUserModels] = useState<string[]>([]);
const [modelsToPick, setModelsToPick] = useState<string[]>([]);
const [keyOwner, setKeyOwner] = useState("you");
const [predefinedTags, setPredefinedTags] = useState(getPredefinedTags(data));
const [hasPrefilled, setHasPrefilled] = useState(false);
const [pendingPrefillModels, setPendingPrefillModels] = useState<string[] | null>(null);
const [guardrailsList, setGuardrailsList] = useState<string[]>([]);
Expand Down Expand Up @@ -1340,9 +1344,9 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey, autoOp
<Select
mode="tags"
style={{ width: "100%" }}
placeholder="Enter tags"
placeholder="Select or enter tags"
tokenSeparators={[","]}
options={predefinedTags}
options={tagOptions}
/>
</Form.Item>
<Accordion className="mt-4 mb-4">
Expand Down
Loading