Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit 10f5d83

Browse files
authored
Merge pull request #221 from ghiscoding/feat/extension-unit-tests
feat(tests): add all Extensions full test suite coverage
2 parents 92ae929 + 2774b88 commit 10f5d83

11 files changed

+844
-92
lines changed

src/app/modules/angular-slickgrid/extensions/__tests__/cellExternalCopyManagerExtension.spec.ts

Lines changed: 191 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import { GridOption } from '../../models/gridOption.interface';
44
import { CellExternalCopyManagerExtension } from '../cellExternalCopyManagerExtension';
55
import { ExtensionUtility } from '../extensionUtility';
66
import { SharedService } from '../../services/shared.service';
7-
import { SelectedRange } from '../../models';
7+
import { EditCommand, Formatter, SelectedRange } from '../../models';
8+
import { Formatters } from '../../formatters';
89

910
declare var Slick: any;
1011

1112
const gridStub = {
13+
getData: jest.fn(),
1214
getOptions: jest.fn(),
1315
registerPlugin: jest.fn(),
1416
setSelectionModel: jest.fn(),
@@ -21,6 +23,7 @@ const addonStub = {
2123
onCopyCancelled: new Slick.Event(),
2224
onPasteCells: new Slick.Event(),
2325
};
26+
2427
const mockAddon = jest.fn().mockImplementation(() => addonStub);
2528
const mockSelectionModel = jest.fn().mockImplementation(() => ({
2629
init: jest.fn(),
@@ -34,6 +37,7 @@ jest.mock('slickgrid/plugins/slick.cellselectionmodel', () => mockSelectionModel
3437
Slick.CellSelectionModel = mockSelectionModel;
3538

3639
describe('cellExternalCopyManagerExtension', () => {
40+
let queueCallback: EditCommand;
3741
let translate: TranslateService;
3842
const mockEventCallback = (e, args: { ranges: SelectedRange[] }) => { };
3943
const mockSelectRange = [{ fromCell: 1, fromRow: 1, toCell: 1, toRow: 1 }] as SelectedRange[];
@@ -72,6 +76,15 @@ describe('cellExternalCopyManagerExtension', () => {
7276
beforeEach(() => {
7377
jest.spyOn(SharedService.prototype, 'grid', 'get').mockReturnValue(gridStub);
7478
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(gridOptionsMock);
79+
queueCallback = {
80+
execute: () => { },
81+
undo: () => { },
82+
row: 0,
83+
cell: 0,
84+
editor: {},
85+
serializedValue: 'serialize',
86+
prevSerializedValue: 'previous'
87+
};
7588
});
7689

7790
it('should register the addon', () => {
@@ -162,4 +175,181 @@ describe('cellExternalCopyManagerExtension', () => {
162175
expect(destroySpy).toHaveBeenCalled();
163176
});
164177
});
178+
179+
describe('createUndoRedo private method', () => {
180+
it('should create the UndoRedoBuffer', () => {
181+
extension.register();
182+
183+
expect(extension.undoRedoBuffer).toEqual({
184+
queueAndExecuteCommand: expect.anything(),
185+
undo: expect.anything(),
186+
redo: expect.anything(),
187+
});
188+
});
189+
190+
it('should have called Edit Command "execute" method after creating the UndoRedoBuffer', () => {
191+
extension.register();
192+
const undoRedoBuffer = extension.undoRedoBuffer;
193+
194+
const spy = jest.spyOn(queueCallback, 'execute');
195+
undoRedoBuffer.queueAndExecuteCommand(queueCallback);
196+
197+
expect(spy).toHaveBeenCalled();
198+
});
199+
200+
it('should not have called Edit Command "undo" method when there is nothing to undo', () => {
201+
extension.register();
202+
const undoRedoBuffer = extension.undoRedoBuffer;
203+
204+
const spy = jest.spyOn(queueCallback, 'undo');
205+
undoRedoBuffer.undo();
206+
207+
expect(spy).not.toHaveBeenCalled();
208+
});
209+
210+
it('should have called Edit Command "undo" method after calling it from UndoRedoBuffer', () => {
211+
extension.register();
212+
const undoRedoBuffer = extension.undoRedoBuffer;
213+
214+
const spy = jest.spyOn(queueCallback, 'undo');
215+
undoRedoBuffer.queueAndExecuteCommand(queueCallback);
216+
undoRedoBuffer.undo();
217+
218+
expect(spy).toHaveBeenCalled();
219+
});
220+
221+
it('should have called Edit Command "execute" method only at first queueing, the "redo" should not call the "execute" method by itself', () => {
222+
extension.register();
223+
const undoRedoBuffer = extension.undoRedoBuffer;
224+
225+
const spy = jest.spyOn(queueCallback, 'execute');
226+
undoRedoBuffer.queueAndExecuteCommand(queueCallback);
227+
undoRedoBuffer.redo();
228+
229+
expect(spy).toHaveBeenCalledTimes(1);
230+
});
231+
232+
it('should have called Edit Command "execute" method at first queueing & then inside the "redo" since we did an "undo" just before', () => {
233+
extension.register();
234+
const undoRedoBuffer = extension.undoRedoBuffer;
235+
236+
const spy = jest.spyOn(queueCallback, 'execute');
237+
undoRedoBuffer.queueAndExecuteCommand(queueCallback);
238+
undoRedoBuffer.undo();
239+
undoRedoBuffer.redo();
240+
241+
expect(spy).toHaveBeenCalledTimes(2);
242+
});
243+
244+
it('should have a single entry in the queue buffer after calling "queueAndExecuteCommand" once', () => {
245+
extension.register();
246+
extension.undoRedoBuffer.queueAndExecuteCommand(queueCallback);
247+
expect(extension.commandQueue).toHaveLength(1);
248+
});
249+
250+
it('should call a redo when Ctrl+Shift+Z keyboard event occurs', () => {
251+
extension.register();
252+
const spy = jest.spyOn(queueCallback, 'execute');
253+
254+
extension.undoRedoBuffer.queueAndExecuteCommand(queueCallback);
255+
const body = window.document.body;
256+
body.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', {
257+
keyCode: 90,
258+
ctrlKey: true,
259+
shiftKey: true,
260+
bubbles: true,
261+
cancelable: true
262+
}));
263+
264+
expect(spy).toHaveBeenCalledTimes(2);
265+
});
266+
267+
it('should call a undo when Ctrl+Z keyboard event occurs', () => {
268+
extension.register();
269+
const spy = jest.spyOn(queueCallback, 'undo');
270+
271+
extension.undoRedoBuffer.queueAndExecuteCommand(queueCallback);
272+
const body = window.document.body;
273+
body.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', {
274+
keyCode: 90,
275+
ctrlKey: true,
276+
shiftKey: false,
277+
bubbles: true
278+
}));
279+
280+
expect(spy).toHaveBeenCalled();
281+
});
282+
});
283+
284+
describe('addonOptions callbacks', () => {
285+
it('should expect "queueAndExecuteCommand" to be called after calling "clipboardCommandHandler" callback', () => {
286+
extension.register();
287+
const spy = jest.spyOn(extension.undoRedoBuffer, 'queueAndExecuteCommand');
288+
289+
extension.addonOptions.clipboardCommandHandler(queueCallback);
290+
291+
expect(spy).toHaveBeenCalled();
292+
});
293+
294+
it('should expect "addItem" method to be called after calling "newRowCreator" callback', () => {
295+
extension.register();
296+
const mockGetData = { addItem: jest.fn() };
297+
const getDataSpy = jest.spyOn(gridStub, 'getData').mockReturnValue(mockGetData);
298+
const addItemSpy = jest.spyOn(mockGetData, 'addItem');
299+
300+
extension.addonOptions.newRowCreator(2);
301+
302+
expect(getDataSpy).toHaveBeenCalled();
303+
expect(addItemSpy).toHaveBeenCalledWith(expect.objectContaining({ id: 'newRow_0' }));
304+
expect(addItemSpy).toHaveBeenCalledWith(expect.objectContaining({ id: 'newRow_1' }));
305+
});
306+
307+
it('should expect a formatted output after calling "dataItemColumnValueExtractor" callback', () => {
308+
extension.register();
309+
const output = extension.addonOptions.dataItemColumnValueExtractor({ firstName: 'John', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, formatter: Formatters.bold });
310+
expect(output).toBe('<b>John</b>');
311+
});
312+
313+
it('should expect a sanitized formatted and empty output after calling "dataItemColumnValueExtractor" callback', () => {
314+
gridOptionsMock.exportOptions = { sanitizeDataExport: true };
315+
const myBoldFormatter: Formatter = (row, cell, value, columnDef, dataContext) => value ? { text: `<b>${value}</b>` } : null;
316+
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(gridOptionsMock);
317+
extension.register();
318+
319+
const output = extension.addonOptions.dataItemColumnValueExtractor({ firstName: '<b>John</b>', lastName: null }, { id: 'lastName', field: 'lastName', exportWithFormatter: true, formatter: myBoldFormatter });
320+
321+
expect(output).toBe('');
322+
});
323+
324+
it('should expect a sanitized formatted output after calling "dataItemColumnValueExtractor" callback', () => {
325+
gridOptionsMock.exportOptions = { sanitizeDataExport: true };
326+
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(gridOptionsMock);
327+
extension.register();
328+
329+
const output = extension.addonOptions.dataItemColumnValueExtractor({ firstName: '<b>John</b>', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, formatter: Formatters.bold });
330+
331+
expect(output).toBe('John');
332+
});
333+
334+
it('should expect a sanitized formatted output, from a Custom Formatter, after calling "dataItemColumnValueExtractor" callback', () => {
335+
const myBoldFormatter: Formatter = (row, cell, value, columnDef, dataContext) => value ? { text: `<b>${value}</b>` } : '';
336+
gridOptionsMock.exportOptions = { sanitizeDataExport: true };
337+
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(gridOptionsMock);
338+
extension.register();
339+
340+
const output = extension.addonOptions.dataItemColumnValueExtractor({ firstName: '<b>John</b>', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, formatter: myBoldFormatter });
341+
342+
expect(output).toBe('John');
343+
});
344+
345+
it('should return null when calling "dataItemColumnValueExtractor" callback without editable', () => {
346+
gridOptionsMock.editable = false;
347+
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(gridOptionsMock);
348+
extension.register();
349+
350+
const output = extension.addonOptions.dataItemColumnValueExtractor({ firstName: '<b>John</b>', lastName: 'Doe' }, { id: 'firstName', field: 'firstName' });
351+
352+
expect(output).toBeNull();
353+
});
354+
});
165355
});

src/app/modules/angular-slickgrid/extensions/__tests__/headerMenuExtension.spec.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@ import { HeaderMenuExtension } from '../headerMenuExtension';
55
import { ExtensionUtility } from '../extensionUtility';
66
import { SharedService } from '../../services/shared.service';
77
import { Column, ColumnSort } from '../../models';
8-
import { ExportService, FilterService, SortService } from '../../services';
8+
import { FilterService, SortService } from '../../services';
99

1010
declare var Slick: any;
1111

12-
const exportServiceStub = {
13-
exportToFile: jest.fn(),
14-
} as unknown as ExportService;
15-
1612
const filterServiceStub = {
1713
clearFilterByColumnId: jest.fn(),
1814
} as unknown as FilterService;
@@ -95,7 +91,6 @@ describe('headerMenuExtension', () => {
9591
HeaderMenuExtension,
9692
ExtensionUtility,
9793
SharedService,
98-
{ provide: ExportService, useValue: exportServiceStub },
9994
{ provide: FilterService, useValue: filterServiceStub },
10095
{ provide: SortService, useValue: sortServiceStub },
10196
],

0 commit comments

Comments
 (0)