import { EditorSelection } from '@codemirror/state'; import createTestEditor from '../../testing/createTestEditor'; import toggleCheckbox, { isChecklistLine, reorderChecklistItems, ChecklistItemBlock } from './toggleCheckboxAt'; describe('toggleCheckboxAt', () => { describe('isChecklistLine', () => { it('identifies standard checklist formats correctly', () => { expect(isChecklistLine('- [ ] Task 1')).toBe(true); expect(isChecklistLine('- [x] Task 2')).toBe(true); expect(isChecklistLine('* [ ] Task 3')).toBe(true); expect(isChecklistLine('+ [ ] Task 4')).toBe(true); expect(isChecklistLine('1. [ ] Task 5')).toBe(true); expect(isChecklistLine(' - [ ] Subtask')).toBe(true); expect(isChecklistLine('- Just bullet')).toBe(false); expect(isChecklistLine('# Heading')).toBe(false); expect(isChecklistLine('Plain text')).toBe(false); }); }); describe('reorderChecklistItems', () => { it('moves checked target to the bottom of completed items', () => { const items: ChecklistItemBlock[] = [ { lines: ['- [ ] Task 1'], isChecked: false, isTarget: true }, { lines: ['- [ ] Task 2'], isChecked: false, isTarget: false }, { lines: ['- [x] Task 3'], isChecked: true, isTarget: false }, ]; const reordered = reorderChecklistItems(items, true); expect(reordered.map(item => item.lines[0])).toEqual([ '- [ ] Task 2', '- [x] Task 3', '- [x] Task 1', ]); }); it('moves unchecked target to the bottom of active items', () => { const items: ChecklistItemBlock[] = [ { lines: ['- [ ] Task 1'], isChecked: false, isTarget: false }, { lines: ['- [x] Task 2'], isChecked: true, isTarget: false }, { lines: ['- [x] Task 3'], isChecked: true, isTarget: true }, ]; const reordered = reorderChecklistItems(items, false); expect(reordered.map(item => item.lines[0])).toEqual([ '- [ ] Task 1', '- [ ] Task 3', '- [x] Task 2', ]); }); }); describe('toggleCheckbox editor command', () => { it('toggles a single item in place without moving', async () => { const initialText = '- [ ] Single item'; const editor = await createTestEditor(initialText, EditorSelection.cursor(2), []); const handled = toggleCheckbox(2)(editor); expect(handled).toBe(true); expect(editor.state.doc.toString()).toBe('- [x] Single item'); toggleCheckbox(2)(editor); expect(editor.state.doc.toString()).toBe('- [ ] Single item'); }); it('auto-sorts checked item to the bottom of the list block', async () => { const initialText = [ '- [ ] Item 1', '- [ ] Item 2', '- [x] Item 3', '- [ ] Item 4', ].join('\n'); const editor = await createTestEditor(initialText, EditorSelection.cursor(2), []); // Click first item (Item 1) toggleCheckbox(2)(editor); expect(editor.state.doc.toString()).toBe([ '- [ ] Item 2', '- [ ] Item 4', '- [x] Item 3', '- [x] Item 1', ].join('\n')); }); it('auto-sorts unchecked item back to the bottom of active items', async () => { const initialText = [ '- [ ] Item 1', '- [x] Item 2', '- [x] Item 3', ].join('\n'); const editor = await createTestEditor(initialText, EditorSelection.cursor(initialText.indexOf('Item 2')), []); // Uncheck Item 2 toggleCheckbox(initialText.indexOf('Item 2'))(editor); expect(editor.state.doc.toString()).toBe([ '- [ ] Item 1', '- [ ] Item 2', '- [x] Item 3', ].join('\n')); }); it('preserves attached child subtasks when moving a parent item', async () => { const initialText = [ '- [ ] Parent 1', ' - sub-detail line 1', ' - sub-detail line 2', '- [ ] Parent 2', ].join('\n'); const editor = await createTestEditor(initialText, EditorSelection.cursor(2), []); // Check Parent 1 toggleCheckbox(2)(editor); expect(editor.state.doc.toString()).toBe([ '- [ ] Parent 2', '- [x] Parent 1', ' - sub-detail line 1', ' - sub-detail line 2', ].join('\n')); }); it('respects autoSort: false option to toggle strictly in place', async () => { const initialText = [ '- [ ] Item 1', '- [ ] Item 2', ].join('\n'); const editor = await createTestEditor(initialText, EditorSelection.cursor(2), []); toggleCheckbox(2, { autoSort: false })(editor); expect(editor.state.doc.toString()).toBe([ '- [x] Item 1', '- [ ] Item 2', ].join('\n')); }); it('returns false for lines without any checkbox', async () => { const initialText = 'Just a regular markdown line'; const editor = await createTestEditor(initialText, EditorSelection.cursor(5), []); const result = toggleCheckbox(5)(editor); expect(result).toBe(false); expect(editor.state.doc.toString()).toBe(initialText); }); }); });