diff --git a/packages/core/src/blocks/ListItem/NumberedListItem/block.ts b/packages/core/src/blocks/ListItem/NumberedListItem/block.ts index 677d02523a..f3b5f108de 100644 --- a/packages/core/src/blocks/ListItem/NumberedListItem/block.ts +++ b/packages/core/src/blocks/ListItem/NumberedListItem/block.ts @@ -51,13 +51,9 @@ export const createNumberedListItemBlockSpec = createBlockSpec( const defaultProps = parseDefaultProps(element); - if (element.previousElementSibling || startIndex === 1) { - return defaultProps; - } - return { ...defaultProps, - start: startIndex, + start: element.previousElementSibling || startIndex === 1 ? undefined : startIndex, }; } diff --git a/tests/src/unit/core/blocks/NumberedListItem.test.ts b/tests/src/unit/core/blocks/NumberedListItem.test.ts new file mode 100644 index 0000000000..0187b2470d --- /dev/null +++ b/tests/src/unit/core/blocks/NumberedListItem.test.ts @@ -0,0 +1,101 @@ +import { describe, expect, it } from "vitest"; +import { createNumberedListItemBlockSpec } from "../../../../../packages/core/src/blocks/ListItem/NumberedListItem/block.js"; + +describe("NumberedListItem parse() method", () => { + const blockSpec = createNumberedListItemBlockSpec(); + const parseFunc = blockSpec.implementation.parse; + + if (!parseFunc) { + throw new Error("parse function not found"); + } + + it("should always return an object with 'start' property - first item, startIndex=1", () => { + // Create mock DOM elements + const li = document.createElement("li"); + const ol = document.createElement("ol"); + ol.setAttribute("start", "1"); + ol.appendChild(li); + + const result = parseFunc(li); + + // The parse function should return an object with 'start' property + expect(result).toBeDefined(); + expect(result).toHaveProperty("start"); + expect(result?.start).toBeUndefined(); // Should be undefined for first item at index 1 + }); + + it("should always return an object with 'start' property - first item, startIndex=5", () => { + const li = document.createElement("li"); + const ol = document.createElement("ol"); + ol.setAttribute("start", "5"); + ol.appendChild(li); + + const result = parseFunc(li); + + expect(result).toBeDefined(); + expect(result).toHaveProperty("start"); + expect(result?.start).toBe(5); // Should be 5 for first item at non-standard index + }); + + it("should always return an object with 'start' property - subsequent item", () => { + const li1 = document.createElement("li"); + const li2 = document.createElement("li"); + const ol = document.createElement("ol"); + ol.setAttribute("start", "1"); + ol.appendChild(li1); + ol.appendChild(li2); + + const result = parseFunc(li2); + + expect(result).toBeDefined(); + expect(result).toHaveProperty("start"); + expect(result?.start).toBeUndefined(); // Subsequent items don't need explicit start + }); + + it("should always return an object with 'start' property - subsequent item in list starting at 5", () => { + const li1 = document.createElement("li"); + const li2 = document.createElement("li"); + const ol = document.createElement("ol"); + ol.setAttribute("start", "5"); + ol.appendChild(li1); + ol.appendChild(li2); + + const result = parseFunc(li2); + + expect(result).toBeDefined(); + expect(result).toHaveProperty("start"); + expect(result?.start).toBeUndefined(); // Subsequent items get undefined + }); + + it("regression test for issue #2241 - ensures 'start' property is always present", () => { + // This test verifies the fix for issue #2241 + // The old code would return defaultProps (without 'start') for certain conditions + // The new code always includes 'start' in the returned object + + const testCases = [ + { startAttr: "1", hasPreSibling: false, expectedStart: undefined }, + { startAttr: "1", hasPreSibling: true, expectedStart: undefined }, + { startAttr: "5", hasPreSibling: false, expectedStart: 5 }, + { startAttr: "5", hasPreSibling: true, expectedStart: undefined }, + ]; + + testCases.forEach(({ startAttr, hasPreSibling, expectedStart }) => { + const li = document.createElement("li"); + const ol = document.createElement("ol"); + ol.setAttribute("start", startAttr); + + if (hasPreSibling) { + const li1 = document.createElement("li"); + ol.appendChild(li1); + } + + ol.appendChild(li); + + const result = parseFunc(li); + + // Critical assertion: 'start' property must ALWAYS be present + expect(result).toHaveProperty("start"); + expect(result?.start).toBe(expectedStart); + }); + }); +}); diff --git a/tests/src/unit/core/formatConversion/parse/__snapshots__/markdown/issue2241NumberedListStartProperty.json b/tests/src/unit/core/formatConversion/parse/__snapshots__/markdown/issue2241NumberedListStartProperty.json new file mode 100644 index 0000000000..b31cdba778 --- /dev/null +++ b/tests/src/unit/core/formatConversion/parse/__snapshots__/markdown/issue2241NumberedListStartProperty.json @@ -0,0 +1,104 @@ +[ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "First item", + "type": "text", + }, + ], + "id": "1", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "numberedListItem", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Second item", + "type": "text", + }, + ], + "id": "2", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "numberedListItem", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Third item", + "type": "text", + }, + ], + "id": "3", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "numberedListItem", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "List starting at 5", + "type": "text", + }, + ], + "id": "4", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "numberedListItem", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Second item", + "type": "text", + }, + ], + "id": "5", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "numberedListItem", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Third item", + "type": "text", + }, + ], + "id": "6", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "numberedListItem", + }, +] \ No newline at end of file diff --git a/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts b/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts index 86fe9157be..b3257825ae 100644 --- a/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts +++ b/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts @@ -1111,4 +1111,17 @@ Regular paragraph`, }, executeTest: testParseMarkdown, }, + { + testCase: { + name: "issue2241NumberedListStartProperty", + content: `1. First item +2. Second item +3. Third item + +5. List starting at 5 +6. Second item +7. Third item`, + }, + executeTest: testParseMarkdown, + }, ];