From 8b7daa860cffe63b089a1125ca289e88d1d7b073 Mon Sep 17 00:00:00 2001 From: Kawa Date: Wed, 1 Apr 2026 13:29:48 +0200 Subject: [PATCH] test(11-02): add failing tests for auto-scroll to first error on validation failure - Add scrollIntoView mock (vi.fn()) in beforeEach to both test files - Add POLISH-04 test in BackendSelectionStep: scrolls to remote-name on empty submit - Add POLISH-04 test in RemoteConfigStep: scrolls to first errored field on empty submit --- .../wizard/BackendSelectionStep.test.tsx | 22 +++++++++++++++++- .../wizard/RemoteConfigStep.test.tsx | 23 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/components/wizard/BackendSelectionStep.test.tsx b/src/components/wizard/BackendSelectionStep.test.tsx index f3bfe5b..064dc39 100644 --- a/src/components/wizard/BackendSelectionStep.test.tsx +++ b/src/components/wizard/BackendSelectionStep.test.tsx @@ -1,7 +1,8 @@ // @vitest-environment jsdom // Covers WIZD-01: card grid renders Azure Blob, Amazon S3, S3-Compatible (Azure first) // Covers WIZD-04: remote name field validates alphanumeric/dash/underscore -import { describe, it, expect } from 'vitest'; +// Covers POLISH-04: auto-scroll to first errored field on validation failure +import { describe, it, expect, beforeEach, vi } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { WizardProvider } from '../../store/context'; @@ -16,6 +17,10 @@ function renderStep() { } describe('BackendSelectionStep', () => { + beforeEach(() => { + Element.prototype.scrollIntoView = vi.fn(); + }); + describe('WIZD-01: backend card grid', () => { it('renders Azure Blob Storage card', () => { renderStep(); @@ -138,4 +143,19 @@ describe('BackendSelectionStep', () => { }); }); }); + + describe('POLISH-04: auto-scroll to first error', () => { + it('scrolls to remote-name field when submitted with empty name', async () => { + const user = userEvent.setup(); + renderStep(); + const nameInput = screen.getByRole('textbox'); + await user.clear(nameInput); + // Submit via Next button with empty name to trigger validation failure + const nextButton = screen.getByRole('button', { name: /next/i }); + await user.click(nextButton); + await waitFor(() => { + expect(Element.prototype.scrollIntoView).toHaveBeenCalled(); + }); + }); + }); }); diff --git a/src/components/wizard/RemoteConfigStep.test.tsx b/src/components/wizard/RemoteConfigStep.test.tsx index cfc82f8..de5d305 100644 --- a/src/components/wizard/RemoteConfigStep.test.tsx +++ b/src/components/wizard/RemoteConfigStep.test.tsx @@ -4,7 +4,8 @@ // Covers BACK-03: S3-Compatible config form — same as S3 plus endpoint field // Covers VALID-01: Format validation stubs (RED — validate property not implemented yet) // Covers UX-01: Tooltip toggle stubs (RED — tooltipText property not implemented yet) -import { describe, it, expect } from 'vitest'; +// Covers POLISH-04: auto-scroll to first errored field on validation failure +import { describe, it, expect, beforeEach, vi } from 'vitest'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useEffect } from 'react'; @@ -29,6 +30,10 @@ function renderWithBackend(backendType: BackendType) { } describe('RemoteConfigStep', () => { + beforeEach(() => { + Element.prototype.scrollIntoView = vi.fn(); + }); + describe('BACK-01: Azure Blob form', () => { it('renders Storage Account Name field', async () => { renderWithBackend('azureblob'); @@ -427,4 +432,20 @@ describe('RemoteConfigStep', () => { expect(screen.getByRole('button', { name: /more info about application key id/i })).toBeDefined(); }); }); + + describe('POLISH-04: auto-scroll to first error', () => { + it('scrolls to first errored field when submitted with missing required fields', async () => { + const user = userEvent.setup(); + renderWithBackend('azureblob'); + // Wait for form to render + await waitFor(() => { + expect(screen.getByLabelText(/storage account name/i)).toBeDefined(); + }); + // Submit without filling required fields to trigger validation failure + await user.click(screen.getByRole('button', { name: /next/i })); + await waitFor(() => { + expect(Element.prototype.scrollIntoView).toHaveBeenCalled(); + }); + }); + }); });