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

Commit 92ae929

Browse files
authored
Merge pull request #218 from ghiscoding/feat/extension-tests
feat(tests): add some RowDetail Extension tests
2 parents 54c1f09 + f93983f commit 92ae929

File tree

7 files changed

+540
-63
lines changed

7 files changed

+540
-63
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const mockAddon = jest.fn().mockImplementation(() => ({
2121
getColumnDefinition: jest.fn(),
2222
selectRows: jest.fn(),
2323
}));
24+
2425
const mockSelectionModel = jest.fn().mockImplementation(() => ({
2526
init: jest.fn(),
2627
destroy: jest.fn()

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ describe('draggableGroupingExtension', () => {
4545
translate = TestBed.get(TranslateService);
4646
});
4747

48-
it('should return null when either the grid object or the grid options is missing', () => {
48+
it('should return null after calling "create" method when the grid options is missing', () => {
49+
const output = extension.create(null);
50+
expect(output).toBeNull();
51+
});
52+
53+
it('should return null after calling "register" method when either the grid object or the grid options is missing', () => {
4954
const output = extension.register();
5055
expect(output).toBeNull();
5156
});

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
import { TestBed } from '@angular/core/testing';
22
import { TranslateService, TranslateModule } from '@ngx-translate/core';
33
import { GridOption } from '../../models/gridOption.interface';
4-
import { AutoTooltipExtension } from '../autoTooltipExtension';
54
import { ExtensionUtility } from '../extensionUtility';
65
import { SharedService } from '../../services/shared.service';
76
import { ExtensionName } from '../../models';
87

98
declare var Slick: any;
109

11-
const gridStub = {
12-
getOptions: jest.fn(),
13-
registerPlugin: jest.fn(),
14-
};
15-
1610
const mockAddon = jest.fn().mockImplementation(() => ({
1711
init: jest.fn(),
1812
destroy: jest.fn()

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

Lines changed: 473 additions & 0 deletions
Large diffs are not rendered by default.

src/app/modules/angular-slickgrid/extensions/draggableGroupingExtension.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ export class DraggableGroupingExtension implements Extension {
3434
* For example the multi-select have to be added to the column definition before the grid is created to work properly
3535
*/
3636
create(gridOptions: GridOption) {
37-
// dynamically import the SlickGrid plugin (addon) with RequireJS
38-
this.extensionUtility.loadExtensionDynamically(ExtensionName.draggableGrouping);
37+
if (gridOptions) {
38+
// dynamically import the SlickGrid plugin (addon) with RequireJS
39+
this.extensionUtility.loadExtensionDynamically(ExtensionName.draggableGrouping);
3940

40-
if (!this._addon && gridOptions) {
41-
this._addon = new Slick.DraggableGrouping(gridOptions.draggableGrouping || {});
41+
if (!this._addon) {
42+
this._addon = new Slick.DraggableGrouping(gridOptions.draggableGrouping || {});
43+
}
44+
return this._addon;
4245
}
43-
return this._addon;
46+
return null;
4447
}
4548

4649
register(): any {

src/app/modules/angular-slickgrid/extensions/rowDetailViewExtension.ts

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ApplicationRef, ComponentRef, Injectable, Type, ViewContainerRef } from '@angular/core';
2-
import { Column, CurrentFilter, Extension, ExtensionName, GridOption } from '../models/index';
2+
import { Column, CurrentFilter, Extension, ExtensionName, GridOption, SlickEventHandler } from '../models/index';
33
import { ExtensionUtility } from './extensionUtility';
44
import { AngularUtilService } from '../services/angularUtilService';
55
import { FilterService } from '../services/filter.service';
@@ -24,8 +24,8 @@ export interface CreatedView {
2424
@Injectable()
2525
export class RowDetailViewExtension implements Extension {
2626
rowDetailContainer: ViewContainerRef;
27-
private _eventHandler: any = new Slick.EventHandler();
28-
private _extension: any;
27+
private _addon: any;
28+
private _eventHandler: SlickEventHandler;
2929
private _preloadComponent: Type<object>;
3030
private _views: CreatedView[] = [];
3131
private _viewComponent: Type<object>;
@@ -38,14 +38,20 @@ export class RowDetailViewExtension implements Extension {
3838
private extensionUtility: ExtensionUtility,
3939
private filterService: FilterService,
4040
private sharedService: SharedService,
41-
) { }
41+
) {
42+
this._eventHandler = new Slick.EventHandler();
43+
}
44+
45+
get eventHandler(): SlickEventHandler {
46+
return this._eventHandler;
47+
}
4248

4349
dispose() {
4450
// unsubscribe all SlickGrid events
4551
this._eventHandler.unsubscribeAll();
4652

47-
if (this._extension && this._extension.destroy) {
48-
this._extension.destroy();
53+
if (this._addon && this._addon.destroy) {
54+
this._addon.destroy();
4955
}
5056

5157
// also unsubscribe all RxJS subscriptions
@@ -67,7 +73,7 @@ export class RowDetailViewExtension implements Extension {
6773
}
6874

6975
if (gridOptions && gridOptions.rowDetailView) {
70-
if (!this._extension) {
76+
if (!this._addon) {
7177
if (typeof gridOptions.rowDetailView.process === 'function') {
7278
// we need to keep the user "process" method and replace it with our own execution method
7379
// we do this because when we get the item detail, we need to call "onAsyncResponse.notify" for the plugin to work
@@ -89,25 +95,27 @@ export class RowDetailViewExtension implements Extension {
8995
}
9096

9197
// finally register the Row Detail View Plugin
92-
this._extension = new Slick.Plugins.RowDetailView(gridOptions.rowDetailView);
98+
this._addon = new Slick.Plugins.RowDetailView(gridOptions.rowDetailView);
99+
}
100+
const selectionColumn: Column = this._addon.getColumnDefinition();
101+
if (typeof selectionColumn === 'object') {
102+
selectionColumn.excludeFromExport = true;
103+
selectionColumn.excludeFromColumnPicker = true;
104+
selectionColumn.excludeFromGridMenu = true;
105+
selectionColumn.excludeFromQuery = true;
106+
selectionColumn.excludeFromHeaderMenu = true;
107+
columnDefinitions.unshift(selectionColumn);
93108
}
94-
const selectionColumn: Column = this._extension.getColumnDefinition();
95-
selectionColumn.excludeFromExport = true;
96-
selectionColumn.excludeFromColumnPicker = true;
97-
selectionColumn.excludeFromGridMenu = true;
98-
selectionColumn.excludeFromQuery = true;
99-
selectionColumn.excludeFromHeaderMenu = true;
100-
columnDefinitions.unshift(selectionColumn);
101109
}
102-
return this._extension;
110+
return this._addon;
103111
}
104112
return null;
105113
}
106114

107115
register(rowSelectionPlugin?: any) {
108116
if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
109117
// the plugin has to be created BEFORE the grid (else it behaves oddly), but we can only watch grid events AFTER the grid is created
110-
this.sharedService.grid.registerPlugin(this._extension);
118+
this.sharedService.grid.registerPlugin(this._addon);
111119

112120
// this also requires the Row Selection Model to be registered as well
113121
if (!rowSelectionPlugin || !this.sharedService.grid.getSelectionModel()) {
@@ -116,28 +124,25 @@ export class RowDetailViewExtension implements Extension {
116124
this.sharedService.grid.setSelectionModel(rowSelectionPlugin);
117125
}
118126

119-
// this._extension = this.create(this.sharedService.allColumns, this.sharedService.gridOptions);
120-
this.sharedService.grid.registerPlugin(this._extension);
121-
122127
// hook all events
123128
if (this.sharedService.grid && this.sharedService.gridOptions.rowDetailView) {
124129
if (this.sharedService.gridOptions.rowDetailView.onExtensionRegistered) {
125-
this.sharedService.gridOptions.rowDetailView.onExtensionRegistered(this._extension);
130+
this.sharedService.gridOptions.rowDetailView.onExtensionRegistered(this._addon);
126131
}
127-
this._eventHandler.subscribe(this._extension.onAsyncResponse, (e: any, args: { item: any; detailView: any }) => {
132+
this._eventHandler.subscribe(this._addon.onAsyncResponse, (e: any, args: { item: any; detailView: any }) => {
128133
if (this.sharedService.gridOptions.rowDetailView && typeof this.sharedService.gridOptions.rowDetailView.onAsyncResponse === 'function') {
129134
this.sharedService.gridOptions.rowDetailView.onAsyncResponse(e, args);
130135
}
131136
});
132-
this._eventHandler.subscribe(this._extension.onAsyncEndUpdate, (e: any, args: { grid: any; item: any; }) => {
137+
this._eventHandler.subscribe(this._addon.onAsyncEndUpdate, (e: any, args: { grid: any; item: any; }) => {
133138
// triggers after backend called "onAsyncResponse.notify()"
134139
this.renderViewModel(args && args.item);
135140

136141
if (this.sharedService.gridOptions.rowDetailView && typeof this.sharedService.gridOptions.rowDetailView.onAsyncEndUpdate === 'function') {
137142
this.sharedService.gridOptions.rowDetailView.onAsyncEndUpdate(e, args);
138143
}
139144
});
140-
this._eventHandler.subscribe(this._extension.onAfterRowDetailToggle, (e: any, args: { grid: any; item: any; expandedRows: any[]; }) => {
145+
this._eventHandler.subscribe(this._addon.onAfterRowDetailToggle, (e: any, args: { grid: any; item: any; expandedRows: any[]; }) => {
141146
// display preload template & re-render all the other Detail Views after toggling
142147
// the preload View will eventually go away once the data gets loaded after the "onAsyncEndUpdate" event
143148
this.renderPreloadView();
@@ -147,23 +152,23 @@ export class RowDetailViewExtension implements Extension {
147152
this.sharedService.gridOptions.rowDetailView.onAfterRowDetailToggle(e, args);
148153
}
149154
});
150-
this._eventHandler.subscribe(this._extension.onBeforeRowDetailToggle, (e: any, args: { grid: any; item: any; }) => {
155+
this._eventHandler.subscribe(this._addon.onBeforeRowDetailToggle, (e: any, args: { grid: any; item: any; }) => {
151156
// before toggling row detail, we need to create View Component if it doesn't exist
152157
this.onBeforeRowDetailToggle(e, args);
153158

154159
if (this.sharedService.gridOptions.rowDetailView && typeof this.sharedService.gridOptions.rowDetailView.onBeforeRowDetailToggle === 'function') {
155160
this.sharedService.gridOptions.rowDetailView.onBeforeRowDetailToggle(e, args);
156161
}
157162
});
158-
this._eventHandler.subscribe(this._extension.onRowBackToViewportRange, (e: any, args: { grid: any; item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; }) => {
163+
this._eventHandler.subscribe(this._addon.onRowBackToViewportRange, (e: any, args: { grid: any; item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; }) => {
159164
// when row is back to viewport range, we will re-render the View Component(s)
160165
this.onRowBackToViewportRange(e, args);
161166

162167
if (this.sharedService.gridOptions.rowDetailView && typeof this.sharedService.gridOptions.rowDetailView.onRowBackToViewportRange === 'function') {
163168
this.sharedService.gridOptions.rowDetailView.onRowBackToViewportRange(e, args);
164169
}
165170
});
166-
this._eventHandler.subscribe(this._extension.onRowOutOfViewportRange, (e: any, args: { grid: any; item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; }) => {
171+
this._eventHandler.subscribe(this._addon.onRowOutOfViewportRange, (e: any, args: { grid: any; item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; }) => {
167172
if (this.sharedService.gridOptions.rowDetailView && typeof this.sharedService.gridOptions.rowDetailView.onRowOutOfViewportRange === 'function') {
168173
this.sharedService.gridOptions.rowDetailView.onRowOutOfViewportRange(e, args);
169174
}
@@ -182,7 +187,7 @@ export class RowDetailViewExtension implements Extension {
182187
this.filterService.onFilterChanged.subscribe((currentFilters: CurrentFilter[]) => this.redrawAllViewComponents())
183188
);
184189
}
185-
return this._extension;
190+
return this._addon;
186191
}
187192
return null;
188193
}
@@ -219,8 +224,8 @@ export class RowDetailViewExtension implements Extension {
219224
* @param item
220225
*/
221226
private notifyTemplate(item: any) {
222-
if (this._extension) {
223-
this._extension.onAsyncResponse.notify({ item }, undefined, this);
227+
if (this._addon) {
228+
this._addon.onAsyncResponse.notify({ item }, undefined, this);
224229
}
225230
}
226231

@@ -275,23 +280,19 @@ export class RowDetailViewExtension implements Extension {
275280
// expanding
276281
if (args && args.item && args.item.__collapsed) {
277282
// expanding row detail
278-
if (args && args.item) {
279-
const viewInfo: CreatedView = {
280-
id: args.item.id,
281-
dataContext: args.item
282-
};
283-
this.addToArrayWhenNotFound(this._views, viewInfo);
284-
}
283+
const viewInfo: CreatedView = {
284+
id: args.item.id,
285+
dataContext: args.item
286+
};
287+
this.addToArrayWhenNotFound(this._views, viewInfo);
285288
} else {
286289
// collapsing, so dispose of the View/Component
287290
const foundViewIndex = this._views.findIndex((view: CreatedView) => view.id === args.item.id);
288-
if (foundViewIndex >= 0) {
289-
if (this._views.hasOwnProperty(foundViewIndex)) {
290-
const compRef = this._views[foundViewIndex].componentRef;
291-
this.appRef.detachView(compRef.hostView);
292-
compRef.destroy();
293-
this._views.splice(foundViewIndex, 1);
294-
}
291+
if (foundViewIndex >= 0 && this._views.hasOwnProperty(foundViewIndex)) {
292+
const compRef = this._views[foundViewIndex].componentRef;
293+
this.appRef.detachView(compRef.hostView);
294+
compRef.destroy();
295+
this._views.splice(foundViewIndex, 1);
295296
}
296297
}
297298
}

src/app/modules/angular-slickgrid/models/rowDetailView.interface.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ export interface RowDetailView {
4141
*/
4242
useSimpleViewportCalc?: boolean;
4343

44-
/** View Component of the preload template which shows after opening row detail & before row detail data shows up */
44+
/** View Component of the preload template (typically a spinner) which shows after opening on the row detail but before the row detail is ready */
4545
preloadComponent?: Type<object>;
4646

47-
/** View Component that will be loaded once the async function finishes */
47+
/** View Component that will be loaded in the row detail after the async function completed */
4848
viewComponent: Type<object>;
4949

5050
// --
@@ -80,17 +80,17 @@ export interface RowDetailView {
8080
onAsyncResponse?: (e: Event, args: { item: any; detailView?: any }) => void;
8181

8282
/** Fired when the async response finished */
83-
onAsyncEndUpdate?: (e: Event, args: { grid: any; item: any }) => void;
83+
onAsyncEndUpdate?: (e: Event, args: { item: any; grid: any; }) => void;
8484

8585
/** Fired after the row detail gets toggled */
86-
onAfterRowDetailToggle?: (e: Event, args: { grid: any; item: any; expandedRows: any[] }) => void;
86+
onAfterRowDetailToggle?: (e: Event, args: { item: any; expandedRows: any[]; grid: any; }) => void;
8787

8888
/** Fired before the row detail gets toggled */
89-
onBeforeRowDetailToggle?: (e: Event, args: { grid: any; item: any }) => void;
89+
onBeforeRowDetailToggle?: (e: Event, args: { item: any; grid: any; }) => void;
9090

9191
/** Fired after the row detail gets toggled */
92-
onRowBackToViewportRange?: (e: Event, args: { grid: any; item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; }) => void;
92+
onRowBackToViewportRange?: (e: Event, args: { item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; grid: any; }) => void;
9393

9494
/** Fired after a row becomes out of viewport range (user can't see the row anymore) */
95-
onRowOutOfViewportRange?: (e: Event, args: { grid: any; item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; }) => void;
95+
onRowOutOfViewportRange?: (e: Event, args: { item: any; rowId: number; rowIndex: number; expandedRows: any[]; rowIdsOutOfViewport: number[]; grid: any; }) => void;
9696
}

0 commit comments

Comments
 (0)