UseJunior Book a Demo

safe-docx · Accept Tracked Changes

Insertion acceptance by unwrapping w:ins wrappers

To accept inserted content in a WordprocessingML paragraph, the revision wrapper (i.e., the <w:ins> element that marks inserted content) must be removed without deleting the run element (i.e., the <w:r> element that holds run-level content). The inserted content remains part of the document because accepting an insertion changes the revision state, not the authored words inside the wrapper.

acceptChanges applies that operation by unwrapping insertion wrappers and counting each accepted insertion in its summary result.[1] The wrapper removal is paired with content preservation because the function moves the wrapper's children into the surrounding document tree instead of removing the entire insertion subtree.

Below is a test scenario of the baseline successful case of acceptChanges: accepting one inserted text run by unwrapping its w:ins wrapper.

The scenario

Given a document with an inserted text run,
When insertions are accepted and wrappers unwrapped,
Then

  • one insertion is accepted.
  • w:ins wrappers are removed.
  • the inserted text is preserved.

The Fixture

The scenario uses a paragraph whose only content is an insertion wrapper around a single run. Below is the test fixture code.

  humanReadableTest.openspec('accept insertions by unwrapping w:ins wrappers')(
    'accept insertions by unwrapping w:ins wrappers',
    async ({ given, when, then, and, attachPrettyJson }: AllureBddContext) => {
      const input = '<w:p><w:ins><w:r><w:t>Inserted text</w:t></w:r></w:ins></w:p>';

      let result: { xml: string; summary: ReturnType<typeof acceptChanges> };

      await given('a document with an inserted text run', async () => {});

      await when('insertions are accepted and wrappers unwrapped', async () => {
        result = runAcceptChanges(input);
        await attachPrettyJson('accept-insertions-result', result);
      });

      await then('one insertion is accepted', async () => {
        expect(result.summary.insertionsAccepted).toBe(1);
      });

      await and('w:ins wrappers are removed', async () => {
        expect(result.xml.includes('<w:ins')).toBe(false);
      });

      await and('the inserted text is preserved', async () => {
        expect(result.xml.includes('Inserted text')).toBe(true);
      });
    },
  );

The Expected Result Shape

The scenario asserts both the summary count returned by acceptChanges and the serialized XML produced after the document has been rewritten.[2] Below is the result that acceptChanges is expected to return for this scenario.

expect(result.summary.insertionsAccepted).toBe(1);
expect(result.xml.includes('<w:ins')).toBe(false);
expect(result.xml.includes('Inserted text')).toBe(true);

Below is a description of the expected fields:

Conformance

The w:ins element is a tracked-change wrapper in WordprocessingML, so accepting the insertion must leave valid paragraph content after the wrapper is gone.[3] In this scenario, the remaining paragraph contains a run element with text content, which is the document state the assertion checks through serialized XML.