From 9943d1214debdd7e398eb92619e73ee010061f70 Mon Sep 17 00:00:00 2001 From: "Jiuqing Song (from Dev Box)" Date: Thu, 21 Nov 2024 10:07:45 -0800 Subject: [PATCH] add test --- .../formatContentModelTest.ts | 98 +++++++- .../corePlugin/format/FormatPluginTest.ts | 15 +- .../format/applyPendingFormatTest.ts | 219 ++++++++++++++++++ 3 files changed, 327 insertions(+), 5 deletions(-) diff --git a/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts b/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts index 10729d754dd..8109dea5a2b 100644 --- a/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts +++ b/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts @@ -658,6 +658,7 @@ describe('formatContentModel', () => { it('Has pending format, callback returns true, preserve pending format', () => { core.format.pendingFormat = { format: mockedFormat1, + paragraphFormat: mockedFormat2, insertPoint: { node: mockedStartContainer1, offset: mockedStartOffset1, @@ -679,9 +680,61 @@ describe('formatContentModel', () => { } as any); }); - it('Has pending format, callback returns false, preserve pending format', () => { + it('Has pending format, callback returns true, preserve paragraph pending format', () => { core.format.pendingFormat = { format: mockedFormat1, + paragraphFormat: mockedFormat2, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, + }; + + formatContentModel(core, (model, context) => { + context.newPendingParagraphFormat = 'preserve'; + return true; + }); + + expect(core.format.pendingFormat).toEqual({ + format: undefined, + paragraphFormat: mockedFormat2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, + } as any); + }); + + it('Has pending format, callback returns true, preserve both pending format', () => { + core.format.pendingFormat = { + format: mockedFormat1, + paragraphFormat: mockedFormat2, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, + }; + + formatContentModel(core, (model, context) => { + context.newPendingFormat = 'preserve'; + context.newPendingParagraphFormat = 'preserve'; + return true; + }); + + expect(core.format.pendingFormat).toEqual({ + format: mockedFormat1, + paragraphFormat: mockedFormat2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, + } as any); + }); + + it('Has pending format, callback returns false, preserve both pending format', () => { + core.format.pendingFormat = { + format: mockedFormat1, + paragraphFormat: mockedFormat2, insertPoint: { node: mockedStartContainer1, offset: mockedStartOffset1, @@ -690,12 +743,13 @@ describe('formatContentModel', () => { formatContentModel(core, (model, context) => { context.newPendingFormat = 'preserve'; + context.newPendingParagraphFormat = 'preserve'; return false; }); expect(core.format.pendingFormat).toEqual({ format: mockedFormat1, - paragraphFormat: undefined, + paragraphFormat: mockedFormat2, insertPoint: { node: mockedStartContainer2, offset: mockedStartOffset2, @@ -719,6 +773,22 @@ describe('formatContentModel', () => { }); }); + it('No pending format, callback returns true, new paragraph format', () => { + formatContentModel(core, (model, context) => { + context.newPendingParagraphFormat = mockedFormat2; + return true; + }); + + expect(core.format.pendingFormat).toEqual({ + format: undefined, + paragraphFormat: mockedFormat2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, + }); + }); + it('No pending format, callback returns false, new format', () => { formatContentModel(core, (model, context) => { context.newPendingFormat = mockedFormat2; @@ -783,6 +853,30 @@ describe('formatContentModel', () => { }); }); + it('Has pending format, callback returns false, new paragraph format', () => { + core.format.pendingFormat = { + paragraphFormat: mockedFormat1, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, + }; + + formatContentModel(core, (model, context) => { + context.newPendingParagraphFormat = mockedFormat2; + return false; + }); + + expect(core.format.pendingFormat).toEqual({ + format: undefined, + paragraphFormat: mockedFormat2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, + }); + }); + it('Has pending format, callback returns false, preserve format, selection is not collapsed', () => { core.format.pendingFormat = { format: mockedFormat1, diff --git a/packages/roosterjs-content-model-core/test/corePlugin/format/FormatPluginTest.ts b/packages/roosterjs-content-model-core/test/corePlugin/format/FormatPluginTest.ts index c1111dbcc76..e278325c4cf 100644 --- a/packages/roosterjs-content-model-core/test/corePlugin/format/FormatPluginTest.ts +++ b/packages/roosterjs-content-model-core/test/corePlugin/format/FormatPluginTest.ts @@ -8,6 +8,9 @@ describe('FormatPlugin', () => { const mockedFormat = { fontSize: '10px', }; + const mockedFormat2 = { + lineSpace: 2, + }; let applyPendingFormatSpy: jasmine.Spy; beforeEach(() => { @@ -49,6 +52,7 @@ describe('FormatPlugin', () => { (state.pendingFormat = { format: mockedFormat, + paragraphFormat: mockedFormat2, } as any), plugin.initialize(editor); @@ -60,7 +64,12 @@ describe('FormatPlugin', () => { plugin.dispose(); expect(applyPendingFormatSpy).toHaveBeenCalledTimes(1); - expect(applyPendingFormatSpy).toHaveBeenCalledWith(editor, 'a', mockedFormat, undefined); + expect(applyPendingFormatSpy).toHaveBeenCalledWith( + editor, + 'a', + mockedFormat, + mockedFormat2 + ); expect(state.pendingFormat).toBeNull(); }); @@ -111,7 +120,7 @@ describe('FormatPlugin', () => { const state = plugin.getState(); state.pendingFormat = { - format: mockedFormat, + paragraphFormat: mockedFormat2, } as any; plugin.onPluginEvent({ @@ -122,7 +131,7 @@ describe('FormatPlugin', () => { expect(applyPendingFormatSpy).not.toHaveBeenCalled(); expect(state.pendingFormat).toEqual({ - format: mockedFormat, + paragraphFormat: mockedFormat2, } as any); }); diff --git a/packages/roosterjs-content-model-core/test/corePlugin/format/applyPendingFormatTest.ts b/packages/roosterjs-content-model-core/test/corePlugin/format/applyPendingFormatTest.ts index 9b2ed118a8c..be044ad6e32 100644 --- a/packages/roosterjs-content-model-core/test/corePlugin/format/applyPendingFormatTest.ts +++ b/packages/roosterjs-content-model-core/test/corePlugin/format/applyPendingFormatTest.ts @@ -94,6 +94,225 @@ describe('applyPendingFormat', () => { }); }); + it('Has pending paragraph format', () => { + const text: ContentModelText = { + segmentType: 'Text', + text: 'abc', + format: {}, + }; + const marker: ContentModelSelectionMarker = { + segmentType: 'SelectionMarker', + isSelected: true, + format: {}, + }; + const paragraph: ContentModelParagraph = { + blockType: 'Paragraph', + segments: [text, marker], + format: { textAlign: 'start', textIndent: '10pt' }, + }; + const model: ContentModelDocument = { + blockGroupType: 'Document', + blocks: [paragraph], + }; + + const formatContentModelSpy = jasmine + .createSpy('formatContentModel') + .and.callFake((callback: ContentModelFormatter, options: FormatContentModelOptions) => { + expect(options.apiName).toEqual('applyPendingFormat'); + callback(model, { + newEntities: [], + deletedEntities: [], + newImages: [], + }); + }); + + const editor = ({ + formatContentModel: formatContentModelSpy, + } as any) as IEditor; + + spyOn(iterateSelections, 'iterateSelections').and.callFake((_, callback) => { + callback([model], undefined, paragraph, [marker]); + return false; + }); + + applyPendingFormat(editor, 'c', undefined, { + textIndent: '20pt', + lineHeight: '2', + }); + + expect(formatContentModelSpy).toHaveBeenCalledTimes(1); + expect(model).toEqual({ + blockGroupType: 'Document', + blocks: [ + { + blockType: 'Paragraph', + format: { textAlign: 'start', textIndent: '20pt', lineHeight: '2' }, + segments: [ + { + segmentType: 'Text', + text: 'abc', + format: {}, + }, + { + segmentType: 'SelectionMarker', + format: {}, + isSelected: true, + }, + ], + }, + ], + }); + }); + + it('Has pending both format', () => { + const text: ContentModelText = { + segmentType: 'Text', + text: 'abc', + format: {}, + }; + const marker: ContentModelSelectionMarker = { + segmentType: 'SelectionMarker', + isSelected: true, + format: {}, + }; + const paragraph: ContentModelParagraph = { + blockType: 'Paragraph', + segments: [text, marker], + format: { textAlign: 'start', textIndent: '10pt' }, + }; + const model: ContentModelDocument = { + blockGroupType: 'Document', + blocks: [paragraph], + }; + + const formatContentModelSpy = jasmine + .createSpy('formatContentModel') + .and.callFake((callback: ContentModelFormatter, options: FormatContentModelOptions) => { + expect(options.apiName).toEqual('applyPendingFormat'); + callback(model, { + newEntities: [], + deletedEntities: [], + newImages: [], + }); + }); + + const editor = ({ + formatContentModel: formatContentModelSpy, + } as any) as IEditor; + + spyOn(iterateSelections, 'iterateSelections').and.callFake((_, callback) => { + callback([model], undefined, paragraph, [marker]); + return false; + }); + + applyPendingFormat( + editor, + 'c', + { fontSize: '10px' }, + { + textIndent: '20pt', + lineHeight: '2', + } + ); + + expect(formatContentModelSpy).toHaveBeenCalledTimes(1); + expect(model).toEqual({ + blockGroupType: 'Document', + blocks: [ + { + blockType: 'Paragraph', + format: { textAlign: 'start', textIndent: '20pt', lineHeight: '2' }, + segments: [ + { + segmentType: 'Text', + text: 'ab', + format: {}, + }, + { + segmentType: 'Text', + text: 'c', + format: { + fontSize: '10px', + }, + }, + { + segmentType: 'SelectionMarker', + format: { fontSize: '10px' }, + isSelected: true, + }, + ], + }, + ], + }); + }); + + it('Has no pending format', () => { + const text: ContentModelText = { + segmentType: 'Text', + text: 'abc', + format: {}, + }; + const marker: ContentModelSelectionMarker = { + segmentType: 'SelectionMarker', + isSelected: true, + format: {}, + }; + const paragraph: ContentModelParagraph = { + blockType: 'Paragraph', + segments: [text, marker], + format: {}, + }; + const model: ContentModelDocument = { + blockGroupType: 'Document', + blocks: [paragraph], + }; + + const formatContentModelSpy = jasmine + .createSpy('formatContentModel') + .and.callFake((callback: ContentModelFormatter, options: FormatContentModelOptions) => { + expect(options.apiName).toEqual('applyPendingFormat'); + callback(model, { + newEntities: [], + deletedEntities: [], + newImages: [], + }); + }); + + const editor = ({ + formatContentModel: formatContentModelSpy, + } as any) as IEditor; + + spyOn(iterateSelections, 'iterateSelections').and.callFake((_, callback) => { + callback([model], undefined, paragraph, [marker]); + return false; + }); + + applyPendingFormat(editor, 'c'); + + expect(formatContentModelSpy).toHaveBeenCalledTimes(1); + expect(model).toEqual({ + blockGroupType: 'Document', + blocks: [ + { + blockType: 'Paragraph', + format: {}, + segments: [ + { + segmentType: 'Text', + text: 'abc', + format: {}, + }, + { + segmentType: 'SelectionMarker', + format: {}, + isSelected: true, + }, + ], + }, + ], + }); + }); + it('Has pending format but wrong text', () => { const text: ContentModelText = { segmentType: 'Text',