fix: spurious unsaved-changes warning when navigating between test cases in a test run (#406)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kimatata <117462761+kimatata@users.noreply.github.com>
This commit is contained in:
103
frontend/utils/formGuard.test.ts
Normal file
103
frontend/utils/formGuard.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
// @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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user