refactor(web): extract ResourcesClient types + inline components, fix test TS errors

Extract types.ts, FilterDropdown.tsx, BooleanBadge.tsx from
ResourcesClient.tsx into resource-client/ subdirectory.
ResourcesClient reduced from 1,613 to 1,507 lines.

Fix TypeScript strict mode errors across 8 test files:
- Add id/order to BlueprintFieldDefinition test objects
- Use FieldType enum instead of string literals in useFilters
- Add non-null assertions for mock.calls array access
- Type ScrollDiv for jsdom scrollLeft workaround
- Fix exactOptionalPropertyTypes violations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 22:40:24 +02:00
parent dcac9952ca
commit d3f721ce58
13 changed files with 217 additions and 162 deletions
@@ -41,7 +41,14 @@ describe("canGoNext", () => {
shortCode: "PRJ01",
name: "Test",
blueprintFieldDefs: [
{ key: "field1", type: "TEXT" as never, label: "Field 1", required: true },
{
id: "f1",
key: "field1",
type: "TEXT" as never,
label: "Field 1",
required: true,
order: 0,
},
],
dynamicFields: {},
});
@@ -53,7 +60,14 @@ describe("canGoNext", () => {
shortCode: "PRJ01",
name: "Test",
blueprintFieldDefs: [
{ key: "field1", type: "TEXT" as never, label: "Field 1", required: true },
{
id: "f1",
key: "field1",
type: "TEXT" as never,
label: "Field 1",
required: true,
order: 0,
},
],
dynamicFields: { field1: "value" },
});
@@ -65,7 +79,14 @@ describe("canGoNext", () => {
shortCode: "PRJ01",
name: "Test",
blueprintFieldDefs: [
{ key: "tags", type: "TAG_LIST" as never, label: "Tags", required: true },
{
id: "f2",
key: "tags",
type: "TAG_LIST" as never,
label: "Tags",
required: true,
order: 0,
},
],
dynamicFields: { tags: [] },
});
@@ -77,7 +98,14 @@ describe("canGoNext", () => {
shortCode: "PRJ01",
name: "Test",
blueprintFieldDefs: [
{ key: "optional", type: "TEXT" as never, label: "Optional", required: false },
{
id: "f3",
key: "optional",
type: "TEXT" as never,
label: "Optional",
required: false,
order: 0,
},
],
dynamicFields: {},
});
@@ -153,7 +181,7 @@ describe("canGoNext", () => {
});
it("returns false when a requirement has empty role and no roleId", () => {
const req = { ...makeReq(), role: "", roleId: undefined, hoursPerDay: 8, headcount: 1 };
const req = { ...makeReq(), role: "", hoursPerDay: 8, headcount: 1 };
const state = stateWith({ staffingReqs: [req] });
expect(canGoNext(2, state)).toBe(false);
});
@@ -1,7 +1,7 @@
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import { render, screen } from "~/test-utils.js";
import userEvent from "@testing-library/user-event";
import type { ErrorInfo } from "react";
import React, { type ErrorInfo } from "react";
import { ErrorBoundary, DefaultErrorFallback } from "./ErrorBoundary.js";
// Suppress React's console.error output during error boundary tests
@@ -16,7 +16,7 @@ afterEach(() => {
});
// A component that unconditionally throws
function ThrowingChild({ message = "Test error" }: { message?: string }) {
function ThrowingChild({ message = "Test error" }: { message?: string }): React.ReactNode {
throw new Error(message);
}
@@ -131,7 +131,7 @@ describe("ErrorBoundary", () => {
});
it("shows a generic message when error.message is empty", () => {
function ThrowEmptyMessage() {
function ThrowEmptyMessage(): React.ReactNode {
const e = new Error("");
throw e;
}
@@ -88,7 +88,9 @@ describe("ShimmerSkeleton", () => {
});
describe("rounded prop", () => {
const roundedCases: Array<[React.ComponentProps<typeof ShimmerSkeleton>["rounded"], string]> = [
const roundedCases: Array<
[NonNullable<React.ComponentProps<typeof ShimmerSkeleton>["rounded"]>, string]
> = [
["sm", "rounded-sm"],
["md", "rounded-md"],
["lg", "rounded-lg"],