import {applyAreYouSure, ignoreAreYouSure, initGlobalFormDirtyLeaveConfirm, shouldTriggerAreYouSure} from './are-you-sure.ts'; function createForm(fieldsHtml: string, wrapperClass = ''): HTMLFormElement { document.body.insertAdjacentHTML('beforeend', `
${fieldsHtml}
`); return document.body.lastElementChild!.querySelector('form')!; } const field = (form: HTMLFormElement, name: string) => form.elements.namedItem(name) as HTMLInputElement; function set(field: HTMLInputElement, props: Partial, eventType = 'change') { Object.assign(field, props); field.dispatchEvent(new Event(eventType, {bubbles: true})); } const isBeforeUnloadPrevented = () => !window.dispatchEvent(new Event('beforeunload', {cancelable: true})); afterEach(() => document.body.replaceChildren()); test('tracks field changes, clears on submit and reset', () => { const form = createForm(` `); const onDirtyChange = vi.fn(); applyAreYouSure(form, onDirtyChange); set(field(form, 'title'), {value: 'b'}, 'input'); set(field(form, 'title'), {value: 'c'}, 'input'); set(field(form, 'title'), {value: 'a'}, 'keyup'); set(field(form, 'flag'), {checked: true}); set(field(form, 'flag'), {checked: false}); set(field(form, 'pick'), {value: 'b'}); expect(onDirtyChange.mock.calls).toEqual([[true], [false], [true], [false], [true]]); expect(shouldTriggerAreYouSure()).toBe(true); form.addEventListener('submit', (e) => e.preventDefault()); form.dispatchEvent(new SubmitEvent('submit', {cancelable: true})); expect(shouldTriggerAreYouSure()).toBe(false); set(field(form, 'title'), {value: 'b'}); form.reset(); expect(shouldTriggerAreYouSure()).toBe(false); }); test('ignores untracked fields', () => { const form = createForm(`
`); applyAreYouSure(form); form.insertAdjacentHTML('beforeend', ''); for (const input of form.querySelectorAll('input')) set(input, {value: 'b'}); expect(shouldTriggerAreYouSure()).toBe(false); }); test('applying again resets the baseline', () => { const form = createForm(`
`); const oldOnDirtyChange = vi.fn(); const onDirtyChange = vi.fn(); applyAreYouSure(form, oldOnDirtyChange); set(field(form, 'title'), {value: 'b'}); form.querySelector('.wrapper')!.classList.add('ays-ignore'); applyAreYouSure(form, onDirtyChange); set(field(form, 'summary'), {value: 'b'}); set(field(form, 'extra'), {value: 'b'}); field(form, 'extra').remove(); set(field(form, 'title'), {value: 'b'}); set(field(form, 'title'), {value: 'a'}); expect(oldOnDirtyChange.mock.calls).toEqual([[true]]); expect(onDirtyChange.mock.calls).toEqual([[true], [false], [true]]); }); test('initGlobalFormDirtyLeaveConfirm guards beforeunload', () => { const signin = createForm('', 'page-content user signin'); initGlobalFormDirtyLeaveConfirm(); set(field(signin, 'user_name'), {value: 'b'}); expect(shouldTriggerAreYouSure()).toBe(false); signin.parentElement!.remove(); const form = createForm(''); const ignored = createForm(''); ignored.classList.add('ignore-dirty'); initGlobalFormDirtyLeaveConfirm(); set(field(ignored, 'q'), {value: 'b'}); ignored.classList.remove('ignore-dirty'); expect(isBeforeUnloadPrevented()).toBe(false); set(field(form, 'title'), {value: 'b'}); expect(isBeforeUnloadPrevented()).toBe(true); form.parentElement!.classList.add('tw-hidden'); expect(isBeforeUnloadPrevented()).toBe(false); form.parentElement!.classList.remove('tw-hidden'); ignoreAreYouSure(form); expect(isBeforeUnloadPrevented()).toBe(false); });