UseJunior Book a Demo

safe-docx · Accept Tracked Changes

Property change acceptance by removal of change records

When accepting tracked formatting changes in a WordprocessingML document, property-change records mark prior formatting state rather than live text content. Removing those records prevents accepted output from retaining revision metadata that no longer describes an unresolved change.

acceptChanges mutates the document DOM and returns a summary of the tracked-change categories it resolved. For property changes, the function removes each supported *PrChange element and counts the removed records in propertyChangesResolved.[1]

Below is a test scenario of the baseline successful case of acceptChanges: accept property changes by removing change records.

The scenario

Given a document with a run property change record,
When property changes are accepted,
Then

  • one property change is resolved
  • rPrChange elements are removed
  • stable text is preserved.

The Test Fixture

The fixture builds a minimal document body with one run property change record and live text in the same run. The helper wraps that body in a WordprocessingML document, calls acceptChanges, serializes the mutated document, and returns both the XML and the summary.[2]

Below is the test fixture code.

humanReadableTest.openspec('accept property changes by removing change records')(
  'accept property changes by removing change records',
  async ({ given, when, then, and, attachPrettyJson }: AllureBddContext) => {
    const input = [
      '<w:p>',
      '<w:r>',
      '<w:rPr><w:rPrChange w:id="1" w:author="test"/></w:rPr>',
      '<w:t>Stable text</w:t>',
      '</w:r>',
      '</w:p>',
    ].join('');

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

    await given('a document with a run property change record', async () => {});

    await when('property changes are accepted', async () => {
      result = runAcceptChanges(input);
      await attachPrettyJson('accept-property-changes-result', result);
    });

    await then('one property change is resolved', async () => {
      expect(result.summary.propertyChangesResolved).toBe(1);
    });

    await and('rPrChange elements are removed', async () => {
      expect(result.xml.includes('rPrChange')).toBe(false);
    });

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

The Expected Outcome

The scenario asserts both the summary counter and the serialized document content after mutation. The counter records that one property-change element was removed, while the serialized XML checks verify that the change record is gone and the text node remains.

Below is the result that acceptChanges is expected to return for this scenario.

expect(result.summary.propertyChangesResolved).toBe(1);
expect(result.xml.includes('rPrChange')).toBe(false);
expect(result.xml.includes('Stable text')).toBe(true);

Below is a description of the expected fields:

A Non-Obvious Detail

The property-change record is represented by w:rPrChange, which uses the CT_TrackChange schema shape for revision metadata. The scenario checks removal of that metadata record, not a rewrite of the live w:rPr formatting container or the text run that follows it.[3]