@@ -18,16 +18,30 @@ const TEST_DOC = 'blank-doc.docx';
1818const CT_CUSTOM = 'application/vnd.openxmlformats-officedocument.custom-properties+xml' ;
1919const REL_CUSTOM = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties' ;
2020const WORD_STAT_TEXT = 'Alpha beta gamma' ;
21+ const PARENT_WORD_STAT_TEXT = 'Alpha beta gamma delta' ;
22+ const CHILD_ONLY_TEXT = 'Header words only' ;
2123
2224function readXmlTagValue ( xml , tagName ) {
2325 const match = xml . match ( new RegExp ( `<${ tagName } >([^<]*)</${ tagName } >` ) ) ;
2426 return match ?. [ 1 ] ?? null ;
2527}
2628
29+ function readAppStatistics ( xml ) {
30+ return {
31+ words : readXmlTagValue ( xml , 'Words' ) ,
32+ characters : readXmlTagValue ( xml , 'Characters' ) ,
33+ charactersWithSpaces : readXmlTagValue ( xml , 'CharactersWithSpaces' ) ,
34+ } ;
35+ }
36+
37+ async function createHeadlessEditor ( testDoc = TEST_DOC ) {
38+ const { docx, media, mediaFiles, fonts } = await loadTestDataForEditorTests ( testDoc ) ;
39+ return initTestEditor ( { content : docx , media, mediaFiles, fonts, isHeadless : true } ) ;
40+ }
41+
2742describe ( 'OPC package metadata: custom-properties registration' , ( ) => {
2843 it ( 'getUpdatedDocs includes correct [Content_Types].xml and _rels/.rels for new custom.xml' , async ( ) => {
29- const { docx, media, mediaFiles, fonts } = await loadTestDataForEditorTests ( TEST_DOC ) ;
30- const { editor } = initTestEditor ( { content : docx , media, mediaFiles, fonts, isHeadless : true } ) ;
44+ const { editor } = await createHeadlessEditor ( ) ;
3145
3246 try {
3347 const updatedDocs = await editor . exportDocx ( { getUpdatedDocs : true } ) ;
@@ -54,8 +68,7 @@ describe('OPC package metadata: custom-properties registration', () => {
5468 } ) ;
5569
5670 it ( 'zipped export includes valid package metadata for new custom.xml' , async ( ) => {
57- const { docx, media, mediaFiles, fonts } = await loadTestDataForEditorTests ( TEST_DOC ) ;
58- const { editor } = initTestEditor ( { content : docx , media, mediaFiles, fonts, isHeadless : true } ) ;
71+ const { editor } = await createHeadlessEditor ( ) ;
5972
6073 try {
6174 const exportedBuffer = await editor . exportDocx ( { compression : 'STORE' } ) ;
@@ -92,8 +105,7 @@ describe('OPC package metadata: custom-properties registration', () => {
92105 } ) ;
93106
94107 it ( 'preserves existing managed registrations without duplication' , async ( ) => {
95- const { docx, media, mediaFiles, fonts } = await loadTestDataForEditorTests ( TEST_DOC ) ;
96- const { editor } = initTestEditor ( { content : docx , media, mediaFiles, fonts, isHeadless : true } ) ;
108+ const { editor } = await createHeadlessEditor ( ) ;
97109
98110 try {
99111 const updatedDocs = await editor . exportDocx ( { getUpdatedDocs : true } ) ;
@@ -130,8 +142,7 @@ describe('OPC package metadata: custom-properties registration', () => {
130142 } ) ;
131143
132144 it ( 'getUpdatedDocs includes refreshed docProps/app.xml statistics' , async ( ) => {
133- const { docx, media, mediaFiles, fonts } = await loadTestDataForEditorTests ( TEST_DOC ) ;
134- const { editor } = initTestEditor ( { content : docx , media, mediaFiles, fonts, isHeadless : true } ) ;
145+ const { editor } = await createHeadlessEditor ( ) ;
135146
136147 try {
137148 editor . commands . insertContent ( WORD_STAT_TEXT ) ;
@@ -140,10 +151,40 @@ describe('OPC package metadata: custom-properties registration', () => {
140151 const appXml = updatedDocs [ 'docProps/app.xml' ] ;
141152
142153 expect ( appXml ) . toBeTruthy ( ) ;
143- expect ( readXmlTagValue ( appXml , 'Words' ) ) . toBe ( '3' ) ;
144- expect ( readXmlTagValue ( appXml , 'Characters' ) ) . toBe ( '14' ) ;
145- expect ( readXmlTagValue ( appXml , 'CharactersWithSpaces' ) ) . toBe ( '16' ) ;
154+ expect ( readAppStatistics ( appXml ) ) . toEqual ( {
155+ words : '3' ,
156+ characters : '14' ,
157+ charactersWithSpaces : '16' ,
158+ } ) ;
159+ } finally {
160+ editor . destroy ( ) ;
161+ }
162+ } ) ;
163+
164+ it ( 'linked child exports keep docProps/app.xml statistics scoped to the main document' , async ( ) => {
165+ const { editor } = await createHeadlessEditor ( ) ;
166+ let childEditor = null ;
167+
168+ try {
169+ editor . commands . insertContent ( PARENT_WORD_STAT_TEXT ) ;
170+
171+ childEditor = editor . createChildEditor ( {
172+ isHeadless : true ,
173+ isHeaderOrFooter : true ,
174+ } ) ;
175+ childEditor . commands . insertContent ( CHILD_ONLY_TEXT ) ;
176+
177+ const updatedDocs = await childEditor . exportDocx ( { getUpdatedDocs : true } ) ;
178+ const appXml = updatedDocs [ 'docProps/app.xml' ] ;
179+
180+ expect ( appXml ) . toBeTruthy ( ) ;
181+ expect ( readAppStatistics ( appXml ) ) . toEqual ( {
182+ words : '4' ,
183+ characters : '19' ,
184+ charactersWithSpaces : '22' ,
185+ } ) ;
146186 } finally {
187+ childEditor ?. destroy ( ) ;
147188 editor . destroy ( ) ;
148189 }
149190 } ) ;
0 commit comments