From c04b149756497e145488caef5642e58405880b26 Mon Sep 17 00:00:00 2001 From: kawa Date: Wed, 26 Aug 2026 17:34:43 +0200 Subject: [PATCH] fix: resolve TypeScript compilation errors in Docker build - Add vitest globals type definitions to tsconfig.app.json - Enable globals in vite.config.ts test configuration - Add explicit vitest imports and type references to all .test.ts files - Add missing `placeholder` property to PasswordFieldProps interface - Add missing `required` field to test field definitions in FieldRenderer.test.tsx - Update FieldDef and BackendMeta interfaces to support readonly arrays - Fix readonly array type incompatibilities in BackendSelectionStep.tsx - Fix form submission handler type mismatch in RemoteConfigStep.tsx - Remove unused helper functions and imports from StepIndicator.test.tsx These changes resolve all TypeScript compilation errors preventing the Docker build from completing. Co-Authored-By: Claude Haiku 4.5 --- src/components/ui/FieldRenderer.test.tsx | 2 + src/components/ui/PasswordField.tsx | 4 +- .../wizard/BackendSelectionStep.tsx | 2 +- src/components/wizard/RemoteConfigStep.tsx | 4 +- src/components/wizard/StepIndicator.test.tsx | 58 +------------------ src/generators/intune-detection.test.ts | 2 + src/generators/intune-install.test.ts | 2 + src/generators/rclone-conf.test.ts | 2 + src/generators/rmm-script.test.ts | 2 + src/schemas/registry.ts | 4 +- tsconfig.app.json | 1 + vite.config.ts | 1 + 12 files changed, 21 insertions(+), 63 deletions(-) diff --git a/src/components/ui/FieldRenderer.test.tsx b/src/components/ui/FieldRenderer.test.tsx index 6c8c232..2ae492b 100644 --- a/src/components/ui/FieldRenderer.test.tsx +++ b/src/components/ui/FieldRenderer.test.tsx @@ -17,6 +17,7 @@ const textFieldWithTooltip = { key: 'bucket_name', label: 'Bucket Name', inputType: 'text' as const, + required: true, tooltipText: 'The name of your storage bucket', }; @@ -24,6 +25,7 @@ const selectFieldWithTooltip = { key: 'region', label: 'Region', inputType: 'select' as const, + required: true, tooltipText: 'Select your deployment region', options: [ { value: 'us-east', label: 'US East' }, diff --git a/src/components/ui/PasswordField.tsx b/src/components/ui/PasswordField.tsx index 91da6e4..2e4c8a9 100644 --- a/src/components/ui/PasswordField.tsx +++ b/src/components/ui/PasswordField.tsx @@ -7,11 +7,12 @@ interface PasswordFieldProps { label: string; error?: FieldError; registration: UseFormRegisterReturn; + placeholder?: string; helpText?: string; tooltipText?: string; } -export function PasswordField({ id, label, error, registration, helpText, tooltipText }: PasswordFieldProps) { +export function PasswordField({ id, label, error, registration, placeholder, helpText, tooltipText }: PasswordFieldProps) { const [show, setShow] = useState(false); const [showTooltip, setShowTooltip] = useState(false); const [hoverTooltip, setHoverTooltip] = useState(false); @@ -49,6 +50,7 @@ export function PasswordField({ id, label, error, registration, helpText, toolti label={label} error={error} registration={registration} + placeholder={placeholder} type={show ? 'text' : 'password'} helpText={helpText} helpTextPrefix={tooltipIcon} diff --git a/src/components/wizard/BackendSelectionStep.tsx b/src/components/wizard/BackendSelectionStep.tsx index 34ce721..505bb67 100644 --- a/src/components/wizard/BackendSelectionStep.tsx +++ b/src/components/wizard/BackendSelectionStep.tsx @@ -32,7 +32,7 @@ const CATEGORY_LABELS: Record = { }; function matchesSearch( - entry: { displayName: string; description: string; category: BackendCategory; fields: { label: string }[] }, + entry: { displayName: string; description: string; category: BackendCategory; fields: readonly { label: string }[] }, query: string ): boolean { const q = query.toLowerCase(); diff --git a/src/components/wizard/RemoteConfigStep.tsx b/src/components/wizard/RemoteConfigStep.tsx index df00329..9dbe480 100644 --- a/src/components/wizard/RemoteConfigStep.tsx +++ b/src/components/wizard/RemoteConfigStep.tsx @@ -210,8 +210,8 @@ export function RemoteConfigStep() { return null; } - const onNext = (values: Record) => { - dispatch({ type: 'SET_REMOTE_PARAMS', payload: values }); + const onNext = (values: Record) => { + dispatch({ type: 'SET_REMOTE_PARAMS', payload: values as Record }); dispatch({ type: 'SET_STEP', payload: 2 }); }; diff --git a/src/components/wizard/StepIndicator.test.tsx b/src/components/wizard/StepIndicator.test.tsx index d5dcacb..665f3f3 100644 --- a/src/components/wizard/StepIndicator.test.tsx +++ b/src/components/wizard/StepIndicator.test.tsx @@ -1,6 +1,6 @@ // @vitest-environment jsdom // Covers WIZD-03: going back preserves remote.params; deployment options are untouched -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -8,62 +8,6 @@ import { StepIndicator } from './StepIndicator'; import { WizardProvider } from '../../store/context'; import { useWizard } from '../../store/context'; -// Helper: renders StepIndicator with a given currentStep by navigating the wizard state -function renderWithStep(currentStep: number) { - // We need a wrapper that sets the step before rendering StepIndicator - function Wrapper() { - const { dispatch } = useWizard(); - React.useEffect(() => { - if (currentStep > 0) { - dispatch({ type: 'SET_STEP', payload: currentStep }); - } - }, [dispatch]); - return ; - } - - return render( - - - - ); -} - -// Helper: renders StepIndicator with a spy dispatch -function renderWithDispatchSpy(currentStep: number) { - const dispatched: { type: string; payload?: unknown }[] = []; - - function SpyWrapper() { - const { dispatch, state } = useWizard(); - React.useEffect(() => { - if (currentStep > 0) { - dispatch({ type: 'SET_STEP', payload: currentStep }); - } - }, [dispatch]); - - // Wrap dispatch to spy on calls after initial setup - const spyDispatch = React.useCallback( - (action: { type: string; payload?: unknown }) => { - dispatched.push(action); - dispatch(action as Parameters[0]); - }, - [dispatch] - ); - - return ( -
- {state.currentStep} - -
- ); - } - - // We'll test dispatch behavior by checking actual state changes instead - return { dispatched, ...render() }; -} - -// A version of StepIndicator that accepts an optional dispatch override for testing -// Actually we'll just test via rendered output and state changes - describe('StepIndicator', () => { describe('WIZD-03: back navigation preserves state', () => { it('step 0 shows as active when currentStep is 0', async () => { diff --git a/src/generators/intune-detection.test.ts b/src/generators/intune-detection.test.ts index bf7756f..976fc9a 100644 --- a/src/generators/intune-detection.test.ts +++ b/src/generators/intune-detection.test.ts @@ -1,7 +1,9 @@ +/// // src/generators/intune-detection.test.ts // Tests for buildIntuneDetection — Intune PowerShell detection script generator. // RED: imports will fail until Plan 02-03 creates intune-detection.ts. +import { describe, it, expect } from 'vitest'; import { buildIntuneDetection } from './intune-detection'; import { INITIAL_STATE } from '../store/types'; import type { WizardState } from '../store/types'; diff --git a/src/generators/intune-install.test.ts b/src/generators/intune-install.test.ts index 8d61cf8..b493f80 100644 --- a/src/generators/intune-install.test.ts +++ b/src/generators/intune-install.test.ts @@ -1,7 +1,9 @@ +/// // src/generators/intune-install.test.ts // Tests for buildIntuneInstall — Intune PowerShell install script generator. // RED: imports will fail until Plan 02-02 creates intune-install.ts. +import { describe, it, expect } from 'vitest'; import { buildIntuneInstall } from './intune-install'; import { INITIAL_STATE } from '../store/types'; import type { WizardState } from '../store/types'; diff --git a/src/generators/rclone-conf.test.ts b/src/generators/rclone-conf.test.ts index beaa949..c6b53fe 100644 --- a/src/generators/rclone-conf.test.ts +++ b/src/generators/rclone-conf.test.ts @@ -1,6 +1,8 @@ +/// // src/generators/rclone-conf.test.ts // Tests for buildRcloneConf — rclone INI config generator. +import { describe, it, expect } from 'vitest'; import { buildRcloneConf, RCLONE_TYPE_MAP } from './rclone-conf'; import { BACKEND_REGISTRY, BackendType } from '../schemas/registry'; import { INITIAL_STATE } from '../store/types'; diff --git a/src/generators/rmm-script.test.ts b/src/generators/rmm-script.test.ts index 5b58f9c..fd45389 100644 --- a/src/generators/rmm-script.test.ts +++ b/src/generators/rmm-script.test.ts @@ -1,7 +1,9 @@ +/// // src/generators/rmm-script.test.ts // Tests for buildRmmScript — RMM (NinjaRMM / Datto etc.) PowerShell script generator. // RED: imports will fail until Plan 02-04 creates rmm-script.ts. +import { describe, it, expect } from 'vitest'; import { buildRmmScript } from './rmm-script'; import { INITIAL_STATE } from '../store/types'; import type { WizardState } from '../store/types'; diff --git a/src/schemas/registry.ts b/src/schemas/registry.ts index 50a7dc8..ce78e0c 100644 --- a/src/schemas/registry.ts +++ b/src/schemas/registry.ts @@ -16,7 +16,7 @@ export interface FieldDef { required: boolean; placeholder?: string; helpText?: string; - options?: { value: string; label: string }[]; // for inputType: 'select' + options?: readonly { value: string; label: string }[]; // for inputType: 'select' validate?: { regex: RegExp; message: string }; tooltipText?: string; } @@ -25,7 +25,7 @@ export interface BackendMeta { displayName: string; description: string; category: BackendCategory; - fields: FieldDef[]; + fields: readonly FieldDef[]; } export const BACKEND_REGISTRY = { diff --git a/tsconfig.app.json b/tsconfig.app.json index 358ca9b..0d8586a 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -6,6 +6,7 @@ "lib": ["ES2020", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, + "types": ["vitest/globals"], /* Bundler mode */ "moduleResolution": "bundler", diff --git a/vite.config.ts b/vite.config.ts index 93d8981..7ca1c95 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,6 +5,7 @@ import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [react(), tailwindcss()], test: { + globals: true, environment: 'jsdom', passWithNoTests: true, },