Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kimatata <117462761+kimatata@users.noreply.github.com>
104 lines
3.0 KiB
TypeScript
104 lines
3.0 KiB
TypeScript
// @vitest-environment happy-dom
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
// mock cleanup
|
|
let cleanupFn: (() => void) | undefined;
|
|
vi.mock('react', () => ({
|
|
useEffect: (fn: () => void) => {
|
|
cleanupFn = fn() as (() => void) | undefined;
|
|
},
|
|
}));
|
|
|
|
import { useFormGuard } from './formGuard';
|
|
|
|
describe('useFormGuard', () => {
|
|
let confirmSpy: ReturnType<typeof vi.spyOn>;
|
|
|
|
beforeEach(() => {
|
|
// @ts-expect-error - we will mock confirm
|
|
confirmSpy = vi.spyOn(window, 'confirm');
|
|
cleanupFn = undefined;
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanupFn?.();
|
|
cleanupFn = undefined;
|
|
vi.restoreAllMocks();
|
|
document.body.innerHTML = '';
|
|
});
|
|
|
|
// helper: simulate clicking an anchor
|
|
const clickAnchor = (href: string, target?: string): MouseEvent => {
|
|
const anchor = document.createElement('a');
|
|
anchor.setAttribute('href', href);
|
|
if (target) anchor.setAttribute('target', target);
|
|
document.body.appendChild(anchor);
|
|
|
|
const event = new MouseEvent('click', { bubbles: true, cancelable: true });
|
|
anchor.dispatchEvent(event);
|
|
return event;
|
|
};
|
|
|
|
describe('Basic functionality', () => {
|
|
it('does not show confirm when form is clean', () => {
|
|
useFormGuard(false, 'Leave?');
|
|
clickAnchor('/some-path');
|
|
|
|
expect(confirmSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('shows confirm with the given text when dirty', () => {
|
|
confirmSpy.mockReturnValue(true);
|
|
useFormGuard(true, 'Are you sure?');
|
|
clickAnchor('/other-page');
|
|
|
|
expect(confirmSpy).toHaveBeenCalledWith('Are you sure?');
|
|
});
|
|
|
|
it('prevents navigation when dirty and user cancels confirm', () => {
|
|
confirmSpy.mockReturnValue(false);
|
|
useFormGuard(true, 'Leave?');
|
|
|
|
const event = clickAnchor('/other-page');
|
|
expect(event.defaultPrevented).toBe(true);
|
|
});
|
|
|
|
it('allows navigation when dirty and user confirms', () => {
|
|
confirmSpy.mockReturnValue(true);
|
|
useFormGuard(true, 'Leave?');
|
|
|
|
const event = clickAnchor('/other-page');
|
|
expect(event.defaultPrevented).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('external links', () => {
|
|
it('does not show confirm for anchor with target="_blank"', () => {
|
|
useFormGuard(true, 'Leave?');
|
|
clickAnchor('https://example.com', '_blank');
|
|
|
|
expect(confirmSpy).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('UnitTCMS use case', () => {
|
|
it('does not show confirm when navigating to case detail page of test run', () => {
|
|
const projectId = '1';
|
|
const runId = '2';
|
|
useFormGuard(true, 'Leave?', [`/projects/${projectId}/runs/${runId}/cases/\\d+`]);
|
|
clickAnchor(`/projects/${projectId}/runs/${runId}/cases/123`);
|
|
|
|
expect(confirmSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('shows confirm when navigating to test cases page', () => {
|
|
const projectId = '1';
|
|
const runId = '2';
|
|
useFormGuard(true, 'Leave?', [`/projects/${projectId}/runs/${runId}/cases/\\d+`]);
|
|
clickAnchor(`/projects/${projectId}/runs/${runId}/cases`);
|
|
|
|
expect(confirmSpy).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|