From 38cd7e86803c6724ca0894f6b86702e42e9c9f6c Mon Sep 17 00:00:00 2001 From: asouqi Date: Thu, 15 Jan 2026 20:16:32 +0300 Subject: [PATCH] Add more test cases for open slice ends --- test/__fixtures__/manuscript-simple.json | 479 +++++++++++------- test/manuscript/manuscript.test.ts | 4 +- test/nodes/nodes.test.ts | 8 +- .../replace-around-steps.test.ts | 102 +++- 4 files changed, 384 insertions(+), 209 deletions(-) diff --git a/test/__fixtures__/manuscript-simple.json b/test/__fixtures__/manuscript-simple.json index fb606c95..9b96d193 100644 --- a/test/__fixtures__/manuscript-simple.json +++ b/test/__fixtures__/manuscript-simple.json @@ -2,320 +2,419 @@ { "type": "manuscript", "attrs": { - "id": "MPManuscript:BFABFC43-99C7-4F4D-985E-777B2138A726" + "id": "MPManuscript:BFABFC43-99C7-4F4D-985E-777B2138A726", + "doi": "", + "prototype": "", + "primaryLanguageCode": "", + "articleType": "" }, "content": [ { - "type": "section", + "type": "title", "attrs": { - "id": "MPSection:919A1176-C606-4105-9783-8A0ABEB952B5", - "category": "MPSectionCategory:abstract", - "titleSuppressed": false, + "id": "", + "placeholder": "Insert title here...", "dataTracked": null + } + }, + { + "type": "abstracts", + "attrs": { + "id": "" + } + }, + { + "type": "body", + "attrs": { + "id": "" }, "content": [ { - "type": "section_title", + "type": "section", "attrs": { + "id": "MPSection:919A1176-C606-4105-9783-8A0ABEB952B5", + "category": "MPSectionCategory:abstract", + "titleSuppressed": false, "dataTracked": null }, "content": [ { - "type": "text", - "text": "Abstract" - } - ] - }, - { - "type": "paragraph", - "attrs": { - "id": "MPParagraphElement:A1890637-54EB-44E0-BC19-A6C6FA5F2C94", - "paragraphStyle": "", - "placeholder": "" - }, - "content": [ - { - "type": "text", - "text": "First section" - } - ] - }, - { - "type": "blockquote_element", - "attrs": { - "id": "MPQuoteElement:9F51C428-D458-4A62-A9AE-ADA5FF60D598", - "paragraphStyle": "", - "placeholder": "" - }, - "content": [ + "type": "section_title", + "attrs": { + "dataTracked": null + }, + "content": [ + { + "type": "text", + "text": "Abstract" + } + ] + }, { "type": "paragraph", "attrs": { - "id": "MPParagraphElement:628749AD-BBFE-4A83-B98B-9D14F069D6C2", + "id": "MPParagraphElement:A1890637-54EB-44E0-BC19-A6C6FA5F2C94", "paragraphStyle": "", "placeholder": "" }, "content": [ { "type": "text", - "text": "I am a quote" + "text": "First section" } ] }, { - "type": "attribution", + "type": "blockquote_element", + "attrs": { + "id": "MPQuoteElement:9F51C428-D458-4A62-A9AE-ADA5FF60D598", + "paragraphStyle": "", + "placeholder": "" + }, "content": [ { - "type": "text", - "text": "I am an attribution" + "type": "paragraph", + "attrs": { + "id": "MPParagraphElement:628749AD-BBFE-4A83-B98B-9D14F069D6C2", + "paragraphStyle": "", + "placeholder": "" + }, + "content": [ + { + "type": "text", + "text": "I am a quote" + } + ] + }, + { + "type": "attribution", + "content": [ + { + "type": "text", + "text": "I am an attribution" + } + ] } ] } ] - } - ] - }, - { - "type": "section", - "attrs": { - "id": "MPSection:8F47C5E7-4F17-44B1-8597-542C7B398172", - "category": "MPSectionCategory:introduction", - "titleSuppressed": false - }, - "content": [ - { - "type": "section_title", - "content": [ - { - "type": "text", - "text": "Introduction" - } - ] }, { - "type": "paragraph", + "type": "section", "attrs": { - "id": "MPParagraphElement:920E413A-7920-48D7-B1DC-8E010138620E", - "paragraphStyle": "", - "placeholder": "" + "id": "MPSection:8F47C5E7-4F17-44B1-8597-542C7B398172", + "category": "MPSectionCategory:introduction", + "titleSuppressed": false }, "content": [ { - "type": "text", - "text": "Second section" - } - ] - }, - { - "type": "figure_element", - "attrs": { - "figureLayout": "", - "figureStyle": "", - "id": "MPFigureElement:37C9C906-3472-4A2C-B170-B2B0E62FC0D9", - "label": "", - "sizeFraction": 0, - "suppressCaption": false - }, - "content": [ + "type": "section_title", + "content": [ + { + "type": "text", + "text": "Introduction" + } + ] + }, { - "type": "figure", + "type": "paragraph", "attrs": { - "id": "MPFigure:7AA967A7-BF9E-4B67-8B1D-11CB4DA2A660", - "label": "", - "src": "", - "contentType": "" + "id": "MPParagraphElement:920E413A-7920-48D7-B1DC-8E010138620E", + "paragraphStyle": "", + "placeholder": "" }, "content": [ { - "type": "figcaption" + "type": "text", + "text": "Second section" } ] }, { - "type": "figcaption", + "type": "list", + "attrs": { + "id": "MPListElement:3FA8E030-1275-485A-910F-4D3541AC11BE", + "dataTracked": null, + "listStyleType": "bullet" + }, "content": [ { - "type": "caption_title", + "type": "list_item", "attrs": { - "placeholder": "Title..." - } + "dataTracked": null, + "placeholder": "List item" + }, + "content": [ + { + "type": "paragraph", + "attrs": { + "id": "MPParagraphElement:37962805-18AA-4706-AEDC-129FEF1DE422", + "comments": null, + "dataTracked": null, + "placeholder": "", + "paragraphStyle": "" + }, + "content": [ + { + "text": "B1", + "type": "text" + } + ] + } + ] }, { - "type": "caption", + "type": "list_item", "attrs": { - "placeholder": "Caption..." + "dataTracked": null, + "placeholder": "List item" }, "content": [ { - "type": "text", - "text": "I am a caption" + "type": "paragraph", + "attrs": { + "id": "MPParagraphElement:76B8C5F8-09DA-4066-9341-7D575D5F4367", + "comments": null, + "dataTracked": null, + "placeholder": "", + "paragraphStyle": "" + }, + "content": [ + { + "text": "B2", + "type": "text" + } + ] } ] } ] }, { - "type": "listing", - "attrs": { - "id": "MPListing:73A88D44-9223-412D-AF24-8CE6F3E5D44B", - "contents": "", - "language": "", - "languageKey": "null", - "isExpanded": false, - "isExecuting": false - } - } - ] - }, - { - "type": "table_element", - "attrs": { - "id": "MPTableElement:F577BB5E-87AB-4003-AAAD-A3A6B10BA815", - "dataTracked": null - }, - "content": [ - { - "type": "figcaption", + "type": "figure_element", "attrs": { - "dataTracked": null + "figureLayout": "", + "figureStyle": "", + "id": "MPFigureElement:37C9C906-3472-4A2C-B170-B2B0E62FC0D9", + "label": "", + "sizeFraction": 0, + "suppressCaption": false }, "content": [ { - "type": "caption_title", + "type": "figure", "attrs": { - "placeholder": "Title...", - "dataTracked": null - } + "id": "MPFigure:7AA967A7-BF9E-4B67-8B1D-11CB4DA2A660", + "label": "", + "src": "", + "contentType": "" + }, + "content": [ + { + "type": "figcaption" + } + ] }, { - "type": "caption", + "type": "figcaption", + "content": [ + { + "type": "caption_title", + "attrs": { + "placeholder": "Title..." + } + }, + { + "type": "caption", + "attrs": { + "placeholder": "Caption..." + }, + "content": [ + { + "type": "text", + "text": "I am a caption" + } + ] + } + ] + }, + { + "type": "listing", "attrs": { - "placeholder": "Caption...", - "dataTracked": null + "id": "MPListing:73A88D44-9223-412D-AF24-8CE6F3E5D44B", + "contents": "", + "language": "", + "languageKey": "null", + "isExpanded": false, + "isExecuting": false } } ] }, { - "type": "table", + "type": "table_element", "attrs": { - "id": "MPTable:B4338040-0106-400D-8A3A-141C8FF3DE32", + "id": "MPTableElement:F577BB5E-87AB-4003-AAAD-A3A6B10BA815", "dataTracked": null }, "content": [ { - "type": "table_row", + "type": "figcaption", "attrs": { "dataTracked": null }, "content": [ { - "type": "table_cell", + "type": "caption_title", "attrs": { - "colspan": 1, - "rowspan": 1, - "colwidth": null, - "placeholder": "Data", - "valign": null, - "align": null, - "scope": null, - "style": null, + "placeholder": "Title...", "dataTracked": null - }, - "content": [ - { - "type": "text", - "text": "0" - } - ] + } }, { - "type": "table_cell", + "type": "caption", "attrs": { - "colspan": 1, - "rowspan": 1, - "colwidth": null, - "placeholder": "Data", - "valign": null, - "align": null, - "scope": null, - "style": null, + "placeholder": "Caption...", "dataTracked": null - }, - "content": [ - { - "type": "text", - "text": "1" - } - ] + } } ] }, { - "type": "table_row", + "type": "table", "attrs": { + "id": "MPTable:B4338040-0106-400D-8A3A-141C8FF3DE32", "dataTracked": null }, "content": [ { - "type": "table_cell", + "type": "table_row", "attrs": { - "colspan": 1, - "rowspan": 1, - "colwidth": null, - "placeholder": "Data", - "valign": null, - "align": null, - "scope": null, - "style": null, "dataTracked": null }, "content": [ { - "type": "text", - "text": "2" + "type": "table_cell", + "attrs": { + "colspan": 1, + "rowspan": 1, + "colwidth": null, + "placeholder": "Data", + "valign": null, + "align": null, + "scope": null, + "style": null, + "dataTracked": null + }, + "content": [ + { + "type": "text", + "text": "0" + } + ] + }, + { + "type": "table_cell", + "attrs": { + "colspan": 1, + "rowspan": 1, + "colwidth": null, + "placeholder": "Data", + "valign": null, + "align": null, + "scope": null, + "style": null, + "dataTracked": null + }, + "content": [ + { + "type": "text", + "text": "1" + } + ] } ] }, { - "type": "table_cell", + "type": "table_row", "attrs": { - "colspan": 1, - "rowspan": 1, - "colwidth": null, - "placeholder": "Data", - "valign": null, - "align": null, - "scope": null, - "style": null, "dataTracked": null }, "content": [ { - "type": "text", - "text": "3" + "type": "table_cell", + "attrs": { + "colspan": 1, + "rowspan": 1, + "colwidth": null, + "placeholder": "Data", + "valign": null, + "align": null, + "scope": null, + "style": null, + "dataTracked": null + }, + "content": [ + { + "type": "text", + "text": "2" + } + ] + }, + { + "type": "table_cell", + "attrs": { + "colspan": 1, + "rowspan": 1, + "colwidth": null, + "placeholder": "Data", + "valign": null, + "align": null, + "scope": null, + "style": null, + "dataTracked": null + }, + "content": [ + { + "type": "text", + "text": "3" + } + ] } ] } ] + }, + { + "type": "listing", + "attrs": { + "id": "MPListing:910EEF2F-12F7-4C49-91B7-BC499646A0B1", + "contents": "", + "language": "", + "languageKey": "null", + "isExpanded": false, + "isExecuting": false, + "dataTracked": null + } } ] - }, - { - "type": "listing", - "attrs": { - "id": "MPListing:910EEF2F-12F7-4C49-91B7-BC499646A0B1", - "contents": "", - "language": "", - "languageKey": "null", - "isExpanded": false, - "isExecuting": false, - "dataTracked": null - } } ] } ] + }, + { + "type": "backmatter", + "attrs": { + "id": "", + "placeholder": " " + } + }, + { + "type": "comments", + "attrs": { + "id": "" + } } ] } diff --git a/test/manuscript/manuscript.test.ts b/test/manuscript/manuscript.test.ts index d7661a77..e6cbd6af 100644 --- a/test/manuscript/manuscript.test.ts +++ b/test/manuscript/manuscript.test.ts @@ -50,8 +50,8 @@ describe('manuscript.test', () => { doc: docs.manuscriptSimple[0], schema: schema as unknown as Schema, }) - .insertNode(schema.nodes.table_element.createAndFill() as unknown as PMNode, 11) - .insertNode(schema.nodes.figure_element.createAndFill() as unknown as PMNode, 11) + .insertNode(schema.nodes.table_element.createAndFill() as unknown as PMNode, 15) + .insertNode(schema.nodes.figure_element.createAndFill() as unknown as PMNode, 15) .cmd((state, dispatch) => { const trackChangesState = trackChangesPluginKey.getState(state) if (!trackChangesState) { diff --git a/test/nodes/nodes.test.ts b/test/nodes/nodes.test.ts index 78232b6c..c7640c70 100644 --- a/test/nodes/nodes.test.ts +++ b/test/nodes/nodes.test.ts @@ -407,20 +407,20 @@ describe('nodes.test', () => { const tr = state.tr const tableFooter = manuscriptSchema.nodes.table_element_footer.create() - tr.insert(144, tableFooter) + tr.insert(163, tableFooter) const generalTableFootnote = manuscriptSchema.nodes.general_table_footnote.create({}, [ manuscriptSchema.nodes.paragraph.create(), ]) - tr.insert(145, generalTableFootnote) + tr.insert(164, generalTableFootnote) dispatch(tr) }) - expect(tester.view.state.doc.nodeAt(144)?.type.name).toBe( + expect(tester.view.state.doc.nodeAt(163)?.type.name).toBe( manuscriptSchema.nodes.table_element_footer.name ) - expect(tester.view.state.doc.nodeAt(145)?.type.name).toBe( + expect(tester.view.state.doc.nodeAt(164)?.type.name).toBe( manuscriptSchema.nodes.general_table_footnote.name ) expect(log.warn).toHaveBeenCalledTimes(0) diff --git a/test/replace-around-steps/replace-around-steps.test.ts b/test/replace-around-steps/replace-around-steps.test.ts index 58b2d893..d5cc4e63 100644 --- a/test/replace-around-steps/replace-around-steps.test.ts +++ b/test/replace-around-steps/replace-around-steps.test.ts @@ -16,7 +16,7 @@ /// ; import { promises as fs } from 'fs' import { Fragment, Slice } from 'prosemirror-model' -import { liftTarget } from 'prosemirror-transform' +import { liftTarget, ReplaceAroundStep } from 'prosemirror-transform' import { CHANGE_STATUS, ChangeSet, trackChangesPluginKey, trackCommands } from '../../src' import { log } from '../../src/utils/logger' @@ -24,6 +24,7 @@ import docs from '../__fixtures__/docs' import { schema } from '../utils/schema' import { setupEditor } from '../utils/setupEditor' import replaceAroundSteps from './replace-around-steps.json' +import { schema as manuscriptSchema } from '@manuscripts/transform' let counter = 0 // https://stackoverflow.com/questions/65554910/jest-referenceerror-cannot-access-before-initialization @@ -48,6 +49,92 @@ describe('replace-around-steps.test', () => { jest.clearAllMocks() }) + test.skip('should track join of paragraph to the nested blockquote', async () => { + setupEditor({ + doc: docs.nestedBlockquotes, + }) + .selectText(12, 14) + .cmd((state, dispatch) => { + const { tr, schema } = state + const slice = new Slice(Fragment.from(schema.nodes.blockquote.create()), 1, 0) + const step = new ReplaceAroundStep(48, 64, 49, 64, slice, 0, true) + dispatch(tr.step(step)) + }) + }) + + test.skip('should track inserted content of merged slice', async () => { + setupEditor({ + doc: docs.nestedBlockquotes, + }) + .selectText(47) + .cmd((state, dispatch) => { + const { tr } = state + const slice = new Slice( + Fragment.from([ + schema.nodes.blockquote.create(undefined, [ + schema.nodes.paragraph.create(undefined, schema.text('merged text')), + schema.nodes.blockquote.create( + undefined, + schema.nodes.paragraph.create(undefined, schema.text('remaining content')) + ), + ]), + ]), + 2, + 0 + ) + const step = new ReplaceAroundStep(47, 49, 47, 47, slice, 31) + dispatch(tr.step(step)) + }) + }) + + test.skip('should track merged content within a shrunk slice', async () => { + setupEditor({ + doc: docs.nestedBlockquotes, + }) + .selectText(44) + .cmd((state, dispatch) => { + const { tr } = state + const slice = new Slice( + Fragment.from([ + schema.nodes.blockquote.create(undefined, [ + schema.nodes.paragraph.create(undefined, schema.text('merged text')), + schema.nodes.blockquote.create( + undefined, + schema.nodes.paragraph.create(undefined, schema.text('remaining:')) + ), + ]), + ]), + 2, + 0 + ) + const step = new ReplaceAroundStep(44, 49, 44, 47, slice, 24) + dispatch(tr.step(step)) + }) + }) + + test.skip('should track split of block nodes from uneven open slice ends', async () => { + setupEditor({ + doc: docs.manuscriptSimple[0], + schema: manuscriptSchema, + }) + .selectText(29) + .cmd((state, dispatch) => { + const { tr, schema } = state + const slice = new Slice( + Fragment.from([ + schema.nodes.paragraph.create(undefined, schema.text('merged text')), + schema.nodes.section.create(undefined, [ + schema.nodes.section_title.create(), + schema.nodes.paragraph.create(undefined, schema.text('remaining:')), + ]), + ]), + 1, + 2 + ) + dispatch(tr.replaceSelection(slice)) + }) + }) + test('should track basic wrapping and unwrapping of blockquotes', async () => { const tester = setupEditor({ doc: docs.nestedBlockquotes, @@ -66,16 +153,6 @@ describe('replace-around-steps.test', () => { // .backspace(4) // Unwrap the innermost blockquote which should set it deleted but leave the content intact .liftnode(17) - // This simulates pressing backspace inside 4th paragraph which should try to lift it inside the blockquote - // .cmd((state, dispatch) => { - // const { tr, schema } = state - // const bq = schema.nodes.blockquote.create() - // // Or, more challenging? - // // const bq = schema.nodes.blockquote.create(undefined, schema.nodes.paragraph.create()) - // const slice = new Slice(Fragment.from(bq), 1, 0) - // const step = new ReplaceAroundStep(48, 64, 49, 64, slice, 0, true) - // dispatch(tr.step(step)) - // }) // Wrap the 4th paragraph in a blockquote and see whether track-changes-plugin correctly handles the positions // when adjacent to blockquote above and end of doc at the bottom .selectText(50) @@ -116,10 +193,9 @@ describe('replace-around-steps.test', () => { setupEditor({ doc: docs.list, }) - .selectText(26, 37) .cmd((state, dispatch) => { const { tr } = state - state.doc.nodesBetween(22, 22 + (state.doc.nodeAt(22)?.nodeSize || 0), (node, pos) => { + state.doc.nodesBetween(0, state.doc.nodeAt(22)?.nodeSize || 0, (node, pos) => { const $fromPos = tr.doc.resolve(tr.mapping.map(pos)) const $toPos = tr.doc.resolve(tr.mapping.map(pos + node.nodeSize - 1)) const nodeRange = $fromPos.blockRange($toPos)