diff --git a/resources/js/modules/admin-table/components/DeleteButton.test.ts b/resources/js/modules/admin-table/components/DeleteButton.test.ts new file mode 100644 index 00000000000..f83e030a708 --- /dev/null +++ b/resources/js/modules/admin-table/components/DeleteButton.test.ts @@ -0,0 +1,34 @@ +import {createApp} from 'vue'; +import {afterEach, expect, it, vi} from 'vite-plus/test'; +import DeleteButton from './DeleteButton.vue'; + +const container = document.createElement('div'); +let app: ReturnType; + +afterEach(() => { + app.unmount(); + container.replaceChildren(); + vi.unstubAllGlobals(); +}); + +it('emits clicks only after confirmation', () => { + const confirm = vi.fn((): boolean => false); + const onClick = vi.fn(); + vi.stubGlobal('confirm', confirm); + app = createApp(DeleteButton, { + confirm: 'Delete this item?', + onClick, + }); + app.mount(container); + + const button = container.querySelector('craft-button'); + if (!button) throw new Error('Expected a delete button.'); + + button.click(); + expect(confirm).toHaveBeenCalledWith('Delete this item?'); + expect(onClick).not.toHaveBeenCalled(); + + confirm.mockReturnValue(true); + button.click(); + expect(onClick).toHaveBeenCalledOnce(); +}); diff --git a/resources/js/modules/admin-table/components/DeleteButton.vue b/resources/js/modules/admin-table/components/DeleteButton.vue index 3f7f7448666..3212f430cc2 100644 --- a/resources/js/modules/admin-table/components/DeleteButton.vue +++ b/resources/js/modules/admin-table/components/DeleteButton.vue @@ -4,19 +4,28 @@ const emit = defineEmits<{ (e: 'click'): void; }>(); - withDefaults( + const props = withDefaults( defineProps<{ + confirm?: string; label?: string; icon?: string; }>(), {label: t('Delete item'), icon: 'x'} ); + + function handleClick(): void { + if (props.confirm && !window.confirm(props.confirm)) { + return; + } + + emit('click'); + }