2026-05-29 23:58:41 -04:00
|
|
|
// @vitest-environment jsdom
|
|
|
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
|
import { cleanup, render, screen } from '@testing-library/react';
|
|
|
|
|
|
2026-08-14 21:20:43 -04:00
|
|
|
import Login, { isSafeAppReturnUrl } from '../../pages/login.js';
|
2026-05-29 23:58:41 -04:00
|
|
|
|
|
|
|
|
vi.mock('next/router', () => ({
|
|
|
|
|
useRouter: () => ({ push: vi.fn() }),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock('../../components/AuthLayout', () => ({
|
|
|
|
|
default: ({ children }) => <div>{children}</div>,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock('../../components/AnimatedFireLogo', () => ({
|
|
|
|
|
default: () => <div aria-hidden="true">logo</div>,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
describe('Login page', () => {
|
|
|
|
|
afterEach(() => cleanup());
|
|
|
|
|
|
|
|
|
|
it('renders the sign-in CTA without dev quick-login credentials', () => {
|
|
|
|
|
render(<Login />);
|
|
|
|
|
|
|
|
|
|
expect(screen.getByRole('button', { name: /sign in to deck hearth/i })).toBeTruthy();
|
|
|
|
|
expect(screen.queryByText(/quick login/i)).toBeNull();
|
|
|
|
|
expect(document.body.textContent).not.toMatch(/alice123|bob123/);
|
|
|
|
|
});
|
2026-08-14 21:20:43 -04:00
|
|
|
|
|
|
|
|
it('accepts same-origin relative return URLs and rejects open redirects', () => {
|
|
|
|
|
const origin = 'https://deckhearth.com';
|
|
|
|
|
expect(isSafeAppReturnUrl('/scanner', origin)).toBe(true);
|
|
|
|
|
expect(isSafeAppReturnUrl('/login', origin)).toBe(true);
|
|
|
|
|
expect(isSafeAppReturnUrl('//evil.example', origin)).toBe(false);
|
|
|
|
|
expect(isSafeAppReturnUrl('/\\evil.example', origin)).toBe(false);
|
|
|
|
|
expect(isSafeAppReturnUrl('https://evil.example', origin)).toBe(false);
|
|
|
|
|
expect(isSafeAppReturnUrl(null, origin)).toBe(false);
|
|
|
|
|
});
|
2026-05-29 23:58:41 -04:00
|
|
|
});
|