Restructures frontend to a feature-based folder layout
Continuous Integration / config (pull_request) Successful in 11s
Continuous Integration / changes (pull_request) Successful in 21s
Continuous Integration / backend-build (pull_request) Skipped
Continuous Integration / backend-test (pull_request) Skipped
Continuous Integration / vulnerability-scan (pull_request) Skipped
Continuous Integration / frontend-prepare (pull_request) Successful in 1m37s
Continuous Integration / frontend-build (pull_request) Successful in 2m12s
Continuous Integration / frontend-test (pull_request) Successful in 4m42s
Continuous Integration / frontend-lint (pull_request) Successful in 2m2s
Continuous Integration / publish-production (pull_request) Skipped
Continuous Integration / deploy-production (pull_request) Skipped
Continuous Integration / publish-test (pull_request) Successful in 6m51s
Continuous Integration / deploy-test (pull_request) Skipped
Continuous Integration / config (pull_request) Successful in 11s
Continuous Integration / changes (pull_request) Successful in 21s
Continuous Integration / backend-build (pull_request) Skipped
Continuous Integration / backend-test (pull_request) Skipped
Continuous Integration / vulnerability-scan (pull_request) Skipped
Continuous Integration / frontend-prepare (pull_request) Successful in 1m37s
Continuous Integration / frontend-build (pull_request) Successful in 2m12s
Continuous Integration / frontend-test (pull_request) Successful in 4m42s
Continuous Integration / frontend-lint (pull_request) Successful in 2m2s
Continuous Integration / publish-production (pull_request) Skipped
Continuous Integration / deploy-production (pull_request) Skipped
Continuous Integration / publish-test (pull_request) Successful in 6m51s
Continuous Integration / deploy-test (pull_request) Skipped
Groups auth, setup, invitation, profile, users, cms, availability and system code (services/hooks, components, schemas, mocks, pages) under src/features/<name> instead of splitting by technical layer (api/, components/, lib/schemas/, mocks/, pages/). Renames the old connection-oriented `api` layer to `services` per feature, and splits the monolithic api/types.ts into per-feature types.ts files (with ProblemDetails/ApiResult merged into lib/api-client.ts as shared infra). Layout-agnostic code (ui primitives, app shell, i18n, test utils, lib) stays at the top level. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { renderApp, mockGuest } from '@/test/utils';
|
||||
import { server } from '@/mocks/server';
|
||||
import { setupUninitializedHandlers } from '@/mocks/index';
|
||||
import { _resetSetupStatusCache } from '@/router';
|
||||
|
||||
// Reset module-level setup status cache before each test.
|
||||
beforeEach(() => {
|
||||
_resetSetupStatusCache();
|
||||
});
|
||||
|
||||
describe('InviteCompletePage', () => {
|
||||
it('shows a loading spinner on mount while validating the token', async () => {
|
||||
server.use(...setupUninitializedHandlers);
|
||||
mockGuest();
|
||||
renderApp('/invite/complete?token=valid-token');
|
||||
|
||||
// Loading spinner should appear immediately.
|
||||
expect(await screen.findByTestId('invite-loading')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows an error state for an expired token', async () => {
|
||||
server.use(...setupUninitializedHandlers);
|
||||
mockGuest();
|
||||
renderApp('/invite/complete?token=expired-token');
|
||||
|
||||
expect(await screen.findByTestId('invite-error')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('invite-name-input')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows an error state for a used token', async () => {
|
||||
server.use(...setupUninitializedHandlers);
|
||||
mockGuest();
|
||||
renderApp('/invite/complete?token=used-token');
|
||||
|
||||
expect(await screen.findByTestId('invite-error')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows an error state when no token is provided', async () => {
|
||||
server.use(...setupUninitializedHandlers);
|
||||
mockGuest();
|
||||
renderApp('/invite/complete');
|
||||
|
||||
expect(await screen.findByTestId('invite-error')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the form with a read-only email for a valid token', async () => {
|
||||
server.use(...setupUninitializedHandlers);
|
||||
mockGuest();
|
||||
renderApp('/invite/complete?token=valid-token');
|
||||
|
||||
expect(await screen.findByTestId('invite-name-input')).toBeInTheDocument();
|
||||
const emailInput = screen.getByTestId('invite-email-input') as HTMLInputElement;
|
||||
expect(emailInput.value).toBe('invited@example.com');
|
||||
expect(emailInput.disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('shows validation errors when submitting an empty form', async () => {
|
||||
server.use(...setupUninitializedHandlers);
|
||||
mockGuest();
|
||||
const user = userEvent.setup();
|
||||
renderApp('/invite/complete?token=valid-token');
|
||||
|
||||
const submit = await screen.findByTestId('invite-submit-button');
|
||||
await user.click(submit);
|
||||
|
||||
expect(await screen.findByTestId('invite-name-error')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('invite-password-error')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows success message after a valid submission', async () => {
|
||||
server.use(...setupUninitializedHandlers);
|
||||
mockGuest();
|
||||
const user = userEvent.setup();
|
||||
renderApp('/invite/complete?token=valid-token');
|
||||
|
||||
await user.type(await screen.findByTestId('invite-name-input'), 'Bob User');
|
||||
await user.type(screen.getByTestId('invite-password-input'), 'ValidPass1!');
|
||||
await user.type(screen.getByTestId('invite-confirmPassword-input'), 'ValidPass1!');
|
||||
await user.click(screen.getByTestId('invite-submit-button'));
|
||||
|
||||
expect(await screen.findByTestId('invite-success')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user