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 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ const textFieldWithTooltip = {
|
|||||||
key: 'bucket_name',
|
key: 'bucket_name',
|
||||||
label: 'Bucket Name',
|
label: 'Bucket Name',
|
||||||
inputType: 'text' as const,
|
inputType: 'text' as const,
|
||||||
|
required: true,
|
||||||
tooltipText: 'The name of your storage bucket',
|
tooltipText: 'The name of your storage bucket',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ const selectFieldWithTooltip = {
|
|||||||
key: 'region',
|
key: 'region',
|
||||||
label: 'Region',
|
label: 'Region',
|
||||||
inputType: 'select' as const,
|
inputType: 'select' as const,
|
||||||
|
required: true,
|
||||||
tooltipText: 'Select your deployment region',
|
tooltipText: 'Select your deployment region',
|
||||||
options: [
|
options: [
|
||||||
{ value: 'us-east', label: 'US East' },
|
{ value: 'us-east', label: 'US East' },
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ interface PasswordFieldProps {
|
|||||||
label: string;
|
label: string;
|
||||||
error?: FieldError;
|
error?: FieldError;
|
||||||
registration: UseFormRegisterReturn;
|
registration: UseFormRegisterReturn;
|
||||||
|
placeholder?: string;
|
||||||
helpText?: string;
|
helpText?: string;
|
||||||
tooltipText?: 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 [show, setShow] = useState(false);
|
||||||
const [showTooltip, setShowTooltip] = useState(false);
|
const [showTooltip, setShowTooltip] = useState(false);
|
||||||
const [hoverTooltip, setHoverTooltip] = useState(false);
|
const [hoverTooltip, setHoverTooltip] = useState(false);
|
||||||
@@ -49,6 +50,7 @@ export function PasswordField({ id, label, error, registration, helpText, toolti
|
|||||||
label={label}
|
label={label}
|
||||||
error={error}
|
error={error}
|
||||||
registration={registration}
|
registration={registration}
|
||||||
|
placeholder={placeholder}
|
||||||
type={show ? 'text' : 'password'}
|
type={show ? 'text' : 'password'}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
helpTextPrefix={tooltipIcon}
|
helpTextPrefix={tooltipIcon}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const CATEGORY_LABELS: Record<BackendCategory, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function matchesSearch(
|
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
|
query: string
|
||||||
): boolean {
|
): boolean {
|
||||||
const q = query.toLowerCase();
|
const q = query.toLowerCase();
|
||||||
|
|||||||
@@ -210,8 +210,8 @@ export function RemoteConfigStep() {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onNext = (values: Record<string, string>) => {
|
const onNext = (values: Record<string, unknown>) => {
|
||||||
dispatch({ type: 'SET_REMOTE_PARAMS', payload: values });
|
dispatch({ type: 'SET_REMOTE_PARAMS', payload: values as Record<string, string> });
|
||||||
dispatch({ type: 'SET_STEP', payload: 2 });
|
dispatch({ type: 'SET_STEP', payload: 2 });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @vitest-environment jsdom
|
// @vitest-environment jsdom
|
||||||
// Covers WIZD-03: going back preserves remote.params; deployment options are untouched
|
// 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 { render, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@@ -8,62 +8,6 @@ import { StepIndicator } from './StepIndicator';
|
|||||||
import { WizardProvider } from '../../store/context';
|
import { WizardProvider } from '../../store/context';
|
||||||
import { useWizard } 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 <StepIndicator />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return render(
|
|
||||||
<WizardProvider>
|
|
||||||
<Wrapper />
|
|
||||||
</WizardProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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<typeof dispatch>[0]);
|
|
||||||
},
|
|
||||||
[dispatch]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<span data-testid="current-step">{state.currentStep}</span>
|
|
||||||
<StepIndicatorWithDispatch dispatch={spyDispatch} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll test dispatch behavior by checking actual state changes instead
|
|
||||||
return { dispatched, ...render(<WizardProvider><SpyWrapper /></WizardProvider>) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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('StepIndicator', () => {
|
||||||
describe('WIZD-03: back navigation preserves state', () => {
|
describe('WIZD-03: back navigation preserves state', () => {
|
||||||
it('step 0 shows as active when currentStep is 0', async () => {
|
it('step 0 shows as active when currentStep is 0', async () => {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
/// <reference types="vitest" />
|
||||||
// src/generators/intune-detection.test.ts
|
// src/generators/intune-detection.test.ts
|
||||||
// Tests for buildIntuneDetection — Intune PowerShell detection script generator.
|
// Tests for buildIntuneDetection — Intune PowerShell detection script generator.
|
||||||
// RED: imports will fail until Plan 02-03 creates intune-detection.ts.
|
// RED: imports will fail until Plan 02-03 creates intune-detection.ts.
|
||||||
|
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { buildIntuneDetection } from './intune-detection';
|
import { buildIntuneDetection } from './intune-detection';
|
||||||
import { INITIAL_STATE } from '../store/types';
|
import { INITIAL_STATE } from '../store/types';
|
||||||
import type { WizardState } from '../store/types';
|
import type { WizardState } from '../store/types';
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
/// <reference types="vitest" />
|
||||||
// src/generators/intune-install.test.ts
|
// src/generators/intune-install.test.ts
|
||||||
// Tests for buildIntuneInstall — Intune PowerShell install script generator.
|
// Tests for buildIntuneInstall — Intune PowerShell install script generator.
|
||||||
// RED: imports will fail until Plan 02-02 creates intune-install.ts.
|
// RED: imports will fail until Plan 02-02 creates intune-install.ts.
|
||||||
|
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { buildIntuneInstall } from './intune-install';
|
import { buildIntuneInstall } from './intune-install';
|
||||||
import { INITIAL_STATE } from '../store/types';
|
import { INITIAL_STATE } from '../store/types';
|
||||||
import type { WizardState } from '../store/types';
|
import type { WizardState } from '../store/types';
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
/// <reference types="vitest" />
|
||||||
// src/generators/rclone-conf.test.ts
|
// src/generators/rclone-conf.test.ts
|
||||||
// Tests for buildRcloneConf — rclone INI config generator.
|
// Tests for buildRcloneConf — rclone INI config generator.
|
||||||
|
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { buildRcloneConf, RCLONE_TYPE_MAP } from './rclone-conf';
|
import { buildRcloneConf, RCLONE_TYPE_MAP } from './rclone-conf';
|
||||||
import { BACKEND_REGISTRY, BackendType } from '../schemas/registry';
|
import { BACKEND_REGISTRY, BackendType } from '../schemas/registry';
|
||||||
import { INITIAL_STATE } from '../store/types';
|
import { INITIAL_STATE } from '../store/types';
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
/// <reference types="vitest" />
|
||||||
// src/generators/rmm-script.test.ts
|
// src/generators/rmm-script.test.ts
|
||||||
// Tests for buildRmmScript — RMM (NinjaRMM / Datto etc.) PowerShell script generator.
|
// Tests for buildRmmScript — RMM (NinjaRMM / Datto etc.) PowerShell script generator.
|
||||||
// RED: imports will fail until Plan 02-04 creates rmm-script.ts.
|
// RED: imports will fail until Plan 02-04 creates rmm-script.ts.
|
||||||
|
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { buildRmmScript } from './rmm-script';
|
import { buildRmmScript } from './rmm-script';
|
||||||
import { INITIAL_STATE } from '../store/types';
|
import { INITIAL_STATE } from '../store/types';
|
||||||
import type { WizardState } from '../store/types';
|
import type { WizardState } from '../store/types';
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export interface FieldDef {
|
|||||||
required: boolean;
|
required: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
helpText?: 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 };
|
validate?: { regex: RegExp; message: string };
|
||||||
tooltipText?: string;
|
tooltipText?: string;
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ export interface BackendMeta {
|
|||||||
displayName: string;
|
displayName: string;
|
||||||
description: string;
|
description: string;
|
||||||
category: BackendCategory;
|
category: BackendCategory;
|
||||||
fields: FieldDef[];
|
fields: readonly FieldDef[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BACKEND_REGISTRY = {
|
export const BACKEND_REGISTRY = {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
"types": ["vitest/globals"],
|
||||||
|
|
||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import tailwindcss from '@tailwindcss/vite';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react(), tailwindcss()],
|
plugins: [react(), tailwindcss()],
|
||||||
test: {
|
test: {
|
||||||
|
globals: true,
|
||||||
environment: 'jsdom',
|
environment: 'jsdom',
|
||||||
passWithNoTests: true,
|
passWithNoTests: true,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user