mirror of
https://github.com/groldsf/obsidian_check_plugin.git
synced 2026-07-22 05:37:48 +00:00
remove old test
This commit is contained in:
parent
78bc89c129
commit
d905f92969
2 changed files with 0 additions and 862 deletions
|
|
@ -1,673 +0,0 @@
|
|||
// checkboxUtils.test.ts
|
||||
import { CheckboxUtils } from '../src/checkboxUtils';
|
||||
import { CheckboxSyncPluginSettings } from '../src/types'; // Предполагаем, что типы в types.ts
|
||||
|
||||
// --- Mock Settings ---
|
||||
const defaultSettings: Readonly<CheckboxSyncPluginSettings> = {
|
||||
xOnlyMode: false, // По умолчанию: любой не-пробел считается 'checked'
|
||||
enableAutomaticParentState: true,
|
||||
enableAutomaticChildState: true,
|
||||
};
|
||||
|
||||
const xOnlySettings: Readonly<CheckboxSyncPluginSettings> = {
|
||||
xOnlyMode: true, // Только 'x' считается 'checked'
|
||||
enableAutomaticParentState: true,
|
||||
enableAutomaticChildState: true,
|
||||
};
|
||||
|
||||
const settingsParentSyncDisabled: Readonly<CheckboxSyncPluginSettings> = {
|
||||
xOnlyMode: false, // или true, если нужно тестировать комбинацию
|
||||
enableAutomaticParentState: false, // Родитель НЕ обновляется от детей
|
||||
enableAutomaticChildState: true,
|
||||
};
|
||||
|
||||
const settingsChildSyncDisabled: Readonly<CheckboxSyncPluginSettings> = {
|
||||
xOnlyMode: false,
|
||||
enableAutomaticParentState: true, // Оставим true для этого варианта
|
||||
enableAutomaticChildState: false, // Дети НЕ обновляются от родителя
|
||||
};
|
||||
|
||||
// --- Test Suite ---
|
||||
describe('CheckboxUtils', () => {
|
||||
let utilsDefault: CheckboxUtils;
|
||||
let utilsXOnly: CheckboxUtils;
|
||||
let utilsParentSyncDisabled: CheckboxUtils;
|
||||
let utilsChildSyncDisabled: CheckboxUtils
|
||||
|
||||
beforeEach(() => {
|
||||
// Создаем новые экземпляры перед каждым тестом для изоляции
|
||||
utilsDefault = new CheckboxUtils(defaultSettings);
|
||||
utilsXOnly = new CheckboxUtils(xOnlySettings);
|
||||
utilsParentSyncDisabled = new CheckboxUtils(settingsParentSyncDisabled);
|
||||
utilsChildSyncDisabled = new CheckboxUtils(settingsChildSyncDisabled);
|
||||
});
|
||||
|
||||
// --- matchCheckboxLine ---
|
||||
describe('matchCheckboxLine', () => {
|
||||
it.each([
|
||||
// Простые случаи
|
||||
['- [ ] Text', { indent: 0, marker: '-', checkChar: ' ', checkboxCharPosition: 3 }],
|
||||
['* [x] Task', { indent: 0, marker: '*', checkChar: 'x', checkboxCharPosition: 3 }],
|
||||
['+ [?] Query', { indent: 0, marker: '+', checkChar: '?', checkboxCharPosition: 3 }],
|
||||
['1. [!] Num', { indent: 0, marker: '1.', checkChar: '!', checkboxCharPosition: 4 }],
|
||||
// С отступами
|
||||
[' - [ ] Indented', { indent: 2, marker: '-', checkChar: ' ', checkboxCharPosition: 5 }],
|
||||
['\t* [x] Tab Indent', { indent: 1, marker: '*', checkChar: 'x', checkboxCharPosition: 4 }], // Зависит от размера таба, Jest может считать его 1
|
||||
[' 10. [A] Deep', { indent: 4, marker: '10.', checkChar: 'A', checkboxCharPosition: 9 }],
|
||||
])('should match valid checkbox line: %s', (line, expected) => {
|
||||
const result = utilsDefault.matchCheckboxLine(line);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'Not a list item',
|
||||
'- Just text',
|
||||
'-[] No space',
|
||||
'- [No Char]',
|
||||
'- [ ]', // Нет пробела после скобки, как требует регекс \s
|
||||
' Non-checkbox line',
|
||||
'-[ ] No space before marker',
|
||||
'1.[ ] No space after numbered marker',
|
||||
'- ] Missing opening bracket',
|
||||
'* [x Missing closing bracket',
|
||||
])('should return null for invalid lines: %s', (line) => {
|
||||
expect(utilsDefault.matchCheckboxLine(line)).toBeNull();
|
||||
});
|
||||
|
||||
it('should require a space after the closing bracket', () => {
|
||||
expect(utilsDefault.matchCheckboxLine('- [ ]')).toBeNull(); // Missing trailing space
|
||||
expect(utilsDefault.matchCheckboxLine('- [ ] ')).not.toBeNull(); // Has trailing space
|
||||
});
|
||||
|
||||
it.each([' ', 'x', '-', '?', '!'])('should correctly parse the checkChar', (state) => {
|
||||
const lineInfo = utilsDefault.matchCheckboxLine(`- [${state}] Task`);
|
||||
expect(lineInfo).not.toBeNull();
|
||||
expect(lineInfo?.checkChar).toBe(state);
|
||||
});
|
||||
});
|
||||
|
||||
// --- isCheckedSymbol ---
|
||||
describe('isCheckedSymbol', () => {
|
||||
// Default mode (xOnlyMode: false)
|
||||
it('should check symbols correctly in default mode', () => {
|
||||
expect(utilsDefault.isCheckedSymbol('x')).toBe(true);
|
||||
expect(utilsDefault.isCheckedSymbol('X')).toBe(true);
|
||||
expect(utilsDefault.isCheckedSymbol('/')).toBe(true);
|
||||
expect(utilsDefault.isCheckedSymbol('-')).toBe(true);
|
||||
expect(utilsDefault.isCheckedSymbol('?')).toBe(true);
|
||||
expect(utilsDefault.isCheckedSymbol(' ')).toBe(false); // Только пробел - не отмечено
|
||||
});
|
||||
|
||||
// xOnly mode (xOnlyMode: true)
|
||||
it('should check symbols correctly in xOnly mode', () => {
|
||||
expect(utilsXOnly.isCheckedSymbol('x')).toBe(true); // Только 'x' - отмечено
|
||||
expect(utilsXOnly.isCheckedSymbol('X')).toBe(false);
|
||||
expect(utilsXOnly.isCheckedSymbol('/')).toBe(false);
|
||||
expect(utilsXOnly.isCheckedSymbol('-')).toBe(false);
|
||||
expect(utilsXOnly.isCheckedSymbol('?')).toBe(false);
|
||||
expect(utilsXOnly.isCheckedSymbol(' ')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
// --- updateLineCheckboxStateWithInfo ---
|
||||
describe('updateLineCheckboxStateWithInfo', () => {
|
||||
|
||||
it('should check an unchecked box', () => {
|
||||
const uncheckedLine = ' - [ ] Task';
|
||||
const uncheckedLineInfo = utilsDefault.matchCheckboxLine(uncheckedLine)!;
|
||||
const updatedLine = utilsDefault.updateLineCheckboxStateWithInfo(uncheckedLine, true, uncheckedLineInfo);
|
||||
expect(updatedLine).toBe(' - [x] Task');
|
||||
});
|
||||
|
||||
it('should uncheck a checked box', () => {
|
||||
const checkedLine = ' - [x] Task';
|
||||
const checkedLineInfo = utilsDefault.matchCheckboxLine(checkedLine)!;
|
||||
const updatedLine = utilsDefault.updateLineCheckboxStateWithInfo(checkedLine, false, checkedLineInfo);
|
||||
expect(updatedLine).toBe(' - [ ] Task');
|
||||
});
|
||||
|
||||
it('should handle other initial check chars', () => {
|
||||
const otherLine = ' - [?] Task';
|
||||
const otherLineInfo = utilsDefault.matchCheckboxLine(otherLine)!;
|
||||
expect(utilsDefault.updateLineCheckboxStateWithInfo(otherLine, true, otherLineInfo)).toBe(' - [x] Task');
|
||||
expect(utilsDefault.updateLineCheckboxStateWithInfo(otherLine, false, otherLineInfo)).toBe(' - [ ] Task');
|
||||
});
|
||||
|
||||
it('should return original line if position is invalid (and warn)', () => {
|
||||
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => { }); // Подавить вывод в консоль
|
||||
const uncheckedLine = ' - [ ] Task';
|
||||
const uncheckedLineInfo = utilsDefault.matchCheckboxLine(uncheckedLine)!;
|
||||
const invalidInfo = { ...uncheckedLineInfo, checkboxCharPosition: 100 };
|
||||
const result = utilsDefault.updateLineCheckboxStateWithInfo(uncheckedLine, true, invalidInfo);
|
||||
expect(result).toBe(uncheckedLine);
|
||||
expect(warnSpy).toHaveBeenCalled();
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
// --- propagateStateToChildren ---
|
||||
describe('propagateStateToChildren', () => {
|
||||
const text = [
|
||||
'- [ ] Parent 1', // 0
|
||||
' - [ ] Child 1.1', // 1
|
||||
' - [x] Child 1.2', // 2
|
||||
' - [ ] Grandchild 1.2.1', // 3
|
||||
'- [x] Parent 2', // 4
|
||||
' - [x] Child 2.1', // 5
|
||||
].join('\n');
|
||||
|
||||
it('should check children when parent is checked', () => {
|
||||
// Имитируем проверку Parent 1 (индекс 0)
|
||||
const lines = text.split('\n');
|
||||
lines[0] = '- [x] Parent 1'; // Manually check parent for the test input
|
||||
const initialTextModified = lines.join('\n');
|
||||
|
||||
const result = utilsDefault.propagateStateToChildren(initialTextModified, 0);
|
||||
const expected = [
|
||||
'- [x] Parent 1', // Checked
|
||||
' - [x] Child 1.1', // Updated
|
||||
' - [x] Child 1.2', // Updated
|
||||
' - [x] Grandchild 1.2.1', // Updated
|
||||
'- [x] Parent 2', // Unchanged
|
||||
' - [x] Child 2.1', // Unchanged
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should uncheck children when parent is unchecked', () => {
|
||||
// Имитируем снятие отметки с Parent 2 (индекс 4)
|
||||
const lines = text.split('\n');
|
||||
lines[4] = '- [ ] Parent 2'; // Manually uncheck parent for the test input
|
||||
const initialTextModified = lines.join('\n');
|
||||
|
||||
const result = utilsDefault.propagateStateToChildren(initialTextModified, 4);
|
||||
const expected = [
|
||||
'- [ ] Parent 1', // Unchanged
|
||||
' - [ ] Child 1.1', // Unchanged
|
||||
' - [x] Child 1.2', // Unchanged
|
||||
' - [ ] Grandchild 1.2.1', // Unchanged
|
||||
'- [ ] Parent 2', // Unchecked
|
||||
' - [ ] Child 2.1', // Updated
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should do nothing if the target line is not a checkbox', () => {
|
||||
const textWithNonCheckbox = [
|
||||
'# Header',
|
||||
'- [ ] Item 1'
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateToChildren(textWithNonCheckbox, 0);
|
||||
expect(result).toBe(textWithNonCheckbox);
|
||||
});
|
||||
|
||||
it('should stop only when indent is less than or equal to the original parent', () => {
|
||||
const textSibling = [
|
||||
'- [ ] Parent', // 0, indent 0
|
||||
' - [ ] Child 1', // 1, indent 2
|
||||
' - [ ] Sibling C1', // 2, indent 2 (still > 0)
|
||||
'- [ ] Parent 2' // 3, indent 0 (<= 0, stop here)
|
||||
].join('\n');
|
||||
const lines = textSibling.split('\n');
|
||||
lines[0] = '- [x] Parent'; // Make parent checked
|
||||
const modifiedText = lines.join('\n');
|
||||
const result = utilsDefault.propagateStateToChildren(modifiedText, 0);
|
||||
const expected = [
|
||||
'- [x] Parent',
|
||||
' - [x] Child 1', // Changed (indent 2 > 0)
|
||||
' - [x] Sibling C1', // <<-- ALSO Changed (indent 2 > 0)
|
||||
'- [ ] Parent 2' // Unchanged (indent 0 <= 0)
|
||||
].join('\n');
|
||||
expect(result).toBe(expected); // Проверяем обновленное ожидание
|
||||
});
|
||||
});
|
||||
|
||||
// --- propagateStateFromChildren ---
|
||||
describe('propagateStateFromChildren', () => {
|
||||
it('should check parent if all children are checked', () => {
|
||||
const text = [
|
||||
'- [ ] Parent', // Should become [x]
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2',
|
||||
' - [x] Grandchild 2.1', // Needs to be checked too
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateFromChildren(text);
|
||||
const expected = [
|
||||
'- [x] Parent', // Updated
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2',
|
||||
' - [x] Grandchild 2.1',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should uncheck parent if any child is unchecked', () => {
|
||||
const text = [
|
||||
'- [x] Parent', // Should become [ ]
|
||||
' - [x] Child 1',
|
||||
' - [ ] Child 2', // This one makes parent unchecked
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateFromChildren(text);
|
||||
const expected = [
|
||||
'- [ ] Parent', // Updated
|
||||
' - [x] Child 1',
|
||||
' - [ ] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle nested propagation', () => {
|
||||
const text = [
|
||||
'- [ ] Grandparent', // Should become [ ]
|
||||
' - [x] Parent 1', // Should become [ ]
|
||||
' - [x] Child 1.1',
|
||||
' - [ ] Child 1.2', // Makes Parent 1 unchecked
|
||||
' - [x] Parent 2', // Stays checked
|
||||
' - [x] Child 2.1',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateFromChildren(text);
|
||||
const expected = [
|
||||
'- [ ] Grandparent', // Updated (because Parent 1 is now [ ])
|
||||
' - [ ] Parent 1', // Updated
|
||||
' - [x] Child 1.1',
|
||||
' - [ ] Child 1.2',
|
||||
' - [x] Parent 2',
|
||||
' - [x] Child 2.1',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should not change parent state if it has no children', () => {
|
||||
const text = [
|
||||
'- [ ] Parent No Children',
|
||||
'- [x] Parent No Children Checked',
|
||||
' Some other line',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateFromChildren(text);
|
||||
expect(result).toBe(text); // No changes expected
|
||||
});
|
||||
|
||||
it('should work correctly with xOnlyMode', () => {
|
||||
const text = [
|
||||
'- [ ] Parent', // Should become [x] in xOnly mode
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2'
|
||||
].join('\n');
|
||||
const result = utilsXOnly.propagateStateFromChildren(text);
|
||||
expect(result).toContain('- [x] Parent'); // Parent checked
|
||||
|
||||
const text2 = [
|
||||
'- [x] Parent', // Should become [ ] because '?' is not 'x'
|
||||
' - [x] Child 1',
|
||||
' - [?] Child 2'
|
||||
].join('\n');
|
||||
const result2 = utilsXOnly.propagateStateFromChildren(text2);
|
||||
expect(result2).toContain('- [ ] Parent'); // Parent unchecked
|
||||
});
|
||||
|
||||
it('should handle multiple independent parent checklists', () => {
|
||||
const text = [
|
||||
'- [ ] Parent 1',
|
||||
' - [x] Child 1.1',
|
||||
'Some other text',
|
||||
'* [ ] Parent 2',
|
||||
' * [x] Child 2.1',
|
||||
' * [x] Child 2.2',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateFromChildren(text);
|
||||
const expected = [
|
||||
'- [x] Parent 1', // Updated
|
||||
' - [x] Child 1.1',
|
||||
'Some other text',
|
||||
'* [x] Parent 2', // Updated
|
||||
' * [x] Child 2.1',
|
||||
' * [x] Child 2.2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should stop searching for children for a parent when a line with equal or lesser indent is encountered', () => {
|
||||
const text = [
|
||||
'- [ ] Parent 1', // indent 0
|
||||
'Some regular text', // indent 0. Stops search for Parent 1 children HERE.
|
||||
' - [x] Child 1.1', // indent 2. Ignored for Parent 1 because search stopped.
|
||||
'- [ ] Parent 2', // indent 0. Processed independently later.
|
||||
' - [x] Child 2.1', // indent 2. Child of Parent 2.
|
||||
].join('\n');
|
||||
|
||||
const result = utilsDefault.propagateStateFromChildren(text);
|
||||
|
||||
// Ожидания:
|
||||
// - Parent 1 не найдет детей (из-за "Some regular text") и останется [ ].
|
||||
// - Parent 2 найдет Child 2.1 ([x]) и станет [x].
|
||||
const expected = [
|
||||
'- [ ] Parent 1', // Unchanged
|
||||
'Some regular text', // Unchanged
|
||||
' - [x] Child 1.1', // Unchanged
|
||||
'- [x] Parent 2', // Updated because Child 2.1 is checked
|
||||
' - [x] Child 2.1', // Unchanged
|
||||
].join('\n');
|
||||
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should stop searching for children when a sibling checkbox is encountered', () => {
|
||||
const text = [
|
||||
'- [ ] Parent 1', // indent 0
|
||||
'- [ ] Sibling Parent', // indent 0. Stops search for Parent 1 children HERE.
|
||||
' - [x] Child 1.1', // indent 2. Belongs to Sibling Parent if processed.
|
||||
].join('\n');
|
||||
|
||||
const result = utilsDefault.propagateStateFromChildren(text);
|
||||
|
||||
// Ожидания:
|
||||
// - Parent 1 не найдет детей (из-за "Sibling Parent") и останется [ ].
|
||||
// - Sibling Parent найдет Child 1.1 ([x]) и станет [x].
|
||||
const expected = [
|
||||
'- [ ] Parent 1', // Unchanged
|
||||
'- [x] Sibling Parent', // Updated because Child 1.1 is checked
|
||||
' - [x] Child 1.1', // Unchanged
|
||||
].join('\n');
|
||||
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// --- propagateStateToChildrenFromSingleDiff ---
|
||||
describe('propagateStateToChildrenFromSingleDiff', () => {
|
||||
const textBefore = [
|
||||
'- [ ] Parent', // 0
|
||||
' - [ ] Child', // 1
|
||||
].join('\n');
|
||||
|
||||
it('should propagate down if single line changed and it was a checkbox toggle', () => {
|
||||
const textAfter = [
|
||||
'- [x] Parent', // Changed state
|
||||
' - [ ] Child',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateToChildrenFromSingleDiff(textAfter, textBefore);
|
||||
const expected = [ // Expect children to be updated
|
||||
'- [x] Parent',
|
||||
' - [x] Child',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should NOT propagate down if single line changed but it was NOT checkbox state', () => {
|
||||
const textAfter = [
|
||||
'- [ ] Parent Edited Text', // Text changed, not checkbox
|
||||
' - [ ] Child',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateToChildrenFromSingleDiff(textAfter, textBefore);
|
||||
// Expect original textAfter, no downward propagation
|
||||
expect(result).toBe(textAfter);
|
||||
});
|
||||
|
||||
it('should NOT propagate down if single line changed into non-checkbox', () => {
|
||||
const textAfter = [
|
||||
'Parent removed checkbox', // Structure changed
|
||||
' - [ ] Child',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateToChildrenFromSingleDiff(textAfter, textBefore);
|
||||
expect(result).toBe(textAfter);
|
||||
});
|
||||
|
||||
|
||||
it('should NOT propagate down if multiple lines changed', () => {
|
||||
const textAfter = [
|
||||
'- [x] Parent', // Changed
|
||||
' - [x] Child', // Changed
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateToChildrenFromSingleDiff(textAfter, textBefore);
|
||||
expect(result).toBe(textAfter); // Expect original textAfter
|
||||
});
|
||||
|
||||
it('should NOT propagate down if line counts differ', () => {
|
||||
const textAfter = [
|
||||
'- [x] Parent',
|
||||
' - [ ] Child',
|
||||
' - [ ] New Child',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateToChildrenFromSingleDiff(textAfter, textBefore);
|
||||
expect(result).toBe(textAfter); // Expect original textAfter
|
||||
});
|
||||
|
||||
it('should NOT propagate down if textBefore is undefined', () => {
|
||||
const textAfter = [
|
||||
'- [x] Parent',
|
||||
' - [ ] Child',
|
||||
].join('\n');
|
||||
const result = utilsDefault.propagateStateToChildrenFromSingleDiff(textAfter, undefined);
|
||||
expect(result).toBe(textAfter); // Expect original textAfter
|
||||
});
|
||||
});
|
||||
|
||||
// --- findDifferentLineIndexes ---
|
||||
describe('findDifferentLineIndexes', () => {
|
||||
const lines1 = ['a', 'b', 'c'];
|
||||
|
||||
it('should return empty array for identical lines', () => {
|
||||
const lines2 = ['a', 'b', 'c'];
|
||||
expect(utilsDefault.findDifferentLineIndexes(lines1, lines2)).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return index of the single different line', () => {
|
||||
const lines2 = ['a', 'B', 'c'];
|
||||
expect(utilsDefault.findDifferentLineIndexes(lines1, lines2)).toEqual([1]);
|
||||
});
|
||||
|
||||
it('should return indexes of multiple different lines', () => {
|
||||
const lines2 = ['A', 'b', 'C'];
|
||||
expect(utilsDefault.findDifferentLineIndexes(lines1, lines2)).toEqual([0, 2]);
|
||||
});
|
||||
|
||||
it('should throw error if line lengths are different', () => {
|
||||
const lines2 = ['a', 'b'];
|
||||
expect(() => utilsDefault.findDifferentLineIndexes(lines1, lines2)).toThrow(
|
||||
'the length of the lines must be equal'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// --- syncText (Integration) ---
|
||||
describe('syncText', () => {
|
||||
describe('When user changes parent state directly', () => {
|
||||
const textBefore = [
|
||||
'- [ ] Parent',
|
||||
' - [ ] Child 1',
|
||||
' - [ ] Child 2',
|
||||
].join('\n');
|
||||
const textAfterUserCheck = [
|
||||
'- [x] Parent', // User checked this
|
||||
' - [ ] Child 1',
|
||||
' - [ ] Child 2',
|
||||
].join('\n');
|
||||
|
||||
it('should propagate down when child sync is ENABLED', () => {
|
||||
const result = utilsDefault.syncText(textAfterUserCheck, textBefore);
|
||||
const expected = [
|
||||
'- [x] Parent',
|
||||
' - [x] Child 1', // Propagated down
|
||||
' - [x] Child 2', // Propagated down
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should NOT propagate down when child sync is DISABLED', () => {
|
||||
const result = utilsChildSyncDisabled.syncText(textAfterUserCheck, textBefore);
|
||||
const expected = [ // Ожидаем, что дети НЕ изменились
|
||||
'- [ ] Parent', // propagateStateFromChildren
|
||||
' - [ ] Child 1',
|
||||
' - [ ] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
const textBeforeUncheck = [
|
||||
'- [x] Parent',
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
const textAfterUserUncheck = [
|
||||
'- [ ] Parent', // User unchecked this
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
|
||||
it('should propagate down (uncheck) when child sync is ENABLED', () => {
|
||||
const result = utilsDefault.syncText(textAfterUserUncheck, textBeforeUncheck);
|
||||
const expected = [
|
||||
'- [ ] Parent',
|
||||
' - [ ] Child 1', // Propagated down
|
||||
' - [ ] Child 2', // Propagated down
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should NOT propagate down (uncheck) when child sync is DISABLED', () => {
|
||||
const result = utilsChildSyncDisabled.syncText(textAfterUserUncheck, textBeforeUncheck);
|
||||
const expected = [ // Ожидаем, что дети НЕ изменились
|
||||
'- [x] Parent', // propagateStateFromChildren
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should update parent when parent sync is ENABLED and user checks last child', () => {
|
||||
const textBefore = [
|
||||
'- [ ] Parent',
|
||||
' - [x] Child 1',
|
||||
' - [ ] Child 2', // User will check this
|
||||
].join('\n');
|
||||
const textAfterUserCheck = [
|
||||
'- [ ] Parent',
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2', // User checked this
|
||||
].join('\n');
|
||||
|
||||
const result = utilsDefault.syncText(textAfterUserCheck, textBefore);
|
||||
// SingleDiff won't trigger down prop. FromChildren runs.
|
||||
const expected = [
|
||||
'- [x] Parent', // Updated by FromChildren
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should NOT update parent when parent sync is DISABLED and user checks last child', () => {
|
||||
const textBefore = [
|
||||
'- [ ] Parent',
|
||||
' - [x] Child 1',
|
||||
' - [ ] Child 2', // User will check this
|
||||
].join('\n');
|
||||
const textAfterChildCheck = [
|
||||
'- [ ] Parent', // State before syncText runs propagateFromChildren
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2', // User checked this
|
||||
].join('\n');
|
||||
const result = utilsParentSyncDisabled.syncText(textAfterChildCheck, textBefore); // Использует utilsParentSyncDisabled
|
||||
const expected = [ // Родитель НЕ должен обновиться
|
||||
'- [ ] Parent',
|
||||
' - [x] Child 1',
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should update parent when parent sync is ENABLED and user unchecks child', () => {
|
||||
const textBefore = [
|
||||
'- [x] Parent',
|
||||
' - [x] Child 1', // User will uncheck this
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
const textAfterUserUncheck = [
|
||||
'- [x] Parent',
|
||||
' - [ ] Child 1', // User unchecked this
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
|
||||
const result = utilsDefault.syncText(textAfterUserUncheck, textBefore);
|
||||
// SingleDiff won't trigger down prop. FromChildren runs.
|
||||
const expected = [
|
||||
'- [ ] Parent', // Updated by FromChildren
|
||||
' - [ ] Child 1',
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should NOT update parent when parent sync is DISABLED and user unchecks child', () => {
|
||||
const textBefore = [
|
||||
'- [x] Parent',
|
||||
' - [x] Child 1', // User will uncheck this
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
const textAfterChildUncheck = [
|
||||
'- [x] Parent', // State before syncText runs propagateFromChildren
|
||||
' - [ ] Child 1', // User unchecked this
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
const result = utilsParentSyncDisabled.syncText(textAfterChildUncheck, textBefore); // utilsParentSyncDisabled
|
||||
const expected = [ // Родитель НЕ должен обновиться
|
||||
'- [x] Parent',
|
||||
' - [ ] Child 1',
|
||||
' - [x] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should update parent based on children when multiple lines change and parent sync is ENABLED', () => {
|
||||
const textBefore = [
|
||||
'- [ ] Parent',
|
||||
' - [ ] Child 1',
|
||||
' - [ ] Child 2',
|
||||
' - [ ] Child 3',
|
||||
].join('\n');
|
||||
// User checks Parent AND Child 1, but leaves Child 2 unchecked
|
||||
const textAfterMultipleChanges = [
|
||||
'- [x] Parent', // Changed by user
|
||||
' - [x] Child 1', // Changed by user
|
||||
' - [ ] Child 2', // Left unchecked
|
||||
' - [ ] Child 3', // Left unchecked
|
||||
].join('\n');
|
||||
|
||||
const result = utilsDefault.syncText(textAfterMultipleChanges, textBefore);
|
||||
// SingleDiff won't run (2 changes). FromChildren runs.
|
||||
// Since Child 2/3 are unchecked, Parent should become unchecked.
|
||||
const expected = [
|
||||
'- [ ] Parent', // Corrected by FromChildren
|
||||
' - [x] Child 1',
|
||||
' - [ ] Child 2',
|
||||
' - [ ] Child 3',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should NOT update parent when multiple lines change and parent sync is DISABLED', () => {
|
||||
const textBefore = [
|
||||
'- [ ] Parent',
|
||||
' - [ ] Child 1',
|
||||
' - [ ] Child 2',
|
||||
].join('\n');
|
||||
const textAfterMultipleChanges = [ // User checks Parent and Child 1
|
||||
'- [x] Parent',
|
||||
' - [x] Child 1',
|
||||
' - [ ] Child 2',
|
||||
].join('\n');
|
||||
const result = utilsParentSyncDisabled.syncText(textAfterMultipleChanges, textBefore); // utilsParentSyncDisabled
|
||||
const expected = [ // Родитель НЕ корректируется, остается как есть
|
||||
'- [x] Parent',
|
||||
' - [x] Child 1',
|
||||
' - [ ] Child 2',
|
||||
].join('\n');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
import { CheckboxUtils } from "../src/checkboxUtils";
|
||||
|
||||
describe("CheckboxUtils old", () => {
|
||||
let checkboxUtilsXOnly: CheckboxUtils;
|
||||
let checkboxUtilsSpaceOnly: CheckboxUtils;
|
||||
|
||||
beforeEach(() => {
|
||||
checkboxUtilsXOnly = new CheckboxUtils({ xOnlyMode: true, enableAutomaticParentState: true, enableAutomaticChildState: true, });
|
||||
checkboxUtilsSpaceOnly = new CheckboxUtils({ xOnlyMode: false, enableAutomaticParentState: true, enableAutomaticChildState: true,});
|
||||
});
|
||||
|
||||
describe("findCheckboxesLine", () => {
|
||||
test("recognizes valid checkbox lines", () => {
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("- [ ] Task")).not.toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine(" - [ ] Task")).not.toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("- [x] Task")).not.toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("* [ ] Another task")).not.toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("+ [x] Task")).not.toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("1. [ ] Numbered task")).not.toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("1. [x] Numbered task")).not.toBeNull();
|
||||
});
|
||||
|
||||
test("correctly handles different checkbox states", () => {
|
||||
const states = [" ", "x", "-", "?", "!", "*", "#", "@", "[", "]", "y", "X", "Y"];
|
||||
|
||||
for (const state of states) {
|
||||
const lineInfo = checkboxUtilsXOnly.matchCheckboxLine(`- [${state}] Task`);
|
||||
expect(lineInfo).not.toBeNull();
|
||||
expect(lineInfo?.checkChar).toBe(state);
|
||||
}
|
||||
});
|
||||
|
||||
test("correctly handles indentation", () => {
|
||||
const noIndentMatch = checkboxUtilsXOnly.matchCheckboxLine("- [ ] Task");
|
||||
expect(noIndentMatch).not.toBeNull();
|
||||
expect(noIndentMatch!.indent).toBe("".length);
|
||||
|
||||
const singleSpaceMatch = checkboxUtilsXOnly.matchCheckboxLine(" - [ ] Task");
|
||||
expect(singleSpaceMatch).not.toBeNull();
|
||||
expect(singleSpaceMatch!.indent).toBe(" ".length);
|
||||
|
||||
const multiSpaceMatch = checkboxUtilsXOnly.matchCheckboxLine(" - [ ] Task");
|
||||
expect(multiSpaceMatch).not.toBeNull();
|
||||
expect(multiSpaceMatch!.indent).toBe(" ".length);
|
||||
|
||||
const tabMatch = checkboxUtilsXOnly.matchCheckboxLine("\t- [ ] Task");
|
||||
expect(tabMatch).not.toBeNull();
|
||||
expect(tabMatch!.indent).toBe("\t".length);
|
||||
});
|
||||
|
||||
test("ignores invalid lines", () => {
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("-[ ] Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("*[x] Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("1.[ ] Numbered task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("- [] Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine(" - Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("Just some text")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("1. Some numbered task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("")).toBeNull();
|
||||
});
|
||||
|
||||
test("ignores lines with missing opening or closing brackets", () => {
|
||||
// Missing opening bracket [
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("- ] Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("* ] Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("+ ] Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("1. ] Task")).toBeNull();
|
||||
|
||||
// Missing closing bracket ]
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("- [x Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("* [ Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("+ [- Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("1. [? Task")).toBeNull();
|
||||
|
||||
// Malformed with spaces
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("- [ x Task")).toBeNull();
|
||||
expect(checkboxUtilsXOnly.matchCheckboxLine("- x] Task")).toBeNull();
|
||||
});
|
||||
|
||||
test("extracts list marker correctly", () => {
|
||||
const dashMatch = checkboxUtilsXOnly.matchCheckboxLine("- [ ] Task");
|
||||
expect(dashMatch).not.toBeNull();
|
||||
expect(dashMatch!.marker).toBe("-");
|
||||
|
||||
const asteriskMatch = checkboxUtilsXOnly.matchCheckboxLine("* [ ] Task");
|
||||
expect(asteriskMatch).not.toBeNull();
|
||||
expect(asteriskMatch!.marker).toBe("*");
|
||||
|
||||
const plusMatch = checkboxUtilsXOnly.matchCheckboxLine("+ [ ] Task");
|
||||
expect(plusMatch).not.toBeNull();
|
||||
expect(plusMatch!.marker).toBe("+");
|
||||
|
||||
const numberedMatch = checkboxUtilsXOnly.matchCheckboxLine("1. [ ] Task");
|
||||
expect(numberedMatch).not.toBeNull();
|
||||
expect(numberedMatch!.marker).toBe("1.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("isCheckedSymbol", () => {
|
||||
test("in xOnlyMode only 'x' is considered checked", () => {
|
||||
expect(checkboxUtilsXOnly.isCheckedSymbol("x")).toBe(true);
|
||||
expect(checkboxUtilsXOnly.isCheckedSymbol(" ")).toBe(false);
|
||||
expect(checkboxUtilsXOnly.isCheckedSymbol("-")).toBe(false);
|
||||
expect(checkboxUtilsXOnly.isCheckedSymbol("?")).toBe(false);
|
||||
});
|
||||
|
||||
test("in normal mode all symbols except space are considered checked", () => {
|
||||
expect(checkboxUtilsSpaceOnly.isCheckedSymbol("x")).toBe(true);
|
||||
expect(checkboxUtilsSpaceOnly.isCheckedSymbol(" ")).toBe(false);
|
||||
expect(checkboxUtilsSpaceOnly.isCheckedSymbol("-")).toBe(true);
|
||||
expect(checkboxUtilsSpaceOnly.isCheckedSymbol("?")).toBe(true);
|
||||
});
|
||||
|
||||
test("handles uppercase 'X' correctly", () => {
|
||||
expect(checkboxUtilsXOnly.isCheckedSymbol("X")).toBe(false);
|
||||
expect(checkboxUtilsSpaceOnly.isCheckedSymbol("X")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateSettings", () => {
|
||||
test("updates xOnlyMode setting correctly", () => {
|
||||
|
||||
const settings = { xOnlyMode: true, enableAutomaticParentState: true, enableAutomaticChildState: true,};
|
||||
const utils = new CheckboxUtils(settings);
|
||||
expect(utils.isCheckedSymbol("-")).toBe(false);
|
||||
|
||||
settings.xOnlyMode = false;
|
||||
expect(utils.isCheckedSymbol("-")).toBe(true);
|
||||
|
||||
settings.xOnlyMode = true;
|
||||
expect(utils.isCheckedSymbol("-")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("syncCheckboxes", () => {
|
||||
test("updates parent checkbox if all children are checked (xOnlyMode)", () => {
|
||||
const text = "- [ ] Parent\n - [x] Child 1\n - [x] Child 2";
|
||||
const expected = "- [x] Parent\n - [x] Child 1\n - [x] Child 2";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("updates parent checkbox if all children are checked (spaceOnly)", () => {
|
||||
const text = "- [ ] Parent\n - [?] Child 1\n - [-] Child 2";
|
||||
const expected = "- [x] Parent\n - [?] Child 1\n - [-] Child 2";
|
||||
expect(checkboxUtilsSpaceOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("unchecks parent if not all children are checked", () => {
|
||||
const text = "- [x] Parent\n - [x] Child 1\n - [ ] Child 2";
|
||||
const expected = "- [ ] Parent\n - [x] Child 1\n - [ ] Child 2";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("doesn't change parent if it has no children", () => {
|
||||
const text = "- [x] Single";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(text);
|
||||
});
|
||||
|
||||
test("handles multiple levels of nesting correctly", () => {
|
||||
const text = "- [ ] Parent\n - [ ] Child\n - [x] Grandchild";
|
||||
const expected = "- [x] Parent\n - [x] Child\n - [x] Grandchild";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("handles mixed indentation levels correctly", () => {
|
||||
const text = "- [ ] Parent\n - [x] Child 1\n - [x] Grandchild 1\n - [x] Child 2";
|
||||
const expected = "- [x] Parent\n - [x] Child 1\n - [x] Grandchild 1\n - [x] Child 2";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("handles siblings with different indentation correctly", () => {
|
||||
const text = "- [ ] Parent\n - [x] Child 1\n - [x] Grandchild 1\n - [ ] Child 2";
|
||||
const expected = "- [ ] Parent\n - [x] Child 1\n - [x] Grandchild 1\n - [ ] Child 2";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("handles multiple parents correctly", () => {
|
||||
const text = "- [ ] Parent 1\n - [x] Child 1\n- [ ] Parent 2\n - [x] Child 2";
|
||||
const expected = "- [x] Parent 1\n - [x] Child 1\n- [x] Parent 2\n - [x] Child 2";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("handles mixed content with non-checkbox lines correctly", () => {
|
||||
const text = "- [ ] Parent\nSome regular text\n - [x] Child 1\nMore text\n - [x] Child 2";
|
||||
const expected = "- [ ] Parent\nSome regular text\n - [x] Child 1\nMore text\n - [x] Child 2";
|
||||
expect(checkboxUtilsXOnly.propagateStateFromChildren(text)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue