Redesign the setup flow and consolidate the CSS into one primitives layer
Onboarding asks explicitly for one or two parents and shows one card per parent for balances; the balance form is per parent with inline validation; the partner can be filled from the FK deduction or added from it. Settings and Dashboard reuse the same form. CSS: bare buttons carry no colour any more; buttons, cards, choice cards, fields, alerts, badges, eyebrow and modal chrome are defined once in primitives.css. Media queries live only in responsive.css. A style guard test blocks hex, !important and stray media queries. Bilingual fixes: calendar selects size by content, header no longer wraps. Vitest is capped at four workers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -46,23 +46,50 @@ describe('Auth', () => {
|
||||
personalDataUuid: null,
|
||||
parentName: null,
|
||||
refreshContext: vi.fn(),
|
||||
planVersion: 0,
|
||||
bumpPlanVersion: vi.fn(),
|
||||
})
|
||||
})
|
||||
|
||||
it('renders the login form by default', () => {
|
||||
it('renders the login form by default, with the login tab active', () => {
|
||||
render(<Auth />)
|
||||
expect(screen.getByRole('heading', { name: 'Logga in' })).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText('E-post')).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText('Lösenord')).toBeInTheDocument()
|
||||
expect(screen.queryByPlaceholderText('Namn')).not.toBeInTheDocument()
|
||||
// Both tabs' text is unique except "Logga in", which the login-mode
|
||||
// submit button also renders — the tabs carry their own testids so
|
||||
// these queries don't collide with it.
|
||||
expect(screen.getByTestId('auth-tab-login')).toHaveAttribute('aria-pressed', 'true')
|
||||
expect(screen.getByTestId('auth-tab-register')).toHaveAttribute('aria-pressed', 'false')
|
||||
})
|
||||
|
||||
it('switches to the registration form', () => {
|
||||
it('switches to the registration form via the tab', () => {
|
||||
render(<Auth />)
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Skapa konto' }))
|
||||
fireEvent.click(screen.getByTestId('auth-tab-register'))
|
||||
expect(screen.getByRole('heading', { name: 'Skapa konto' })).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText('Namn')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'Har redan konto' })).toBeInTheDocument()
|
||||
expect(screen.getByTestId('auth-tab-register')).toHaveAttribute('aria-pressed', 'true')
|
||||
expect(screen.getByTestId('auth-tab-login')).toHaveAttribute('aria-pressed', 'false')
|
||||
})
|
||||
|
||||
it('switches back to the login form via the tab', () => {
|
||||
render(<Auth />)
|
||||
fireEvent.click(screen.getByTestId('auth-tab-register'))
|
||||
fireEvent.click(screen.getByTestId('auth-tab-login'))
|
||||
expect(screen.getByRole('heading', { name: 'Logga in' })).toBeInTheDocument()
|
||||
expect(screen.queryByPlaceholderText('Namn')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('clears the error banner when switching between the Log in and Create account tabs', async () => {
|
||||
mockLogin.mockRejectedValue(new Error('Fel användarnamn'))
|
||||
render(<Auth />)
|
||||
|
||||
fireEvent.click(screen.getByTestId('auth-submit'))
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent('Fel användarnamn')
|
||||
|
||||
fireEvent.click(screen.getByTestId('auth-tab-register'))
|
||||
expect(screen.queryByRole('alert')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('logs in with the entered credentials and navigates home', async () => {
|
||||
@@ -71,7 +98,7 @@ describe('Auth', () => {
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('E-post'), { target: { value: 'a@b.com' } })
|
||||
fireEvent.change(screen.getByPlaceholderText('Lösenord'), { target: { value: 'secret' } })
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Logga in' }))
|
||||
fireEvent.click(screen.getByTestId('auth-submit'))
|
||||
|
||||
await waitFor(() => expect(mockLogin).toHaveBeenCalledWith({ email: 'a@b.com', password: 'secret' }))
|
||||
expect(mockNavigate).toHaveBeenCalledWith('/', { replace: true })
|
||||
@@ -81,11 +108,11 @@ describe('Auth', () => {
|
||||
mockRegister.mockResolvedValue(undefined)
|
||||
render(<Auth />)
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Skapa konto' }))
|
||||
fireEvent.click(screen.getByTestId('auth-tab-register'))
|
||||
fireEvent.change(screen.getByPlaceholderText('Namn'), { target: { value: 'Alex' } })
|
||||
fireEvent.change(screen.getByPlaceholderText('E-post'), { target: { value: 'a@b.com' } })
|
||||
fireEvent.change(screen.getByPlaceholderText('Lösenord'), { target: { value: 'secret' } })
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Registrera' }))
|
||||
fireEvent.click(screen.getByTestId('auth-submit'))
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockRegister).toHaveBeenCalledWith({ email: 'a@b.com', password: 'secret', displayName: 'Alex' }),
|
||||
@@ -97,7 +124,7 @@ describe('Auth', () => {
|
||||
mockLogin.mockRejectedValue(new Error('Fel användarnamn'))
|
||||
render(<Auth />)
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Logga in' }))
|
||||
fireEvent.click(screen.getByTestId('auth-submit'))
|
||||
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent('Fel användarnamn')
|
||||
})
|
||||
@@ -106,7 +133,7 @@ describe('Auth', () => {
|
||||
mockLogin.mockRejectedValue('nope')
|
||||
render(<Auth />)
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Logga in' }))
|
||||
fireEvent.click(screen.getByTestId('auth-submit'))
|
||||
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent('Något gick fel')
|
||||
})
|
||||
@@ -146,6 +173,8 @@ describe('Auth', () => {
|
||||
personalDataUuid: null,
|
||||
parentName: null,
|
||||
refreshContext: vi.fn(),
|
||||
planVersion: 0,
|
||||
bumpPlanVersion: vi.fn(),
|
||||
})
|
||||
render(<Auth />)
|
||||
expect(mockNavigate).not.toHaveBeenCalled()
|
||||
|
||||
Reference in New Issue
Block a user