2025-12-03 21:56:50 +00:00
|
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
|
|
import { render, screen, waitFor, act } from '@testing-library/react';
|
|
|
|
|
import userEvent from '@testing-library/user-event';
|
|
|
|
|
import { MemoryRouter } from 'react-router-dom';
|
|
|
|
|
import { VerifyEmailPage } from './VerifyEmailPage';
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
import { authApi } from '@/services/api/auth';
|
|
|
|
|
|
|
|
|
|
// Mock authApi
|
|
|
|
|
vi.mock('@/services/api/auth', () => ({
|
|
|
|
|
authApi: {
|
|
|
|
|
verifyEmail: vi.fn(),
|
|
|
|
|
resendVerification: vi.fn(),
|
|
|
|
|
},
|
2025-12-03 21:56:50 +00:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const mockNavigate = vi.fn();
|
|
|
|
|
vi.mock('react-router-dom', async () => {
|
|
|
|
|
const actual = await vi.importActual('react-router-dom');
|
|
|
|
|
return {
|
|
|
|
|
...actual,
|
|
|
|
|
useNavigate: () => mockNavigate,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter>{children}</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
describe('VerifyEmailPage', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
vi.clearAllMocks();
|
|
|
|
|
mockNavigate.mockClear();
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
vi.clearAllTimers();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should render verifying state when token is present', async () => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockResolvedValue({
|
|
|
|
|
message: 'Email verified',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Should show verifying state initially
|
|
|
|
|
await waitFor(() => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
const heading = document.querySelector('h1');
|
|
|
|
|
expect(heading).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display error message when token is missing', () => {
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper });
|
|
|
|
|
|
|
|
|
|
expect(screen.getByText("Vérification de l'email")).toBeInTheDocument();
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.getByText('Lien de vérification invalide ou manquant'),
|
|
|
|
|
).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should extract token from URL and verify email', async () => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockResolvedValue({
|
|
|
|
|
message: 'Email verified',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=abc123']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for verification to complete
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
expect(authApi.verifyEmail).toHaveBeenCalledWith({ token: 'abc123' });
|
2025-12-13 02:34:34 +00:00
|
|
|
},
|
|
|
|
|
{ timeout: 3000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display success message after successful verification', async () => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockResolvedValue({
|
|
|
|
|
message: 'Email verified',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for success message
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(screen.getByText('Email vérifié')).toBeInTheDocument();
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 2000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display error message when verification fails', async () => {
|
|
|
|
|
const error = { message: 'Token invalide ou expiré' };
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockRejectedValue(error);
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=invalid-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for error message
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(
|
|
|
|
|
screen.getByText('Token invalide ou expiré'),
|
|
|
|
|
).toBeInTheDocument();
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 3000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should redirect to login after successful verification', async () => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockResolvedValue({
|
|
|
|
|
message: 'Email verified',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for success
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText('Email vérifié')).toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
// Wait for the redirect timer (3 seconds)
|
|
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(mockNavigate).toHaveBeenCalledWith('/login', { replace: true });
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 4000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display retry button when verification fails', async () => {
|
|
|
|
|
const error = { message: 'Verification failed' };
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockRejectedValue(error);
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for error state
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(screen.getByText('Réessayer')).toBeInTheDocument();
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 3000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should call verifyEmail when retry button is clicked', async () => {
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
|
const error = { message: 'Verification failed' };
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail)
|
2025-12-13 02:34:34 +00:00
|
|
|
.mockRejectedValueOnce(error)
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
.mockResolvedValueOnce({ message: 'Email verified' });
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for error state
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText('Réessayer')).toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Click retry button
|
|
|
|
|
const retryButton = screen.getByText('Réessayer');
|
|
|
|
|
await act(async () => {
|
|
|
|
|
await user.click(retryButton);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Should call verifyEmail again
|
|
|
|
|
await waitFor(() => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
expect(authApi.verifyEmail).toHaveBeenCalledTimes(2);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display resend email button', async () => {
|
|
|
|
|
const error = { message: 'Verification failed' };
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockRejectedValue(error);
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for error state
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(
|
|
|
|
|
screen.getByText(/Renvoyer l'email de vérification/),
|
|
|
|
|
).toBeInTheDocument();
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 3000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
it('should call resendVerification when resend button is clicked', async () => {
|
2025-12-03 21:56:50 +00:00
|
|
|
const user = userEvent.setup();
|
|
|
|
|
const error = { message: 'Verification failed' };
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockRejectedValue(error);
|
|
|
|
|
vi.mocked(authApi.resendVerification).mockResolvedValue({
|
|
|
|
|
message: 'Email sent',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
localStorage.setItem('pendingVerificationEmail', 'test@example.com');
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for error state
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(
|
|
|
|
|
screen.getByText(/Renvoyer l'email de vérification/),
|
|
|
|
|
).toBeInTheDocument();
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 3000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
// Click resend button
|
|
|
|
|
const resendButton = screen.getByText(/Renvoyer l'email de vérification/);
|
|
|
|
|
await act(async () => {
|
|
|
|
|
await user.click(resendButton);
|
|
|
|
|
});
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
// Should call resendVerification
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
expect(authApi.resendVerification).toHaveBeenCalledWith({
|
|
|
|
|
email: 'test@example.com',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
},
|
|
|
|
|
{ timeout: 3000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should set cooldown after resending email', async () => {
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
|
const error = { message: 'Verification failed' };
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockRejectedValue(error);
|
|
|
|
|
vi.mocked(authApi.resendVerification).mockResolvedValue({
|
|
|
|
|
message: 'Email sent',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
localStorage.setItem('pendingVerificationEmail', 'test@example.com');
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for error state
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(
|
|
|
|
|
screen.getByText(/Renvoyer l'email de vérification/),
|
|
|
|
|
).toBeInTheDocument();
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 2000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
// Click resend button
|
|
|
|
|
const resendButton = screen.getByText(/Renvoyer l'email de vérification/);
|
|
|
|
|
await act(async () => {
|
|
|
|
|
await user.click(resendButton);
|
|
|
|
|
});
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
// Verify that resendVerification was called
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
expect(authApi.resendVerification).toHaveBeenCalledWith({
|
|
|
|
|
email: 'test@example.com',
|
|
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
},
|
|
|
|
|
{ timeout: 2000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle resend when email is not found', async () => {
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
|
const error = { message: 'Verification failed' };
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
vi.mocked(authApi.verifyEmail).mockRejectedValue(error);
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
// No email in localStorage
|
|
|
|
|
localStorage.clear();
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
const wrapperWithToken = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
<MemoryRouter initialEntries={['/verify-email?token=test-token']}>
|
|
|
|
|
{children}
|
|
|
|
|
</MemoryRouter>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper: wrapperWithToken });
|
|
|
|
|
|
|
|
|
|
// Wait for error state
|
2025-12-13 02:34:34 +00:00
|
|
|
await waitFor(
|
|
|
|
|
() => {
|
|
|
|
|
expect(
|
|
|
|
|
screen.getByText(/Renvoyer l'email de vérification/),
|
|
|
|
|
).toBeInTheDocument();
|
|
|
|
|
},
|
|
|
|
|
{ timeout: 2000 },
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
// Click resend button
|
|
|
|
|
const resendButton = screen.getByText(/Renvoyer l'email de vérification/);
|
|
|
|
|
await act(async () => {
|
|
|
|
|
await user.click(resendButton);
|
|
|
|
|
});
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
// resendVerification should NOT be called since email is missing
|
2025-12-03 21:56:50 +00:00
|
|
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
expect(authApi.resendVerification).not.toHaveBeenCalled();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display footer links', () => {
|
|
|
|
|
render(<VerifyEmailPage />, { wrapper });
|
|
|
|
|
|
|
|
|
|
const loginLink = screen.getByText('Retour à la connexion');
|
|
|
|
|
expect(loginLink).toBeInTheDocument();
|
|
|
|
|
expect(loginLink.closest('a')).toHaveAttribute('href', '/login');
|
|
|
|
|
});
|
|
|
|
|
});
|