+ This example demonstrates the use of Pinned (aka pinned) Columns and/or Rows (
-
-
- Remove Frozen Columns
-
-
- Set 3 Frozen Columns
-
-
-
- Toggle Pinned Rows
+
+
Pinned Rows:
+
Set
+
Pinned Columns:
+
Set
+
+ Pinned Right:
+
+
+
+ Set
- : ${ isFrozenBottom ? 'Bottom' : 'Top' }
-
+
+
+
+
+
+ Remove Pinned Columns
+
+
+ Pin 3 Columns
+
+
+ Toggle Pinned Right
+
+
+ Toggle Pinned Rows
+
+
+ Toggle Select All
+
+
+ Set Large Columns
+
+
-
-
-
-
-
-
diff --git a/demos/aurelia/src/examples/slickgrid/example20.scss b/demos/aurelia/src/examples/slickgrid/example20.scss
index 6e31054384..e41265a0e7 100644
--- a/demos/aurelia/src/examples/slickgrid/example20.scss
+++ b/demos/aurelia/src/examples/slickgrid/example20.scss
@@ -1,8 +1,8 @@
-/** You can change the pinned/frozen border styling through this css override */
+/** You can change the pinned/pinned border styling through this css override */
-.slick-row .slick-cell.frozen:last-child,
-.slick-headerrow-column.frozen:last-child,
-.slick-footerrow-column.frozen:last-child {
+.slick-row .slick-cell.pinned:last-child,
+.slick-headerrow-column.pinned:last-child,
+.slick-footerrow-column.pinned:last-child {
border-right: 1px solid #969696 !important;
}
diff --git a/demos/aurelia/src/examples/slickgrid/example20.ts b/demos/aurelia/src/examples/slickgrid/example20.ts
index d655caebce..6215b4e6db 100644
--- a/demos/aurelia/src/examples/slickgrid/example20.ts
+++ b/demos/aurelia/src/examples/slickgrid/example20.ts
@@ -1,9 +1,9 @@
+import { ExcelExportService } from '@slickgrid-universal/excel-export';
import {
Editors,
Filters,
formatNumber,
Formatters,
- SlickEventHandler,
type AureliaGridInstance,
type Column,
type ColumnEditorDualInput,
@@ -11,337 +11,305 @@ import {
type SlickGrid,
} from 'aurelia-slickgrid';
import { showToast } from './utilities.js';
-import './example20.scss'; // provide custom CSS/SASS styling
+import './example20.scss';
export class Example20 {
aureliaGrid!: AureliaGridInstance;
- columns: Column[] = [];
gridObj!: SlickGrid;
+ columns: Column[] = [];
gridOptions!: GridOption;
- frozenColumnCount = 2;
- frozenRowCount = 3;
- hideSubTitle = false;
- isFrozenBottom = false;
dataset: any[] = [];
- slickEventHandler: any;
-
+ pinnedColumnCount = 2;
+ pinnedRightColumnCount = 1;
+ pinnedRowCount = 3;
+ hideSubTitle = false;
+ isPinnedBottom = false;
+ isSelectAllShownAsColumnTitle = false;
+ checkboxSelectorInstance: any;
constructor() {
this.defineGrid();
- this.slickEventHandler = new SlickEventHandler();
}
-
- aureliaGridReady(aureliaGrid: AureliaGridInstance) {
- this.aureliaGrid = aureliaGrid;
- this.gridObj = aureliaGrid && aureliaGrid.slickGrid;
-
- // with frozen (pinned) grid, in order to see the entire row being highlighted when hovering
- // we need to do some extra tricks (that is because frozen grids use 2 separate div containers)
- // the trick is to use row selection to highlight when hovering current row and remove selection once we're not
- this.slickEventHandler.subscribe(this.gridObj.onMouseEnter, (event: Event) => this.colorizeHoveringRow(event, true));
- this.slickEventHandler.subscribe(this.gridObj.onMouseLeave, (event: Event) => this.colorizeHoveringRow(event, false));
- }
-
- colorizeHoveringRow(event: Event, isMouseEnter: boolean) {
- const cell = this.gridObj.getCellFromEvent(event);
- const rows = isMouseEnter ? [cell?.row ?? 0] : [];
- this.gridObj.setSelectedRows(rows); // highlight current row
- event.preventDefault();
- }
-
attached() {
- // populate the dataset once the grid is ready
- this.getData();
+ this.dataset = Array.from({ length: 500 }, (_v, i) => ({
+ id: i,
+ title: `Task ${i}`,
+ duration: `${Math.round(Math.random() * 100)}`,
+ percentComplete: Math.round(Math.random() * 100),
+ start: new Date(2009, 0, 1),
+ finish: new Date(2009, 4, 5),
+ completed: i % 5 === 0,
+ cost: i % 33 === 0 ? null : Math.random() * 10000,
+ cityOfOrigin: i % 2 ? 'Vancouver, BC, Canada' : 'Boston, MA, United States',
+ }));
}
-
- detaching() {
- // unsubscribe every SlickGrid subscribed event (or use the Slick.EventHandler)
- this.slickEventHandler.unsubscribeAll();
+ aureliaGridReady(g: AureliaGridInstance) {
+ this.aureliaGrid = g;
+ this.gridObj = g.slickGrid;
}
-
- /* Define grid Options and Columns */
defineGrid() {
+ const dual = {
+ leftInput: { field: 'cost', type: 'float', decimal: 2, minValue: 0, maxValue: 50000 },
+ rightInput: { field: 'duration', type: 'float', minValue: 0, maxValue: 100 },
+ } as ColumnEditorDualInput;
this.columns = [
- {
- id: 'sel',
- name: '#',
- field: 'id',
- minWidth: 40,
- width: 40,
- maxWidth: 40,
- cannotTriggerInsert: true,
- resizable: false,
- unselectable: true,
- },
- {
- id: 'title',
- name: 'Title',
- field: 'title',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
- },
+ { id: 'title', name: 'Title', field: 'title', width: 120, minWidth: 100, sortable: true, filterable: true },
{
id: 'percentComplete',
name: '% Complete',
field: 'percentComplete',
- resizable: false,
- minWidth: 130,
width: 140,
- formatter: Formatters.percentCompleteBar,
+ minWidth: 130,
type: 'number',
+ sortable: true,
filterable: true,
filter: { model: Filters.slider, operator: '>=' },
- sortable: true,
+ editor: { model: Editors.singleSelect, collection: Array.from({ length: 101 }, (_v, i) => ({ value: i, label: i })) },
},
{
id: 'start',
name: 'Start',
field: 'start',
- minWidth: 100,
- width: 120,
- filterable: true,
+ type: 'dateIso',
sortable: true,
+ filterable: true,
formatter: Formatters.dateIso,
+ filter: { model: Filters.compoundDate },
},
{
id: 'finish',
name: 'Finish',
field: 'finish',
- minWidth: 100,
- width: 120,
- filterable: true,
+ type: 'dateIso',
sortable: true,
+ filterable: true,
formatter: Formatters.dateIso,
+ filter: { model: Filters.compoundDate },
},
{
- id: 'cost',
- name: 'Cost | Duration',
- field: 'cost',
- formatter: this.costDurationFormatter.bind(this),
- minWidth: 150,
- width: 170,
+ id: 'completed',
+ name: 'Completed',
+ field: 'completed',
sortable: true,
- // filterable: true,
- filter: {
- model: Filters.compoundSlider,
- },
- editor: {
- model: Editors.dualInput,
- // the DualInputEditor is of Type ColumnEditorDualInput and MUST include (leftInput/rightInput) in its params object
- // in each of these 2 properties, you can pass any regular properties of a column editor
- // and they will be executed following the options defined in each
- params: {
- leftInput: {
- field: 'cost',
- type: 'float',
- decimal: 2,
- minValue: 0,
- maxValue: 50000,
- placeholder: '< 50K',
- errorMessage: 'Cost must be positive and below $50K.',
- },
- rightInput: {
- field: 'duration',
- type: 'float', // you could have 2 different input type as well
- minValue: 0,
- maxValue: 100,
- title: 'make sure Duration is withing its range of 0 to 100',
- errorMessage: 'Duration must be between 0 and 100.',
-
- // Validator Option #1
- // You could also optionally define a custom validator in 1 or both inputs
- /*
- validator: (value, args) => {
- let isValid = true;
- let errorMsg = '';
- if (value < 0 || value > 120) {
- isValid = false;
- errorMsg = 'Duration MUST be between 0 and 120.';
- }
- return { valid: isValid, msg: errorMsg };
- }
- */
- },
- } as ColumnEditorDualInput,
-
- // Validator Option #2 (shared Validator) - this is the last alternative, option #1 (independent Validators) is still the recommended way
- // You can also optionally use a common Validator (if you do then you cannot use the leftInput/rightInput validators at same time)
- // to compare both values at the same time.
- /*
- validator: (values, args) => {
- let isValid = true;
- let errorMsg = '';
- if (values.cost < 0 || values.cost > 50000) {
- isValid = false;
- errorMsg = 'Cost MUST be between 0 and 50k.';
- }
- if (values.duration < 0 || values.duration > 120) {
- isValid = false;
- errorMsg = 'Duration MUST be between 0 and 120.';
- }
- if (values.cost < values.duration) {
- isValid = false;
- errorMsg = 'Cost can never be lower than its Duration.';
- }
- return { valid: isValid, msg: errorMsg };
- }
- */
- },
- },
- {
- id: 'effortDriven',
- name: 'Effort Driven',
- field: 'effortDriven',
- minWidth: 100,
- width: 120,
- formatter: Formatters.checkmarkMaterial,
filterable: true,
+ formatter: Formatters.checkmarkMaterial,
+ editor: { model: Editors.checkbox },
filter: {
+ model: Filters.singleSelect,
collection: [
{ value: '', label: '' },
{ value: true, label: 'True' },
{ value: false, label: 'False' },
],
- model: Filters.singleSelect,
},
- sortable: true,
- },
- {
- id: 'title1',
- name: 'Title 1',
- field: 'title1',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
},
{
- id: 'title2',
- name: 'Title 2',
- field: 'title2',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
- },
- {
- id: 'title3',
- name: 'Title 3',
- field: 'title3',
- minWidth: 100,
- width: 120,
- filterable: true,
+ id: 'cost',
+ name: 'Cost | Duration',
+ field: 'cost',
+ formatter: this.costDurationFormatter.bind(this),
sortable: true,
+ filter: { model: Filters.compoundSlider },
+ editor: { model: Editors.dualInput, params: dual },
},
+ { id: 'cityOfOrigin', name: 'City of Origin', field: 'cityOfOrigin', minWidth: 100, sortable: true, filterable: true },
{
- id: 'title4',
- name: 'Title 4',
- field: 'title4',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
+ id: 'action',
+ name: 'Action',
+ field: 'action',
+ width: 100,
+ maxWidth: 100,
+ excludeFromExport: true,
+ formatter: () => '',
+ cellMenu: {
+ commandTitle: 'Commands',
+ commandItems: [
+ { command: 'command1', title: 'Command 1' },
+ { command: 'command2', title: 'Command 2', itemUsabilityOverride: (args: any) => !args.dataContext.completed },
+ { command: 'delete-row', title: 'Delete Row', itemVisibilityOverride: (args: any) => !args.dataContext.completed },
+ { divider: true, command: '' },
+ { command: 'help', title: 'Help' },
+ { command: 'something', title: 'Disabled Command', disabled: true },
+ ],
+ optionTitle: 'Change Complete Flag',
+ optionItems: [
+ { option: true, title: 'True' },
+ { option: false, title: 'False' },
+ ],
+ },
},
];
-
this.gridOptions = {
- autoResize: {
- container: '#demo-container',
- rightPadding: 10,
- },
- gridWidth: 920,
+ autoResize: { container: '#demo-container', rightPadding: 10 },
+ // Keep the left-pinned columns compact so two right-pinned columns fit
+ // beside the framework demo's route sidebar.
+ autoFitColumnsOnFirstLoad: false,
enableCellNavigation: true,
editable: true,
autoEdit: true,
+ enableFiltering: true,
enableExcelCopyBuffer: true,
- frozenColumn: this.frozenColumnCount,
- frozenRow: this.frozenRowCount,
- // frozenBottom: true, // if you want to freeze the bottom instead of the top, you can enable this property
-
- // show both Frozen Columns in HeaderMenu & GridMenu, these are opt-in commands so they're disabled by default
- gridMenu: { hideClearFrozenColumnsCommand: false },
- headerMenu: { hideFreezeColumnsCommand: false },
+ enableExcelExport: true,
+ externalResources: [new ExcelExportService()],
+ enableSelection: true,
+ enableCheckboxSelector: true,
+ selectionOptions: { selectActiveRow: false },
+ checkboxSelector: {
+ hideInColumnTitleRow: true,
+ hideInFilterHeaderRow: false,
+ name: 'Sel',
+ onExtensionRegistered: (i: any) => (this.checkboxSelectorInstance = i),
+ },
+ pinning: { columns: { left: ['_checkbox_selector', 'title', 'percentComplete'], right: ['action'] }, rows: { top: [0, 1, 2] } },
+ enableCellMenu: true,
+ cellMenu: {
+ onCommand: (_e: any, a: any) => this.executeCommand(a),
+ onOptionSelected: (_e: any, a: any) => {
+ if (a?.dataContext) {
+ a.dataContext.completed = a.item.option;
+ this.aureliaGrid?.gridService?.updateItem(a.dataContext);
+ }
+ },
+ },
+ enableContextMenu: true,
+ contextMenu: this.getContextMenuOptions(),
+ gridMenu: { hideClearPinningCommand: false },
+ headerMenu: { hidePinColumnCommand: false, hidePinningColumnsCommand: false },
};
}
-
- getData() {
- // Set up some test columns.
- const mockDataset: any[] = [];
- for (let i = 0; i < 500; i++) {
- mockDataset[i] = {
- id: i,
- title: 'Task ' + i,
- cost: i % 33 === 0 ? null : Math.random() * 10000,
- duration: i % 8 ? Math.round(Math.random() * 100) + '' : null,
- percentComplete: Math.round(Math.random() * 100),
- start: new Date(2009, 0, 1),
- finish: new Date(2009, 4, 5),
- effortDriven: i % 5 === 0,
- title1: `Some Text ${Math.round(Math.random() * 25)}`,
- title2: `Some Text ${Math.round(Math.random() * 25)}`,
- title3: `Some Text ${Math.round(Math.random() * 25)}`,
- title4: `Some Text ${Math.round(Math.random() * 25)}`,
- };
- }
- this.dataset = mockDataset;
+ getContextMenuOptions(): any {
+ const p = [
+ { option: 0, title: 'Not Started (0%)' },
+ { option: 50, title: 'Half Completed (50%)' },
+ { option: 100, title: 'Completed (100%)' },
+ ];
+ return {
+ optionShownOverColumnIds: ['percentComplete'],
+ hideCloseButton: true,
+ dropSide: 'right',
+ optionTitle: 'Change Percent Complete',
+ optionItems: [...p, 'divider', { option: null, title: 'Sub-Options (demo)', subMenuTitle: 'Set Percent Complete', optionItems: p }],
+ commandItems: [
+ { command: '', divider: true, positionOrder: 98 },
+ {
+ command: 'export',
+ title: 'Exports',
+ positionOrder: 99,
+ commandItems: [
+ { command: 'exports-txt', title: 'Text (tab delimited)' },
+ {
+ command: 'sub-menu',
+ title: 'Excel',
+ subMenuTitle: 'available formats',
+ commandItems: [
+ { command: 'exports-csv', title: 'Excel (csv)' },
+ { command: 'exports-xlsx', title: 'Excel (xlsx)' },
+ ],
+ },
+ ],
+ },
+ {
+ command: 'feedback',
+ title: 'Feedback',
+ positionOrder: 100,
+ commandItems: [
+ { command: 'request-update', title: 'Request update from supplier' },
+ 'divider',
+ {
+ command: 'sub-menu',
+ title: 'Contact Us',
+ subMenuTitle: 'contact us...',
+ commandItems: [
+ { command: 'contact-email', title: 'Email us' },
+ { command: 'contact-chat', title: 'Chat with us' },
+ { command: 'contact-meeting', title: 'Book an appointment' },
+ ],
+ },
+ ],
+ },
+ ],
+ onOptionSelected: (_e: any, a: any) => {
+ if (a?.dataContext) {
+ a.dataContext.percentComplete = a.item.option;
+ this.gridObj?.updateRow(a.row || 0);
+ }
+ },
+ onCommand: (_e: any, a: any) => this.executeCommand(a),
+ };
}
-
- /** change dynamically, through slickgrid "setOptions()" the number of pinned columns */
- changeFrozenColumnCount() {
- if (this.gridObj && this.gridObj.setOptions) {
- this.gridObj.setOptions({
- frozenColumn: this.frozenColumnCount,
- });
+ executeCommand(a: any) {
+ if (a.command === 'delete-row' && confirm(`Do you really want to delete row (${a.row + 1}) with "${a.dataContext.title}"?`)) {
+ this.aureliaGrid?.gridService?.deleteItemById(a.dataContext.id);
+ } else if (['command1', 'command2', 'help'].includes(a.command)) {
+ alert(a.item.title);
+ } else if (['exports-csv', 'exports-txt', 'exports-xlsx'].includes(a.command)) {
+ alert(`Exporting as ${a.item.title}`);
+ } else {
+ alert(`Command: ${a.command}`);
}
}
-
- /** change dynamically, through slickgrid "setOptions()" the number of pinned rows */
- changeFrozenRowCount() {
- if (this.gridObj && this.gridObj.setOptions) {
- this.gridObj.setOptions({
- frozenRow: this.frozenRowCount,
- });
- }
+ setPinnedColumns(left: number, right = this.pinnedRightColumnCount) {
+ const n = Math.max(0, Number(right) || 0);
+ this.gridObj?.setOptions({
+ pinning: {
+ columns: {
+ left: left >= 0 ? ['_checkbox_selector', 'title', 'percentComplete'].slice(0, left + 1) : [],
+ right: ['cityOfOrigin', 'action'].slice(Math.max(0, 2 - n)),
+ },
+ },
+ });
+ this.pinnedColumnCount = left;
+ this.pinnedRightColumnCount = n;
}
-
- costDurationFormatter(_row: number, _cell: number, _value: any, _columnDef: Column, dataContext: any) {
- const costText = this.isNullUndefinedOrEmpty(dataContext.cost) ? 'n/a' : formatNumber(dataContext.cost, 0, 2, false, '$', '', '.', ',');
- let durationText = 'n/a';
- if (!this.isNullUndefinedOrEmpty(dataContext.duration) && dataContext.duration >= 0) {
- durationText = `${dataContext.duration} ${dataContext.duration > 1 ? 'days' : 'day'}`;
- }
- return `
${costText} | ${durationText}`;
+ changePinnedColumnCount() {
+ this.setPinnedColumns(this.pinnedColumnCount);
}
-
- isNullUndefinedOrEmpty(data: any) {
- return data === '' || data === null || data === undefined;
+ changePinnedRowCount() {
+ const rows = Array.from({ length: Math.max(0, this.pinnedRowCount) }, (_v, i) => i);
+ this.gridObj?.setOptions({ pinning: { rows: this.isPinnedBottom ? { top: [], bottom: rows } : { top: rows, bottom: [] } } });
+ }
+ toggleRightPinning() {
+ this.setPinnedColumns(this.pinnedColumnCount, this.pinnedRightColumnCount > 0 ? 0 : 1);
+ }
+ togglePinnedBottomRows() {
+ this.isPinnedBottom = !this.isPinnedBottom;
+ this.changePinnedRowCount();
+ }
+ toggleSelectAllRow() {
+ this.isSelectAllShownAsColumnTitle = !this.isSelectAllShownAsColumnTitle;
+ this.checkboxSelectorInstance?.setOptions({
+ hideInColumnTitleRow: !this.isSelectAllShownAsColumnTitle,
+ hideInFilterHeaderRow: this.isSelectAllShownAsColumnTitle,
+ });
+ }
+ setLargePinnedColumns() {
+ this.aureliaGrid?.gridStateService?.applyColumnLayout?.(
+ [
+ { columnId: '_checkbox_selector', cssClass: 'slick-cell-checkboxsel', headerCssClass: '', width: 40 },
+ { columnId: 'title', cssClass: '', headerCssClass: '', width: 220 },
+ { columnId: 'percentComplete', cssClass: '', headerCssClass: '', width: 280 },
+ { columnId: 'start', cssClass: '', headerCssClass: '', width: 150 },
+ { columnId: 'finish', cssClass: '', headerCssClass: '', width: 280 },
+ { columnId: 'completed', cssClass: '', headerCssClass: '', width: 180 },
+ { columnId: 'cost', cssClass: '', headerCssClass: '', width: 220 },
+ { columnId: 'cityOfOrigin', cssClass: '', headerCssClass: '', width: 180 },
+ { columnId: 'action', cssClass: '', headerCssClass: '', width: 110 },
+ ],
+ false,
+ false
+ );
+ this.setPinnedColumns(2, this.pinnedRightColumnCount);
}
-
onCellValidationError(_e: Event, args: any) {
showToast(args.validationResults.msg, 'danger');
}
-
- setFrozenColumns(frozenCols: number) {
- this.gridObj.setOptions({ frozenColumn: frozenCols });
- this.gridOptions = this.gridObj.getOptions();
- this.frozenColumnCount = frozenCols;
- }
-
- /** toggle dynamically, through slickgrid "setOptions()" the top/bottom pinned location */
- toggleFrozenBottomRows() {
- if (this.gridObj && this.gridObj.setOptions) {
- this.gridObj.setOptions({
- frozenBottom: !this.isFrozenBottom,
- });
- this.isFrozenBottom = !this.isFrozenBottom; // toggle the variable
- }
+ costDurationFormatter(_r: number, _c: number, _v: any, _d: Column, x: any) {
+ const cost = x.cost == null ? 'n/a' : formatNumber(x.cost, 0, 2, false, '$', '', '.', ',');
+ const duration = x.duration != null && x.duration >= 0 ? `${x.duration} ${x.duration > 1 ? 'days' : 'day'}` : 'n/a';
+ return `
${cost} | ${duration}`;
}
-
toggleSubTitle() {
this.hideSubTitle = !this.hideSubTitle;
- const action = this.hideSubTitle ? 'add' : 'remove';
- document.querySelector('.subtitle')?.classList[action]('hidden');
- this.aureliaGrid.resizerService.resizeGrid(0);
+ document.querySelector('.subtitle')?.classList[this.hideSubTitle ? 'add' : 'remove']('hidden');
+ this.aureliaGrid?.resizerService?.resizeGrid(0);
}
}
diff --git a/demos/aurelia/src/examples/slickgrid/example38.ts b/demos/aurelia/src/examples/slickgrid/example38.ts
index 26a733fa97..68197fb7a6 100644
--- a/demos/aurelia/src/examples/slickgrid/example38.ts
+++ b/demos/aurelia/src/examples/slickgrid/example38.ts
@@ -96,7 +96,8 @@ export class Example38 {
enableSelection: true,
enableGrouping: true,
headerMenu: {
- hideFreezeColumnsCommand: false,
+ hidePinColumnCommand: false,
+ hidePinningColumnsCommand: false,
},
presets: {
// NOTE: pagination preset is NOT supported with infinite scroll
diff --git a/demos/aurelia/src/examples/slickgrid/example43.ts b/demos/aurelia/src/examples/slickgrid/example43.ts
index 9307b653d3..5c4c673c01 100644
--- a/demos/aurelia/src/examples/slickgrid/example43.ts
+++ b/demos/aurelia/src/examples/slickgrid/example43.ts
@@ -144,7 +144,6 @@ export class Example43 {
autoResize: {
container: '#demo-container',
bottomPadding: 30,
- rightPadding: 50,
},
enableCellNavigation: true,
enableColumnReorder: true,
@@ -156,7 +155,7 @@ export class Example43 {
autoEdit: true,
editable: false,
datasetIdPropertyName: 'employeeID',
- frozenColumn: 0,
+ pinning: { columns: { left: 0 } },
gridHeight: 348,
rowHeight: 30,
dataView: {
@@ -451,7 +450,7 @@ export class Example43 {
newMetadata[row].columns[Number(col) + colDirIdx] = (this.metadata as any)[row].columns[col];
}
}
- this.aureliaGrid.slickGrid?.setOptions({ frozenColumn: newShowEmployeeId ? 0 : 1 });
+ this.aureliaGrid.slickGrid?.setOptions({ pinning: { columns: { left: newShowEmployeeId ? 0 : 1 } } });
this.aureliaGrid.slickGrid?.updateColumnById('employeeID', { hidden: !newShowEmployeeId });
this.aureliaGrid.slickGrid?.updateColumns();
*/
diff --git a/demos/aurelia/src/examples/slickgrid/example55.ts b/demos/aurelia/src/examples/slickgrid/example55.ts
index 866e0ab26b..27a506af5c 100644
--- a/demos/aurelia/src/examples/slickgrid/example55.ts
+++ b/demos/aurelia/src/examples/slickgrid/example55.ts
@@ -83,7 +83,7 @@ export class Example55 {
const owners = ['Alex', 'Priya', 'Mia', 'Sam', 'Chris'];
const fragments = [
'Refactor keyboard shortcut handling for better readability.',
- 'Adjust frozen rows when view-model updates after grouping.',
+ 'Adjust pinned rows when view-model updates after grouping.',
'Improve screen-reader labels on grid menu actions.',
'Align batch editor validation with backend constraints.',
'Capture edge-case around hidden columns and row-span.',
diff --git a/demos/aurelia/src/examples/slickgrid/example56.ts b/demos/aurelia/src/examples/slickgrid/example56.ts
index 2d47583e09..e9bd506f48 100644
--- a/demos/aurelia/src/examples/slickgrid/example56.ts
+++ b/demos/aurelia/src/examples/slickgrid/example56.ts
@@ -80,7 +80,7 @@ export class Example56 {
includeColumnWidth: true,
},
rowHeight: 40,
- frozenRow: 2,
+ pinning: { rows: { top: [0, 1] } },
gridHeight: 560,
gridWidth: 1080,
dataView: {
@@ -111,7 +111,7 @@ export class Example56 {
const statuses: Array
= ['Todo', 'In Progress', 'Done'];
const notesPool = [
'Short note.',
- 'Need to validate keyboard navigation and ensure screen reader output remains stable across frozen panes.',
+ 'Need to validate keyboard navigation and ensure screen reader output remains stable across pinned panes.',
'Review row height invalidation path when data changes quickly due to live updates from backend polling.',
'Longer QA note: validate scrolling behavior at top and bottom boundaries, compare rendered range against expected rows, and confirm no visual clipping for wrapped cells.',
];
diff --git a/demos/aurelia/test/cypress/e2e/example03.cy.ts b/demos/aurelia/test/cypress/e2e/example03.cy.ts
index f488efd517..a08337a57c 100644
--- a/demos/aurelia/test/cypress/e2e/example03.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example03.cy.ts
@@ -61,8 +61,8 @@ describe('Example 3 - Grid with Editors', () => {
.click();
// change Title & Custom Title
- cy.get('.editor-title > textarea').type('Task 2222');
- cy.get('.editor-title .btn-save').click();
+ cy.get('.editor-title:visible > textarea').type('Task 2222');
+ cy.get('.editor-title:visible .btn-save').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 2222');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(3)`).should('contain', 'Task 2222');
@@ -98,7 +98,7 @@ describe('Example 3 - Grid with Editors', () => {
`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(11) > input.editor-checkbox.editor-effort-driven`
).check();
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
});
it('should dynamically add 2x new "Title" columns', () => {
@@ -147,8 +147,8 @@ describe('Example 3 - Grid with Editors', () => {
.click();
// change Title & Custom Title
- cy.get('.editor-title > textarea').type('Task 0000');
- cy.get('.editor-title .btn-save').click();
+ cy.get('.editor-title:visible > textarea').type('Task 0000');
+ cy.get('.editor-title:visible .btn-save').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 0000');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(3)`).should('contain', 'Task 0000');
@@ -180,7 +180,7 @@ describe('Example 3 - Grid with Editors', () => {
.blur();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(10)`).click(); // the blur seems to not always work, so just click on another cell
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(11)`).find('.mdi-check.checkmark-icon');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
});
it('should be able to filter and search "Task 2222" in the new column and expect only 1 row showing in the grid', () => {
@@ -258,7 +258,7 @@ describe('Example 3 - Grid with Editors', () => {
});
it('should open the "Prerequisites" Filter and expect to have Task 500 & 101 in the Filter', () => {
- cy.get('div.ms-filter.filter-prerequisites').trigger('click', { force: true });
+ cy.get('div.ms-filter.filter-prerequisites').trigger('click');
cy.get('.ms-drop').find('span:nth(1)').contains('Task 101');
@@ -270,7 +270,7 @@ describe('Example 3 - Grid with Editors', () => {
it('should open the "Prerequisites" Editor and expect to have Task 100 & 101 in the Editor', () => {
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(12)`)
.should('contain', '')
- .click({ force: true });
+ .click();
cy.get('.ms-drop').find('span:nth(1)').contains('Task 101');
@@ -284,11 +284,11 @@ describe('Example 3 - Grid with Editors', () => {
});
it('should delete the last item "Task 101" and expect it to be removed from the Filter', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('right').wait(50);
+ cy.get('.slick-horizontal-scroller').scrollTo('right').wait(50);
cy.get('[data-test="delete-item-btn"]').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0).wait(50);
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0).wait(50);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 100');
cy.get('div.ms-filter.filter-prerequisites').trigger('click');
diff --git a/demos/aurelia/test/cypress/e2e/example07.cy.ts b/demos/aurelia/test/cypress/e2e/example07.cy.ts
index 048c260d9b..446c389b24 100644
--- a/demos/aurelia/test/cypress/e2e/example07.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example07.cy.ts
@@ -75,7 +75,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should go over the last "Column J" and expect to find the button to have the disabled class and clicking it should not turn the negative numbers to red neither expect console log after clicking the disabled button', () => {
- cy.get('#grid7-1 .slick-viewport-top.slick-viewport-left').scrollTo('right').wait(50);
+ cy.get('#grid7-1 .slick-horizontal-scroller').scrollTo('right').wait(50);
cy.get('#grid7-1 .slick-header-columns')
.children('.slick-header-column:nth(9)')
@@ -109,7 +109,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should resize 1st column and make it wider', () => {
- cy.get('#grid7-1 .slick-viewport-top.slick-viewport-left').scrollTo('left').wait(50);
+ cy.get('#grid7-1 .slick-horizontal-scroller').scrollTo('left').wait(50);
cy.get('#grid7-1 .slick-header-columns').children('.slick-header-column:nth(0)').should('contain', 'Resize me!');
@@ -220,7 +220,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should go over the last "Column J" and expect to find the button to have the disabled class and clicking it should not turn the negative numbers to red neither expect console log after clicking the disabled button', () => {
- cy.get('#grid7-2 .slick-viewport-top.slick-viewport-left').scrollTo('right').wait(50);
+ cy.get('#grid7-2 .slick-horizontal-scroller').scrollTo('right').wait(50);
cy.get('#grid7-2 .slick-header-columns')
.children('.slick-header-column:nth(9)')
@@ -254,7 +254,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should resize 1st column and make it wider', () => {
- cy.get('#grid7-2 .slick-viewport-top.slick-viewport-left').scrollTo('left').wait(50);
+ cy.get('#grid7-2 .slick-horizontal-scroller').scrollTo('left').wait(50);
cy.get('#grid7-2 .slick-header-columns').children('.slick-header-column:nth(0)').should('contain', 'Resize me!');
@@ -364,7 +364,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should expect first few items of "Column C" to be negative numbers and be red', () => {
- cy.get('#grid7-2 .slick-viewport-top.slick-viewport-left').scrollTo('top').wait(50);
+ cy.get('#grid7-2 .slick-vertical-scroller').scrollTo('top').wait(50);
cy.get('#grid7-2 .slick-row').each(($row, index) => {
if (index > 10) {
diff --git a/demos/aurelia/test/cypress/e2e/example10.cy.ts b/demos/aurelia/test/cypress/e2e/example10.cy.ts
index f65cc30eeb..fb67e74664 100644
--- a/demos/aurelia/test/cypress/e2e/example10.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example10.cy.ts
@@ -389,14 +389,14 @@ describe('Example 10 - Multiple Grids with Row Selection', () => {
it('should scroll to the bottom of 2nd Grid and still have 5 rows (Task 1,Task 3,Task 12,Task 13,Task 522) selected and find 2 row selected because we now have 2 rows that got rendered (first and last)', () => {
cy.get('#slickGridContainer-grid2').as('grid2');
cy.get('[data-test=grid2-selections]').should('contain', 'Task 1,Task 3,Task 12,Task 13,Task 522');
- cy.get('@grid2').find('.slick-viewport-top.slick-viewport-left').scrollTo('bottom').wait(10);
+ cy.get('@grid2').find('.slick-vertical-scroller').scrollTo('bottom').wait(10);
cy.get('@grid2').find('.slick-row').children().filter('.slick-cell-checkboxsel.selected').should('have.length', 2);
});
it('should have 2 rows (Task 3,Task 13) selected in 2nd grid after typing in a search filter (3)', () => {
cy.get('#slickGridContainer-grid2').as('grid2');
cy.get('@grid2').find('.filter-title').type('3');
- cy.get('@grid2').find('.slick-viewport-top.slick-viewport-left').scrollTo('top').wait(10);
+ cy.get('@grid2').find('.slick-vertical-scroller').scrollTo('top').wait(10);
cy.get('@grid2').find('.slick-row').should('not.have.length', 0);
cy.wait(50);
diff --git a/demos/aurelia/test/cypress/e2e/example12.cy.ts b/demos/aurelia/test/cypress/e2e/example12.cy.ts
index ec11ba1405..7ed1cab4e7 100644
--- a/demos/aurelia/test/cypress/e2e/example12.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example12.cy.ts
@@ -229,7 +229,7 @@ describe('Example 12: Localization (i18n)', () => {
it('should scroll to bottom of the grid then select "Task 4"', () => {
cy.get('#slickGridContainer-grid12').as('grid12');
- cy.get('@grid12').find('.slick-viewport-top.slick-viewport-left').scrollTo('bottom').wait(10);
+ cy.get('@grid12').find('.slick-vertical-scroller').scrollTo('bottom').wait(10);
cy.get('#grid12').contains('Task 4').parent().children('.slick-cell-checkboxsel').find('input[type=checkbox]').click({ force: true });
@@ -259,7 +259,7 @@ describe('Example 12: Localization (i18n)', () => {
cy.get('.grid-canvas').find('.slick-row').should('be.visible');
- cy.get('@grid12').find('.slick-viewport-top.slick-viewport-left').scrollTo('top').wait(10);
+ cy.get('@grid12').find('.slick-vertical-scroller').scrollTo('top').wait(10);
cy.get('@grid12').find('.slick-row').children().filter('.slick-cell-checkboxsel.selected').should('have.length', 1);
diff --git a/demos/aurelia/test/cypress/e2e/example14.cy.ts b/demos/aurelia/test/cypress/e2e/example14.cy.ts
index 91f7db34b6..32b529fd3b 100644
--- a/demos/aurelia/test/cypress/e2e/example14.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example14.cy.ts
@@ -1,5 +1,4 @@
describe('Example 14 - Column Span & Header Grouping', () => {
- // NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const fullPreTitles = ['', 'Common Factor', 'Period', 'Analysis'];
const fullTitles = ['#', 'Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
@@ -20,17 +19,18 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should have a frozen grid on page load with 3 columns on the left and 4 columns on the right', () => {
- cy.get('#grid2').find('[data-row=0]').should('have.length', 2);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 3);
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]').children().should('have.length', 4);
+ it('should have a pinned grid on page load with 3 pinned columns and 4 scrolling columns', () => {
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell`).should('have.length', 3);
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell`).should('have.length', 4);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]> .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]> .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]> .slick-cell:nth(2)').should('contain', '5 days');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(2)`).should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]> .slick-cell:nth(0)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]> .slick-cell:nth(1)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(0)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(1)`).should('contain', '01/05/2009');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid again', () => {
@@ -45,17 +45,18 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should click on the "Remove Frozen Columns" button to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
- cy.get('[data-test="remove-frozen-column-button"]').click();
+ it('should click on the "Remove Pinned Columns" button to switch to a regular grid without pinned columns', () => {
+ cy.get('[data-test="remove-pinned-column-button"]').click();
- cy.get('#grid2').find('[data-row=0]').should('have.length', 1);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 7);
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-cell`).should('have.length', 7);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(2)').should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(3)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(4)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-cell:nth(2)`).should('contain', '5 days');
+ cy.get(`${firstRow} .slick-cell:nth(3)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-cell:nth(4)`).should('contain', '01/05/2009');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid once again', () => {
@@ -70,19 +71,20 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should click on the "Set 3 Frozen Columns" button to switch frozen columns grid and expect 3 frozen columns on the left and 4 columns on the right', () => {
- cy.contains('Set 3 Frozen Columns').click({ force: true });
+ it('should click on the "Set 3 Pinned Columns" button to pin 3 columns and leave 4 scrolling columns', () => {
+ cy.contains('Set 3 Pinned Columns').click({ force: true });
- cy.get('#grid2').find('[data-row=0]').should('have.length', 2);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 3);
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]').children().should('have.length', 4);
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell`).should('have.length', 3);
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell`).should('have.length', 4);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(2)').should('contain', '5 days');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(2)`).should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0] > .slick-cell:nth(0)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0] > .slick-cell:nth(1)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(0)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(1)`).should('contain', '01/05/2009');
});
it('should have still exact Column Pre-Header & Column Header Titles in the grid', () => {
@@ -97,56 +99,49 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should click on the Grid Menu command "Unfreeze Columns/Rows" to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
+ it('should click on the Grid Menu command "Unpin Columns/Rows" to switch to a regular grid without pinned columns', () => {
cy.get('#grid2').find('button.slick-grid-menu-button').click({ force: true });
- cy.contains('Unfreeze Columns/Rows').click({ force: true });
+ cy.contains('Unpin Columns/Rows').click({ force: true });
- cy.get('#grid2').find('[data-row=0]').should('have.length', 1);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 7);
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-cell`).should('have.length', 7);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(2)').should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(3)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(4)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-cell:nth(2)`).should('contain', '5 days');
+ cy.get(`${firstRow} .slick-cell:nth(3)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-cell:nth(4)`).should('contain', '01/05/2009');
});
- it('should reapply 3 frozen columns on 2nd grid', () => {
- cy.contains('Set 3 Frozen Columns').click({ force: true });
+ it('should reapply 3 pinned columns on 2nd grid', () => {
+ cy.contains('Set 3 Pinned Columns').click({ force: true });
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 3);
-
- cy.get('#grid2')
- .find('.slick-pane-right .slick-header.slick-header-right .slick-header-columns .slick-header-column')
- .should('have.length', 4);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-column-pinned-left').should('have.length', 3);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column:not(.slick-column-pinned-left)').should(
+ 'have.length',
+ 4
+ );
});
- it('should be able to "Unfreeze Columns" from header menu', () => {
+ it('should be able to "Unpin All Columns" from header menu', () => {
cy.get('#grid2')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
+ .find('.slick-header.slick-header-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
.click();
- cy.get('.slick-header-menu .slick-menu-command-list')
- .should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Unfreeze Columns')
- .click();
+ cy.get('.slick-header-menu .slick-menu-command-list').should('be.visible').find('[data-command="pin-column"]').click();
+ cy.get('.slick-submenu [data-command="unpin-columns"]').should('contain', 'Unpin All Columns').click();
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 7);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column').should('have.length', 7);
});
- it('should be able to "Freeze Columns" back from header menu', () => {
+ it('should be able to "Pin Through Here" back from header menu', () => {
cy.get('#grid2')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
+ .find('.slick-header.slick-header-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
@@ -154,57 +149,72 @@ describe('Example 14 - Column Span & Header Grouping', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Freeze Columns')
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Column Pinning')
.click();
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 3);
+ cy.get('.slick-submenu [data-command="pin-columns"]').should('contain', 'Pin Through Here').click();
- cy.get('#grid2')
- .find('.slick-pane-right .slick-header.slick-header-right .slick-header-columns .slick-header-column')
- .should('have.length', 4);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-column-pinned-left').should('have.length', 3);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column:not(.slick-column-pinned-left)').should(
+ 'have.length',
+ 4
+ );
});
describe('Basic Key Navigations', () => {
it('should remove any freezing', () => {
- cy.get('[data-test="remove-frozen-column-button"]').click();
+ cy.get('[data-test="remove-pinned-column-button"]').click();
+
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column').should('have.length', 7);
+ });
+
+ it('should start at Task 1 on Duration colspan 5 days and type "PageDown" key once and land on a full colspan', () => {
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('@active_cell').type('{pagedown}');
+ cy.get('#grid1 .slick-cell.l0.r5.active').should('have.length', 1);
+ });
+
+ it('should start at Task 1 on Duration colspan 5 days and type "PageDown" key 2x times and land on a colspan of 3', () => {
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('@active_cell').type('{pagedown}{pagedown}');
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
+ });
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 7);
+ it('should navigate PageUp twice from a colspan of 3 back to the starting colspan of 3', () => {
+ cy.get('#grid1 [data-row=15] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('@active_cell').type('{pageup}{pageup}');
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
it('should start at Task 2 on Duration colspan 5 days and type "PageDown" key 2x times and "PageUp" twice and be back to Task 1 with colspan of 3', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{pagedown}{pagedown}{pageup}{pageup}');
- cy.get('[data-row=1] > .slick-cell.l1.r3.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
it('should start at Task 2 on Duration colspan 5 days and type "PageDown" key 2x times and "PageUp" 3x times and be on Task 0 with full colspan', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{pagedown}{pagedown}{pageup}{pageup}{pageup}');
- cy.get('[data-row=0] > .slick-cell.l0.r5.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l0.r5.active').should('have.length', 1);
});
it('should start at Task 1 on Duration colspan 5 days and type "ArrowDown" key once and be on Task 2 with full colspan', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{downarrow}');
- cy.get('[data-row=2] > .slick-cell.l0.r5.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l0.r5.active').should('have.length', 1);
});
it('should start at Task 1 on Duration colspan 5 days and type "ArrowDown" key 2x times and be on Task 1 with colspan of 3', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{downarrow}{downarrow}');
- cy.get('[data-row=3] > .slick-cell.l1.r3.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
it('should start at Task 1 on Duration colspan 5 days and type "ArrowDown" key 2x times, then "ArrowUp" key 2x times and be back on Task 1 with colspan of 3', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{downarrow}{downarrow}{uparrow}{uparrow}');
- cy.get('[data-row=1] > .slick-cell.l1.r3.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
});
@@ -219,7 +229,7 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.contains(/(true|false)+$/);
cy.get('#grid1')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
+ .find('.slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
@@ -232,6 +242,11 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.should('contain', 'Hide Column')
.click();
+ // The colspan still spans the logical Duration/Start/Finish range, but
+ // the hidden Finish track is zero-width. The host cell must remain
+ // rendered and visibly cover the two remaining columns.
+ cy.get('#grid1 [data-row=1] .slick-cell.l1.r3').should('contain', '5 days').and('be.visible');
+
// goto right
cy.get('#grid1').find('[data-row=1] .slick-cell.l0.r0').click();
cy.get('#grid1').find('[data-row=1] .slick-cell.l0.r0.active').should('contain', 'Task 1').type('{rightArrow}');
@@ -272,7 +287,7 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.contains(/(true|false)+$/);
cy.get('#grid1')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
+ .find('.slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
diff --git a/demos/aurelia/test/cypress/e2e/example15.cy.ts b/demos/aurelia/test/cypress/e2e/example15.cy.ts
index 2792dbeac6..5a7e09da9d 100644
--- a/demos/aurelia/test/cypress/e2e/example15.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example15.cy.ts
@@ -1,7 +1,6 @@
import { format } from '@formkit/tempo';
describe('Example 15: Grid State & Presets using Local Storage', () => {
- const GRID_ROW_HEIGHT = 35;
const fullEnglishTitles = ['', 'Title', 'Description', 'Duration', '% Complete', 'Start', 'Completed'];
beforeEach(() => {
@@ -12,16 +11,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.saveLocalStorage();
});
- it('should display Example title', () => {
- cy.visit(`${Cypress.config('baseUrl')}/example15`);
+ it('should display Example title from a clean local-storage state', () => {
+ cy.visit(`${Cypress.config('baseUrl')}/example15`, {
+ onBeforeLoad: (window) => window.localStorage.clear(),
+ });
cy.get('h2').should('contain', 'Example 15: Grid State & Presets using Local Storage');
-
- cy.clearLocalStorage();
- cy.get('[data-test=reset-button]').click();
- });
-
- it('should reload the page', () => {
- cy.reload().wait(50);
});
it('should have exact Column Titles in the grid', () => {
@@ -348,7 +342,7 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
.each(($child, index) => expect($child.find('.slick-column-name').text()).to.eq(expectedTitles[index]));
});
- it('should be able to freeze "Description" column', () => {
+ it('should be able to pin "Description" column', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.trigger('mouseover')
@@ -359,10 +353,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Geler les colonnes')
- .click();
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Épinglage de colonnes')
+ .trigger('mouseover');
+
+ cy.get('.slick-submenu:visible [data-command="pin-columns"]').should('contain', "Épingler jusqu'ici").click();
});
it('should reload the page', () => {
@@ -423,10 +418,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
});
});
- it('should have a persisted frozen column after "Description" and a grid with 4 containers on page load with 2 columns on the left and 3 columns on the right', () => {
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]').children().should('have.length', 3);
+ it('should have a persisted pinned column after "Description" with 2 pinned and 3 scrolling columns', () => {
+ const firstRow = '#grid15 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells > .slick-cell`).should('have.length', 2);
+ cy.get(`${firstRow} .slick-scrolling-cells > .slick-cell`).should('have.length', 3);
});
it('should click on the reset button and have exact Column Titles position as in beginning', () => {
@@ -453,7 +449,7 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
.each(($child, index) => expect($child.text()).to.eq(expectedTitles[index]));
});
- it('should be able to freeze "Description" 3rd column', () => {
+ it('should be able to pin "Description" 3rd column', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(2)')
.trigger('mouseover')
@@ -464,10 +460,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Freeze Columns')
- .click();
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Column Pinning')
+ .trigger('mouseover');
+
+ cy.get('.slick-submenu:visible [data-command="pin-columns"]').should('contain', 'Pin Through Here').click();
});
it('should swap "Duration" and "% Complete" columns', () => {
@@ -481,7 +478,7 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
.each(($child, index) => expect($child.text()).to.eq(expectedTitles[index]));
});
- it('should be able to freeze "% Complete" and expect 4th column to be freezed', () => {
+ it('should be able to pin "% Complete" and expect 4th column to be pinned', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(3)')
.trigger('mouseover')
@@ -492,16 +489,18 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Freeze Columns')
- .click();
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Column Pinning')
+ .trigger('mouseover');
+
+ cy.get('.slick-submenu:visible [data-command="pin-columns"]').should('contain', 'Pin Through Here').click();
});
- it('should have a persisted frozen column after "Description" and a grid with 4 containers on page load with 2 columns on the left and 3 columns on the right', () => {
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 4);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]').children().should('have.length', 3);
+ it('should have a persisted pinned column after "Description" with 4 pinned and 3 scrolling columns', () => {
+ const firstRow = '#grid15 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells > .slick-cell`).should('have.length', 4);
+ cy.get(`${firstRow} .slick-scrolling-cells > .slick-cell`).should('have.length', 3);
});
describe('Filter Shortcuts', () => {
@@ -599,9 +598,9 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
expect(Number($span.text())).to.gt(80);
});
- cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).contains('desc');
- cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).contains('desc');
- cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(2)`).contains('desc');
+ cy.get('#grid15 .slick-row[data-row="0"] .slick-cell.l2').contains('desc');
+ cy.get('#grid15 .slick-row[data-row="1"] .slick-cell.l2').contains('desc');
+ cy.get('#grid15 .slick-row[data-row="2"] .slick-cell.l2').contains('desc');
});
});
});
diff --git a/demos/aurelia/test/cypress/e2e/example16.cy.ts b/demos/aurelia/test/cypress/e2e/example16.cy.ts
index d9eb35e061..87d69f920c 100644
--- a/demos/aurelia/test/cypress/e2e/example16.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example16.cy.ts
@@ -39,7 +39,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', () => {
});
it('should expect the row to have moved to another row index', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 1');
@@ -76,7 +76,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', () => {
cy.get('@moveIconTask5').trigger('mousemove', 'bottomRight').trigger('mouseup', 'bottomRight', { which: 1, force: true });
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 1');
diff --git a/demos/aurelia/test/cypress/e2e/example19.cy.ts b/demos/aurelia/test/cypress/e2e/example19.cy.ts
index babe74c51a..d17f2c9055 100644
--- a/demos/aurelia/test/cypress/e2e/example19.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example19.cy.ts
@@ -80,7 +80,7 @@ describe('Example 19 - Row Detail View', () => {
cy.get('@detailContainer').find('[data-test=delete-btn]').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('#grid19')
.find('.slick-row')
@@ -111,7 +111,7 @@ describe('Example 19 - Row Detail View', () => {
cy.get('[data-test=collapse-all-btn]').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('#grid19').find('.dynamic-cell-detail .innerDetailView_0 .container_0').should('not.exist');
@@ -175,7 +175,7 @@ describe('Example 19 - Row Detail View', () => {
cy.get('#grid19').find('.slick-header-column:nth(1)').find('.slick-sort-indicator-asc').should('have.length', 1);
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('#grid19').find('.dynamic-cell-detail .innerDetailView_0 .container_0').should('not.exist');
diff --git a/demos/aurelia/test/cypress/e2e/example20.cy.ts b/demos/aurelia/test/cypress/e2e/example20.cy.ts
index 11481d0d77..91c8f4b076 100644
--- a/demos/aurelia/test/cypress/e2e/example20.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example20.cy.ts
@@ -1,102 +1,172 @@
-describe('Example 20 - Frozen Grid', () => {
- // NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
-
- const fullTitles = [
- '#',
- 'Title',
- '% Complete',
- 'Start',
- 'Finish',
- 'Cost | Duration',
- 'Effort Driven',
- 'Title 1',
- 'Title 2',
- 'Title 3',
- 'Title 4',
- ];
+describe('Example 20 - Pinned Grid', () => {
+ before(() => {
+ // The framework demos include a 250px route sidebar. Use enough width for
+ // the two-column pinning scenario to remain valid with that sidebar.
+ cy.viewport(1440, 900);
+ });
+
+ const withTitleRowTitles = ['Sel', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ const withoutTitleRowTitles = ['', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ const getCell = (rowIndex: number, columnIndex: number) =>
+ cy.get(`#grid20 .slick-row[data-row="${rowIndex}"] .slick-cell.l${columnIndex}`);
+ const setRightPinning = (count: number) => {
+ cy.get('.pinned-right-column-count').clear().type(`${count}`);
+ cy.get('[data-test="set-pinned-right-column"]').click();
+ };
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/example20`);
- cy.get('h2').should('contain', 'Example 20: Pinned (frozen) Columns/Rows');
+ cy.get('h2').should('contain', 'Example 20: Pinned Columns/Rows');
});
it('should have exact column titles on 1st grid', () => {
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
+ });
+
+ it('should hide sub-title to provide more space for the grid', () => {
+ cy.get('[data-test="toggle-subtitle"]').click();
});
it('should have exact Column Header Titles in the grid', () => {
cy.get('#grid20')
- .find('.slick-header-columns:nth(0)')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns:nth(0) .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
- it('should have a frozen grid with 4 containers on page load with 3 columns on the left and 4 columns on the right', () => {
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2 * 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ it('should have three top-pinned rows and left/center/right cells on page load', () => {
+ const row0 = '#grid20 .slick-row[data-row="0"]';
+
+ // Pinning uses one row node split into regions and a single docking overlay;
+ // it no longer duplicates rows into legacy left/right pinned canvases.
+ cy.get('#grid20 .slick-docking-overlay > .slick-row.slick-row-pinned-top').should('have.length', 3);
+ cy.get(`${row0} .slick-pinned-left-cells > .slick-cell`).should('have.length', 3);
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell`).should('have.length', 5);
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell`).should('have.length', 1);
+
+ cy.get(`${row0} .slick-pinned-left-cells > .slick-cell:nth(0)`).should('contain', '');
+ cy.get(`${row0} .slick-pinned-left-cells > .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(0)`).should('contain', '2009-01-01');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(1)`).should('contain', '2009-05-05');
+
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell:nth(0) .cell-menu-dropdown`).should('contain', 'Action');
+ });
+
+ it('should pin multiple columns on the right and render matching header and filter regions', () => {
+ setRightPinning(2);
+
+ const row0 = '#grid20 .slick-row[data-row="0"]';
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell`).should('have.length', 2);
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell.l7`).should('contain', 'Boston');
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell.l8 .cell-menu-dropdown`).should('contain', 'Action');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('#grid20 .slick-header-columns-right .slick-header-column').should('have.length', 2);
+ cy.get('#grid20 .slick-header-columns-right [data-id="cityOfOrigin"]').should('contain', 'City of Origin');
+ cy.get('#grid20 .slick-header-columns-right [data-id="action"]').should('contain', 'Action');
+ cy.get('#grid20 .slick-headerrow-columns-right .slick-headerrow-column').should('have.length', 2);
+ cy.get('#grid20 .slick-headerrow-columns-right .slick-headerrow-column.l7 input').should('exist');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ setRightPinning(1);
+ });
+
+ it('should keep multiple right-pinned columns fixed while scrolling', () => {
+ setRightPinning(2);
+ // The default fixture fits in the viewport, so use the demo's wide layout
+ // to exercise an actual horizontal scroll rather than a no-op scroll.
+ cy.get('[data-test="set-large-pinned-columns"]').click();
+ const actionCell = '#grid20 .slick-row[data-row="10"] .slick-pinned-right-cells .slick-cell.l8';
+
+ cy.get(actionCell).then(($cell) => {
+ const rightEdge = $cell[0].getBoundingClientRect().right;
+ cy.get('#grid20 .slick-horizontal-scroller').scrollTo('right');
+ cy.get(actionCell).should(($scrolledCell) => {
+ expect(Math.abs($scrolledCell[0].getBoundingClientRect().right - rightEdge)).to.be.lessThan(2);
+ });
+ });
+
+ cy.get('#grid20 .slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ // Restore the initial fixture after exercising the wide layout so the
+ // following serial tests do not inherit resized columns.
+ cy.visit(`${Cypress.config('baseUrl')}/example20`);
+ });
+
+ it('should resize columns while left and right pinning are active', () => {
+ cy.visit(`${Cypress.config('baseUrl')}/example20`);
+
+ const resizeColumn = (columnSelector: string, pinClass: string) => {
+ cy.get(columnSelector).should('have.class', pinClass);
+ cy.get(`${columnSelector} .slick-resizable-handle`)
+ .should('exist')
+ .then(($handle) => {
+ const header = $handle.closest('.slick-header-column')[0] as HTMLElement;
+ const initialWidth = header.getBoundingClientRect().width;
+
+ cy.wrap($handle).trigger('mousedown', { which: 1, pageX: 100, clientX: 100, force: true });
+ cy.get('body').trigger('mousemove', { which: 1, pageX: 125, clientX: 125, force: true });
+ cy.get('body').trigger('mousemove', { which: 1, pageX: 150, clientX: 150, force: true });
+ cy.get('body').trigger('mouseup', { which: 1, pageX: 150, clientX: 150, force: true });
+
+ cy.get(columnSelector).should(($updatedHeader) => {
+ expect($updatedHeader[0].getBoundingClientRect().width).to.be.greaterThan(initialWidth);
+ });
+ });
+ };
+
+ resizeColumn('#grid20 .slick-header-columns-left [data-id="title"]', 'slick-column-pinned-left');
+
+ // Use City of Origin because Action has a maxWidth of 100px and would refuse a wider resize.
+ setRightPinning(2);
+ resizeColumn('#grid20 .slick-header-columns-right [data-id="cityOfOrigin"]', 'slick-column-pinned-right');
+
+ // Keep the following serial tests on the demo's default configuration.
+ cy.visit(`${Cypress.config('baseUrl')}/example20`);
});
- it('should hide "Title" column from Grid Menu and expect last frozen column to be "% Complete"', () => {
- const newColumnList = [
- '#',
- '% Complete',
- 'Start',
- 'Finish',
- 'Cost | Duration',
- 'Effort Driven',
- 'Title 1',
- 'Title 2',
- 'Title 3',
- 'Title 4',
- ];
+ it('should disable and re-enable right pinning through the numeric grid control', () => {
+ setRightPinning(0);
+ cy.get('#grid20 .slick-row[data-row="0"] .slick-pinned-right-cells').should('exist');
+ cy.get('#grid20 .slick-row[data-row="0"] .slick-pinned-right-cells > .slick-cell').should('not.exist');
+ cy.get('#grid20 .slick-header-columns-right .slick-header-column').should('not.exist');
+
+ setRightPinning(1);
+ cy.get('#grid20 .slick-row[data-row="0"] .slick-pinned-right-cells > .slick-cell.l8').should('contain', 'Action');
+ cy.get('#grid20 .slick-header-columns-right [data-id="action"]').should('contain', 'Action');
+ });
+
+ it('should hide "Title" column from Grid Menu and expect last pinned column to be "% Complete"', () => {
+ const newColumnList = ['Sel', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ const row0 = '#grid20 .slick-row[data-row="0"]';
cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
cy.get('#grid20')
.get('.slick-grid-menu:visible')
.find('.slick-column-picker-list')
- .children('li:visible:nth(1)')
+ .children('li:visible:nth(0)')
.children('label')
.should('contain', 'Title')
.click({ force: true });
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
+ .find('.slick-header-columns .slick-header-column')
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 2 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 2);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 5);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').children().should('have.length', 1);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(0)`).should('contain', '2009-01-01');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(1)`).should('contain', '2009-05-05');
});
- it('should show again "Title" column from Grid Menu and expect last frozen column to still be "% Complete"', () => {
+ it('should show again "Title" column from Grid Menu and expect last pinned column to still be "% Complete"', () => {
cy.get('#grid20')
.get('.slick-grid-menu:visible')
.find('.slick-column-picker-list')
- .children('li:visible:nth(1)')
+ .children('li:visible:nth(0)')
.children('label')
.should('contain', 'Title')
.click({ force: true });
@@ -104,77 +174,60 @@ describe('Example 20 - Frozen Grid', () => {
cy.get('#grid20').get('.slick-grid-menu:visible').find('.close').click({ force: true });
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 3);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 5);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').children().should('have.length', 1);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ cy.get('.slick-scrolling-cells .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-scrolling-cells .slick-cell:nth(1)').should('contain', '2009-05-05');
});
- it('should hide "Title" column from Header Menu and expect last frozen column to be "% Complete"', () => {
- const newColumnList = [
- '#',
- '% Complete',
- 'Start',
- 'Finish',
- 'Cost | Duration',
- 'Effort Driven',
- 'Title 1',
- 'Title 2',
- 'Title 3',
- 'Title 4',
- ];
+ it('should hide "Title" column from Header Menu and expect last pinned column to be "% Complete"', () => {
+ const newColumnList = ['Sel', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
- cy.get('#grid20')
- .find('.slick-header-column:nth(1)')
- .trigger('mouseover')
- .children('.slick-header-menu-button')
- .should('be.hidden')
- .invoke('show')
- .click();
+ cy.get('#grid20').find('.slick-header-column:nth(1)').trigger('mouseover').children('.slick-header-menu-button').invoke('show').click();
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(8)')
+ .children('.slick-menu-item:nth-of-type(9)')
.children('.slick-menu-content')
.should('contain', 'Hide Column')
.click();
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
+ .find('.slick-header-columns .slick-header-column')
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 2 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 2);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 5);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').children().should('have.length', 1);
+
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ });
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ it('should toggle right pinned column and expect only 2 left/center containers to be visible', () => {
+ cy.get('[data-test="toggle-pinned-right"]').click();
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 2);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 6);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').should('exist').and('not.have.class', 'slick-pinned-right-cells-active');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells > .slick-cell').should('not.exist');
});
- it('should show again "Title" column from Column Picker and expect last frozen column to still be "% Complete"', () => {
- cy.get('#grid20').find('.slick-header-column:nth(5)').trigger('mouseover').trigger('contextmenu').invoke('show');
+ it('should show again "Title" column from Column Picker and expect last pinned column to still be "% Complete"', () => {
+ cy.get('#grid20').find('.slick-header-column:nth(4)').trigger('mouseover').trigger('contextmenu').invoke('show');
cy.get('.slick-column-picker')
.find('.slick-column-picker-list')
- .children('li:nth-child(2)')
+ .children('li:nth-of-type(2)')
.children('label')
.should('contain', 'Title')
.click();
@@ -182,83 +235,769 @@ describe('Example 20 - Frozen Grid', () => {
cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 3);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 6);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(1)').should('contain', '2009-05-05');
});
- it('should click on the "Remove Frozen Columns" button to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
- cy.get('[data-test=remove-frozen-column-button]').click({ force: true });
+ it('should click on the "Remove Pinned Columns" button to switch to a regular grid view without pinned columns and expect 7 columns on the left container', () => {
+ cy.get('[data-test=remove-pinned-column-button]').click({ force: true });
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 1 * 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 11 * 2);
+ cy.get('#grid20 .slick-row[data-row="0"]').should('have.length.at.least', 1);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').should('exist').and('not.have.class', 'slick-pinned-left-cells-active');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell').should('have.length', 9);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ getCell(0, 0).should('contain', '');
+ getCell(0, 1).should('contain', 'Task 0');
+ getCell(0, 3).should('contain', '2009-01-01');
+ getCell(0, 4).should('contain', '2009-05-05');
+ });
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(3)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '2009-05-05');
+ it('should expect to have exact Column Header Titles in the grid', () => {
+ cy.get('#grid20')
+ .find('.slick-header-columns:nth(0) .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
- it('should have exact Column Header Titles in the grid', () => {
+ it('should click on the "Set 3 Pinned Columns" button to switch pinned columns grid and expect 3 pinned columns on the left and 4 columns on the right', () => {
+ cy.get('[data-test=set-3pinned-columns]').click({ force: true });
+
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 3);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 6);
+
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(1)').should('contain', 'Task 0');
+
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ });
+
+ it('should recheck again and still have exact Column Header Titles in the grid', () => {
cy.get('#grid20')
- .find('.slick-header-columns:nth(0)')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns:nth(0) .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
- it('should click on the "Set 3 Frozen Columns" button to switch frozen columns grid and expect 3 frozen columns on the left and 4 columns on the right', () => {
- cy.get('[data-test=set-3frozen-columns]').click({ force: true });
+ it('should click on the Grid Menu command "Unpin Columns/Rows" to switch to a regular grid without pinned columns/rows', () => {
+ cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2 * 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.contains('Unpin Columns/Rows').click({ force: true });
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('#grid20 .slick-row[data-row="0"]').should('have.length.at.least', 1);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').should('exist').and('not.have.class', 'slick-pinned-left-cells-active');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell').should('have.length', 9);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ getCell(0, 0).should('contain', '');
+ getCell(0, 1).should('contain', 'Task 0');
+ getCell(0, 3).should('contain', '2009-01-01');
+ getCell(0, 4).should('contain', '2009-05-05');
});
- it('should have exact Column Header Titles in the grid', () => {
+ it('should open the Cell Menu on 2nd and 3rd row and change the Effort-Driven to "True" and expect the cell to be updated and have checkmark icon', () => {
+ getCell(1, 1).should('contain', 'Task 1');
+ getCell(1, 8).find('.checkmark-icon').should('have.length', 0);
+ getCell(2, 1).should('contain', 'Task 2');
+ getCell(2, 8).find('.checkmark-icon').should('have.length', 0);
+
+ getCell(1, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('True').click();
+ getCell(2, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('True').click();
+
+ getCell(1, 5).find('.checkmark-icon').should('have.length', 1);
+ getCell(2, 5).find('.checkmark-icon').should('have.length', 1);
+ });
+
+ it('should open the Cell Menu on 2nd and 3rd row and change the Effort-Driven to "False" and expect the cell to be updated and no longer have checkmark', () => {
+ getCell(1, 5).find('.checkmark-icon').should('have.length', 1);
+ getCell(2, 5).find('.checkmark-icon').should('have.length', 1);
+
+ getCell(1, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('False').click();
+ getCell(2, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('False').click();
+
+ getCell(1, 5).find('.checkmark-icon').should('have.length', 0);
+ getCell(2, 5).find('.checkmark-icon').should('have.length', 0);
+ });
+
+ it('should open the Cell Menu and delete Row 3 and 4 from the Cell Menu', () => {
+ cy.window().then((win) => {
+ const stub = cy.stub(win, 'confirm').returns(true);
+ cy.wrap(stub).as('confirmStub');
+ });
+
+ getCell(3, 1).should('contain', 'Task 3');
+ getCell(4, 1).should('contain', 'Task 4');
+
+ getCell(3, 8).contains('Action').click({ force: true });
+
+ cy.get('.slick-cell-menu .slick-menu-command-list .slick-menu-item').contains('Delete Row').click();
+ cy.get('@confirmStub').should('have.been.calledWith', 'Do you really want to delete row (4) with "Task 3"?');
+ getCell(3, 1).should('contain', 'Task 4');
+ });
+
+ it.skip('should filter autocomplete by typing Vancouver in the "City of Origin" and expect only filtered rows to show up', () => {
+ cy.get('.search-filter.filter-cityOfOrigin').type('Vancouver');
+
+ cy.get('.slick-autocomplete').should('be.visible');
+ cy.get('.slick-autocomplete div').should('have.length', 2);
+ cy.get('.slick-autocomplete').find('div:nth(0)').click();
+
+ getCell(0, 1).should('contain', 'Task 1');
+ getCell(1, 1).should('contain', 'Task 5');
+ getCell(2, 1).should('contain', 'Task 7');
+ getCell(3, 1).should('contain', 'Task 9');
+ getCell(4, 1).should('contain', 'Task 11');
+ });
+
+ it('should Clear all Filters', () => {
+ cy.get('#grid20').find('button.slick-grid-menu-button').trigger('click').click({ force: true });
+
+ cy.get(`.slick-grid-menu:visible`).find('.slick-menu-item').first().find('span').contains('Clear all Filters').click();
+ });
+
+ it.skip('should edit first row (Task 1) and change its city by choosing it inside the autocomplete editor list', () => {
+ getCell(0, 7).click();
+ cy.get('input.autocomplete.editor-cityOfOrigin').type('Sydney');
+
+ cy.get('.slick-autocomplete').should('be.visible');
+ cy.get('.slick-autocomplete div').should('have.length', 3);
+ cy.get('.slick-autocomplete').find('div:nth(1)').click();
+
+ getCell(0, 1).should('contain', 'Task 0');
+ getCell(0, 7).should('contain', 'Sydney, NS, Australia');
+ });
+
+ it('should open Context Menu hover "% Complete" column then select "Not Started (0%)" option and expect Task to be at 0', () => {
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu .slick-menu-option-list').should('exist').contains('Not Started (0%)').click();
+
+ getCell(0, 2).should('contain', '0');
+ });
+
+ it('should reopen Context Menu hover "% Complete" column then open options sub-menu & select "Half Completed (50%)" option and expect Task to be at 50', () => {
+ const subOptions = ['Not Started (0%)', 'Half Completed (50%)', 'Completed (100%)'];
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-option-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Sub-Options (demo)')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-option-list').as('subMenuList');
+ cy.get('@subMenuList').find('.slick-menu-title').contains('Set Percent Complete');
+ cy.get('@subMenuList')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.eq(subOptions[index]));
+
+ cy.get('@subMenuList').find('.slick-menu-item .slick-menu-content').contains('Half Completed (50%)').click();
+
+ getCell(0, 2).should('contain', '50');
+ });
+
+ it('should be able to open Context Menu and click on Export->Text and expect alert triggered with Text Export', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list').find('.slick-menu-item').contains('Text').click();
+ cy.get('@alertStub').should('have.been.calledWith', 'Exporting as Text (tab delimited)');
+ });
+
+ it('should be able to open Context Menu and click on Export->Excel-> sub-commands to see 1 context menu + 1 sub-menu then clicking on Text should call alert action', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ const subCommands2 = ['Excel (csv)', 'Excel (xlsx)'];
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Excel')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list').as('subMenuList2');
+
+ cy.get('@subMenuList2').find('.slick-menu-title').contains('available formats');
+
+ cy.get('@subMenuList2')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Excel (xlsx)')
+ .click();
+ cy.get('@alertStub').should('have.been.calledWith', 'Exporting as Excel (xlsx)');
+ });
+
+ it('should open Export->Excel sub-menu & open again Sub-Options on top and expect sub-menu to be recreated with that Sub-Options list instead of the Export->Excel list', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ const subCommands2 = ['Excel (csv)', 'Excel (xlsx)'];
+ const subOptions = ['Not Started (0%)', 'Half Completed (50%)', 'Completed (100%)'];
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Excel')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-option-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Sub-Options')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-option-list').as('optionSubList2');
+
+ cy.get('@optionSubList2').find('.slick-menu-title').contains('Set Percent Complete');
+
+ cy.get('@optionSubList2')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($option, index) => expect($option.text()).to.contain(subOptions[index]));
+ });
+
+ it('should open Export->Excel context sub-menu then open Feedback->ContactUs sub-menus and expect previous Export menu to no longer exists', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ const subCommands2 = ['Request update from supplier', '', 'Contact Us'];
+ const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment'];
+
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick({ force: true });
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ // click different sub-menu
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Feedback')
+ .should('exist')
+ .click();
+
+ cy.get('.slick-submenu').should('have.length', 1);
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
+
+ // click on Feedback->ContactUs
+ cy.get('.slick-context-menu.slick-menu-level-1.dropright') // right align
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Contact Us')
+ .should('exist')
+ .trigger('mouseover'); // mouseover or click should work
+
+ cy.get('.slick-submenu').should('have.length', 2);
+ cy.get('.slick-context-menu.slick-menu-level-2.dropright') // right align
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-2');
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Chat with us')
+ .click();
+ cy.get('@alertStub').should('have.been.calledWith', 'Command: contact-chat');
+
+ cy.get('.slick-submenu').should('have.length', 0);
+ });
+
+ it('should toggle Select All checkbox and expect back "Sel" column title to show when Select All checkbox is shown in the header row', () => {
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('contain', 'Sel');
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
+
+ cy.get('[data-test="toggle-select-all-row"]').click();
+
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('not.contain', 'Sel');
+
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withoutTitleRowTitles[index]));
+ });
+
+ it('should toggle back Select All checkbox and expect back "Sel" column title to show when Select All checkbox is shown in the header row', () => {
+ cy.get('[data-test="toggle-select-all-row"]').click();
+
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('contain', 'Sel');
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
+
+ cy.get('[data-test="toggle-select-all-row"]').click();
+
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('not.contain', 'Sel');
+
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withoutTitleRowTitles[index]));
+ });
+
+ it('should open Column Picker and try unchecked all the columns on the right of the column pinning and expect an error and abort of the execution', () => {
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+ cy.get('[data-test=set-3pinned-columns]').click({ force: true });
+
+ const leftColumns = ['', 'Title', '% Complete'];
+ const rightColumns = ['Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ cy.get('#grid20').find('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+
+ cy.get('.slick-column-picker')
+ .find('.slick-column-picker-list')
+ .children()
+ .each(($child, index) => {
+ if (index >= leftColumns.length) {
+ if ($child.text() === rightColumns[index - leftColumns.length]) {
+ expect($child.text()).to.eq(rightColumns[index - leftColumns.length]);
+ if (index <= rightColumns.length + 1) {
+ cy.wrap($child).children('label').click();
+ } else {
+ cy.wrap($child)
+ .children('label')
+ .click()
+ .then(() => {
+ cy.get('@alertStub').should(
+ 'have.been.calledWith',
+ '[SlickGrid] Action not allowed and aborted, you need to have at least one or more column in the center section of the grid. ' +
+ 'You could alternatively unpin columns before trying again.'
+ );
+ });
+ }
+ }
+ }
+ });
+
+ cy.get('button[data-dismiss="slick-column-picker"]').click();
+ });
+
+ it('should also not be able to "Hide Column" via the Header Menu', () => {
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+ const newColumnList = ['', 'Title', '% Complete', 'Action'];
+
+ cy.get('#grid20').find('.slick-header-column:nth(3)').trigger('mouseover').children('.slick-header-menu-button').invoke('show').click();
+
+ cy.get('.slick-header-menu .slick-menu-command-list')
+ .should('be.visible')
+ .children('.slick-menu-item')
+ .contains('Hide Column')
+ .click()
+ .then(() => {
+ cy.get('@alertStub').should(
+ 'have.been.calledWith',
+ '[SlickGrid] Action not allowed and aborted, you need to have at least one or more column in the center section of the grid. ' +
+ 'You could alternatively unpin columns before trying again.'
+ );
+ });
+
cy.get('#grid20')
- .find('.slick-header-columns:nth(0)')
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
+ });
+
+ it('should be able to uncheck "Title" column without any alert', () => {
+ cy.get('#grid20').find('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+ const updatedColumns = ['', '% Complete', 'Action'];
+ cy.get('.slick-column-picker-list li:not(.hidden) .checkbox-picker-label').first().click();
+ cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
+ cy.get('.slick-header-columns:nth(0) .slick-header-column').each(($child, index) => expect($child.text()).to.eq(updatedColumns[index]));
+ });
+
+ it('should be able to add back hidden "Title" column without any alert', () => {
+ const updatedColumns = ['', 'Title', '% Complete', 'Action'];
+ cy.get('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+ cy.get('.slick-column-picker-list li:not(.hidden) .checkbox-picker-label').first().click();
+ cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
+ cy.get('.slick-header-columns:nth(0) .slick-header-column').each(($child, index) => expect($child.text()).to.eq(updatedColumns[index]));
+ });
+
+ it('should reset hidden column from the Column Picker and expect all columns to be back', () => {
+ const leftColumns = ['', 'Title', '% Complete'];
+ const rightColumns = ['Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+
+ cy.get('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+ cy.get('.slick-column-picker')
+ .find('.slick-column-picker-list')
.children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .each(($child, index) => {
+ if (index >= leftColumns.length) {
+ if ($child.text() === rightColumns[index - leftColumns.length]) {
+ expect($child.text()).to.eq(rightColumns[index - leftColumns.length]);
+ if (index <= rightColumns.length + 1) {
+ cy.wrap($child).children('label').click();
+ }
+ }
+ }
+ });
+
+ cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
+
+ cy.get('#grid20')
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withoutTitleRowTitles[index]));
});
- it('should click on the Grid Menu command "Unfreeze Columns/Rows" to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
- cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
+ describe('Test UI rendering after Scrolling with large columns', () => {
+ it('should unpin all columns/rows', () => {
+ cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
+
+ cy.contains('Unpin Columns/Rows').click({ force: true });
+ });
+
+ it('should resize all columns and make them wider', () => {
+ // resize CityOfOrigin column
+ cy.get('.slick-header-columns .slick-header-column:nth(7)').should('contain', 'City of Origin');
+
+ cy.get('.slick-resizable-handle:nth(7)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(8)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
- cy.contains('Unfreeze Columns/Rows').click({ force: true });
+ // resize Cost|Duration column
+ cy.get('.slick-header-columns .slick-header-column:nth(6)').should('contain', 'Cost | Duration');
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 1);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 11);
+ cy.get('.slick-resizable-handle:nth(6)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('.slick-header-column:nth(8)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Completed column
+ cy.get('.slick-header-columns .slick-header-column:nth(5)').should('contain', 'Completed');
+
+ cy.get('.slick-resizable-handle:nth(5)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(7)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Finish column
+ cy.get('.slick-header-columns .slick-header-column:nth(4)').should('contain', 'Finish');
+
+ cy.get('.slick-resizable-handle:nth(4)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(6)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Start column
+ cy.get('.slick-header-columns .slick-header-column:nth(3)').should('contain', 'Start');
+
+ cy.get('.slick-resizable-handle:nth(3)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(6)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize %Complete column
+ cy.get('.slick-header-columns .slick-header-column:nth(2)').should('contain', '% Complete');
+
+ cy.get('.slick-resizable-handle:nth(2)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(3)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Title column
+ cy.get('.slick-header-columns .slick-header-column:nth(1)').should('contain', 'Title');
+
+ cy.get('.slick-resizable-handle:nth(1)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(3)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+ });
+
+ it('should scroll horizontally completely to the right and expect all cell to be rendered', () => {
+ getCell(2, 1).contains(/Task [0-9]*/);
+ getCell(2, 2).contains(/[0-9]*/);
+
+ getCell(15, 1).contains(/Task [0-9]*/);
+ getCell(15, 2).contains(/[0-9]*/);
+
+ // horizontal scroll to right
+ // Pinning has one real horizontal scroll owner. Scrolling the old body
+ // viewport only exercises the compatibility bridge; target the proxy
+ // here to verify the user-facing scrollbar and all chrome move together.
+ cy.get('#grid20 .slick-horizontal-scroller').scrollTo('100%', '0%', { duration: 1500 });
+ getCell(2, 3).should('contain', '2009-01-01');
+ getCell(2, 4).should('contain', '2009-05-05');
+ getCell(2, 7).contains(/[United State|Canada]*/);
+ getCell(2, 8).should('contain', 'Action');
+
+ getCell(15, 3).should('contain', '2009-01-01');
+ getCell(15, 4).should('contain', '2009-05-05');
+ getCell(15, 7).contains(/[United State|Canada]*/);
+ getCell(15, 8).should('contain', 'Action');
+ });
+
+ it('should scroll vertically to the middle of the grid and expect all cell to be rendered', () => {
+ // vertical scroll to middle
+ cy.get('.slick-vertical-scroller').scrollTo('0%', '40%', { duration: 1500 });
+
+ getCell(200, 3).should('contain', '2009-01-01');
+ getCell(200, 4).should('contain', '2009-05-05');
+ getCell(200, 7).contains(/[United State|Canada]*/);
+ getCell(200, 8).should('contain', 'Action');
+
+ getCell(205, 3).should('contain', '2009-01-01');
+ getCell(205, 4).should('contain', '2009-05-05');
+ getCell(205, 7).contains(/[United State|Canada]*/);
+ getCell(205, 8).should('contain', 'Action');
+
+ // reset scroll
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ });
+ });
+
+ describe('accessibility sub-menus tests', () => {
+ beforeEach(() => {
+ // Open the context menu on a cell to start each test
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('[data-row="0"] .slick-cell.l3.r3').rightclick({ force: true });
+ cy.get('.slick-context-menu.slick-menu-level-0').should('be.visible');
+ });
+
+ it('should open Exports sub-menu with ArrowRight, then Excel sub-menu with ArrowRight, and close with ArrowLeft', () => {
+ // Move down to "Exports" (4th item)
+ cy.focused();
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-submenu-item[data-command="export"]').should('have.focus');
+
+ // Open "Exports" sub-menu with ArrowRight
+ cy.focused().type('{rightarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-1[data-sub-menu-parent="export"]').should('be.visible');
+
+ // Move down to "Excel" (2nd item in sub-menu)
+ cy.focused().type('{downarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-submenu-item[data-command="sub-menu"]').should('have.focus');
+
+ // Open "Excel" sub-menu with ArrowRight
+ cy.focused().type('{rightarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-2[data-sub-menu-parent="sub-menu"]').should('be.visible');
+
+ // Move down to "Excel (xlsx)" (2nd item in Excel sub-menu)
+ cy.focused().type('{downarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-item[data-command="exports-xlsx"]').should('have.focus');
+
+ // Close Excel sub-menu with ArrowLeft
+ cy.focused().type('{leftarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-2').should('not.exist');
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-submenu-item[data-command="sub-menu"]').should('have.focus');
+
+ // close all context menus
+ cy.get('[data-row="0"] .slick-cell.l0.r0').click();
+ });
+
+ it('should open sub-menus using Enter as well as ArrowRight', () => {
+ // Move down to "Exports"
+ cy.focused();
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-submenu-item[data-command="export"]').should('have.focus');
+
+ // Open "Exports" sub-menu with Enter
+ cy.focused().type('{enter}');
+ cy.get('.slick-context-menu.slick-menu-level-1[data-sub-menu-parent="export"]').should('be.visible');
+
+ // Move down to "Excel"
+ cy.focused().type('{downarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-submenu-item[data-command="sub-menu"]').should('have.focus');
+
+ // Open "Excel" sub-menu with Enter
+ cy.focused().type('{enter}');
+ cy.get('.slick-context-menu.slick-menu-level-2[data-sub-menu-parent="sub-menu"]').should('be.visible');
+
+ // close all context menus
+ cy.get('[data-row="0"] .slick-cell.l0.r0').click();
+ });
+
+ it('should activate a sub-menu leaf item with Enter', () => {
+ // Move down to "Exports"
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+ cy.focused();
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.ENTER);
+ cy.get('.slick-context-menu.slick-menu-level-1[data-sub-menu-parent="export"]').should('be.visible');
+
+ // "Text (tab delimited)" is first item, should have focus
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-item[data-command="exports-txt"]').should('have.focus');
+ // Activate with Enter (add your assertion for the result)
+ cy.focused().type('{enter}');
+ });
+
+ it('should reapply 3 Pinned Columns and expect to be able to focus on first filter and go left/right between both viewports without problems', () => {
+ cy.get('[data-test="set-3pinned-columns"]').click();
+ cy.get('.slick-headerrow-column.l1 input').focus();
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l2 input').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l3 select').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l3 input').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l4 select').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l4 input').should('have.focus');
+
+ // Shift+Tab dosn't work in Cypress, so we can't go further with tests
+ });
+ });
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(3)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '2009-05-05');
+ describe('drag & drop column reordering with auto-scroll', () => {
+ it('should auto-scroll right viewport and reorder columns when "Start" is dragged well past the right edge (ending up after "Finish")', () => {
+ // Close the context menu opened by beforeEach
+ cy.get('body').type('{esc}');
+
+ // Control app timers to make drag auto-scroll deterministic in CI.
+ cy.clock();
+
+ // Normalize right viewport scroll so this test is isolated from previous test state.
+ cy.get('.slick-horizontal-scroller').then(($viewport) => {
+ $viewport[0].scrollLeft = 0;
+ $viewport[0].dispatchEvent(new Event('scroll', { bubbles: true }));
+ });
+ cy.get('.slick-horizontal-scroller').its('0.scrollLeft').should('equal', 0);
+ cy.get('[data-test="set-large-pinned-columns"]').click();
+
+ // Step 1: call SortableJS onStart for the "Start" column (1st center-section column).
+ // This binds the document 'drag' auto-scroll listener for the shared proxy scrollbar.
+ cy.get('.slick-header-columns-center').then(($rightHeader) => {
+ let sortInstance: any;
+ Object.keys($rightHeader[0]).forEach((prop) => {
+ if (prop.startsWith('Sortable')) {
+ sortInstance = ($rightHeader[0] as any)[prop];
+ }
+ });
+ expect(sortInstance).to.exist;
+ const startColumnEl = $rightHeader[0].querySelectorAll('.slick-header-column')[0] as HTMLElement;
+ sortInstance.options.onStart({ item: startColumnEl });
+ });
+
+ // Step 2: fire a document drag event well past the right edge (viewport-relative)
+ // to avoid CI flakiness caused by environment-dependent viewport widths.
+ cy.window().then((win) => {
+ const dragX = win.innerWidth + 1200;
+ cy.document().trigger('drag', { pageX: dragX, clientX: dragX, clientY: 50 });
+ });
+
+ // Step 3: advance mocked time so the 30ms scroll interval ticks several times.
+ cy.tick(350);
+
+ // Auto-scroll should have moved the right viewport to the right
+ cy.get('.slick-horizontal-scroller').its('0.scrollLeft').should('be.greaterThan', 0);
+
+ // Step 4: simulate the drag result — "Start" was moved to the right, past "Finish".
+ // SortableJS reads the DOM order via toArray() inside onEnd, so physically reorder the children first.
+ cy.get('.slick-header-columns-center').then(($rightHeader) => {
+ let sortInstance: any;
+ Object.keys($rightHeader[0]).forEach((prop) => {
+ if (prop.startsWith('Sortable')) {
+ sortInstance = ($rightHeader[0] as any)[prop];
+ }
+ });
+ expect(sortInstance).to.exist;
+ const startColumnEl = $rightHeader[0].querySelector('[data-id="start"]') as HTMLElement;
+ const finishColumnEl = $rightHeader[0].querySelector('[data-id="finish"]') as HTMLElement;
+ expect(startColumnEl).to.exist;
+ expect(finishColumnEl).to.exist;
+
+ // Move "Finish" before "Start" → mirrors dragging Start past Finish
+ $rightHeader[0].insertBefore(finishColumnEl, startColumnEl);
+
+ // onEnd reads the new DOM order via toArray() and calls setColumns() if the order changed
+ sortInstance.options.onEnd({ item: startColumnEl, stopPropagation: () => {} });
+ });
+
+ // The center region should now place Finish before Start. The exact
+ // region membership can vary when a large requested pin band does not
+ // fit the current viewport, so assert semantic order by column id.
+ cy.get('.slick-header-column').then(($headers) => {
+ const ids = [...$headers].map((header) => header.dataset.id);
+ expect(ids.indexOf('finish')).to.be.lessThan(ids.indexOf('start'));
+ });
+
+ // When a left band is active, its order must remain unchanged.
+ cy.get('.slick-header-columns-left').then(($leftRegion) => {
+ const left = $leftRegion.find('.slick-header-column');
+ if (left.length) {
+ expect([...left].map((header) => header.dataset.id)).to.deep.equal(['_checkbox_selector', 'title', 'percentComplete']);
+ }
+ });
+ });
});
});
diff --git a/demos/aurelia/test/cypress/e2e/example24.cy.ts b/demos/aurelia/test/cypress/e2e/example24.cy.ts
index c2ea74764b..b73ab056b1 100644
--- a/demos/aurelia/test/cypress/e2e/example24.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example24.cy.ts
@@ -232,7 +232,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => {
});
it('should check Context Menu "menuUsabilityOverride" condition and expect to not be able to open Context Menu from rows than are >= to Task 21', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('bottom').wait(25);
+ cy.get('.slick-vertical-scroller').scrollTo('bottom').wait(25);
cy.get('#grid24').find('.slick-row:nth(3) .slick-cell:nth(1)').rightclick({ force: true });
@@ -240,7 +240,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => {
});
it('should scroll back to top row and be able to open Context Menu', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top').wait(25);
+ cy.get('.slick-vertical-scroller').scrollTo('top').wait(25);
cy.get('#grid24').find('.slick-row:nth(1) .slick-cell:nth(1)').rightclick({ force: true });
diff --git a/demos/aurelia/test/cypress/e2e/example27.cy.ts b/demos/aurelia/test/cypress/e2e/example27.cy.ts
index 8b76749726..28873fbf4b 100644
--- a/demos/aurelia/test/cypress/e2e/example27.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example27.cy.ts
@@ -160,7 +160,7 @@ describe('Example 27 - Tree Data (from a flat dataset with parentId references)'
it('should be able to update the 1st row item (Task 0)', () => {
cy.get('[data-test=update-item-btn]').contains('Update 1st Row Item').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
const now = new Date();
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
@@ -201,7 +201,7 @@ describe('Example 27 - Tree Data (from a flat dataset with parentId references)'
cy.get(`.slick-grid-menu:visible`).find('.slick-menu-item').first().find('span').contains('Clear all Filters').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
});
it('should be able to open "Task 1" and "Task 3" parents', () => {
diff --git a/demos/aurelia/test/cypress/e2e/example28.cy.ts b/demos/aurelia/test/cypress/e2e/example28.cy.ts
index 8f8f5e2228..123830953d 100644
--- a/demos/aurelia/test/cypress/e2e/example28.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example28.cy.ts
@@ -84,7 +84,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
it('should expand "pdf" folder and expect all folders to be expanded', () => {
cy.get('[data-row="4"] > .slick-cell:nth(0) .slick-group-toggle.collapsed').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('top', { force: true } as any);
});
it('should have default Files list', () => {
@@ -97,7 +97,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with aggregations of Sum(53.3MB) / Avg(26.65MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('center', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('center', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 151.3 MB / avg: 50.43 MB');
@@ -118,7 +118,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with updated aggregations including new pop songs of Sum(218.3MB) / Avg(54.58MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 316.3 MB / avg: 63.26 MB');
@@ -225,7 +225,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with updated aggregations including 4 pop songs of Sum(400.3MB) / Avg(66.72MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 400.3 MB / avg: 66.72 MB');
@@ -308,7 +308,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have again the pop songs folder with updated aggregations including 4 pop songs of Sum(400.3MB) / Avg(66.72MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('center', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('center', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 400.3 MB / avg: 66.72 MB');
@@ -336,7 +336,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with aggregation reflecting what is displayed, Sum(316.3MB) / Avg(63.26MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('center', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('center', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 316.3 MB / avg: 63.26 MB');
@@ -347,7 +347,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have documents with same Sum as the beginning since auto-recalc is disabled, aggregation should be Sum(14.46MB) / Avg(1.45MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('top', { force: true } as any);
cy.get('[data-row="1"] > .slick-cell:nth(0)').should('contain', 'documents');
cy.get('[data-row="1"] > .slick-cell:nth(3)').should('contain', 'sum: 14.46 MB / avg: 1.45 MB (total)');
diff --git a/demos/aurelia/test/cypress/e2e/example38.cy.ts b/demos/aurelia/test/cypress/e2e/example38.cy.ts
index a179cdc5cb..02b700180d 100644
--- a/demos/aurelia/test/cypress/e2e/example38.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example38.cy.ts
@@ -20,7 +20,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -32,7 +32,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a new total of 90 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '60');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '90');
@@ -48,7 +48,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
cy.get('[data-test="data-loaded-tag"]').should('not.have.class', 'fully-loaded');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '100');
@@ -78,7 +78,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom again and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -104,7 +104,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom again and expect next batch to be only 20 females appended to current dataset for a total of 50 items found in DB', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '50');
@@ -119,7 +119,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-test=odata-query-result]').should(($span) => {
expect($span.text()).to.eq(`$count=true&$top=30`);
@@ -130,11 +130,11 @@ describe('Example 38 - Infinite Scroll with OData', () => {
});
it('should scroll to the bottom "Group by Gender" and expect 30 more items for a total of 60 items grouped', () => {
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-test=odata-query-result]').should(($span) => {
expect($span.text()).to.eq(`$count=true&$top=30&$skip=30`);
diff --git a/demos/aurelia/test/cypress/e2e/example39.cy.ts b/demos/aurelia/test/cypress/e2e/example39.cy.ts
index d7091726f6..a87b8ef667 100644
--- a/demos/aurelia/test/cypress/e2e/example39.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example39.cy.ts
@@ -29,7 +29,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -44,7 +44,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a new total of 90 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '60');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '90');
@@ -63,7 +63,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
cy.get('[data-test="data-loaded-tag"]').should('not.have.class', 'fully-loaded');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '100');
@@ -100,7 +100,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom again and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -135,7 +135,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom again and expect next batch to be only 20 females appended to current dataset for a total of 50 items found in DB', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '50');
diff --git a/demos/aurelia/test/cypress/e2e/example40.cy.ts b/demos/aurelia/test/cypress/e2e/example40.cy.ts
index 4f8eeb96e2..4ef56ccdec 100644
--- a/demos/aurelia/test/cypress/e2e/example40.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example40.cy.ts
@@ -25,14 +25,14 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
it('should scroll to bottom of the grid and expect next batch of 50 items appended to current dataset for a total of 100 items', () => {
cy.get('[data-test="totalItemCount"]').should('have.text', '50');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '100');
});
it('should scroll to bottom of the grid again and expect 50 more items for a total of now 150 items', () => {
cy.get('[data-test="totalItemCount"]').should('have.text', '100');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '150');
});
@@ -42,7 +42,7 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
cy.get('[data-id="title"]').click();
cy.get('[data-test="totalItemCount"]').should('have.text', '150');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0)').should('contain', 'Task 0');
cy.get('[data-row="1"] > .slick-cell:nth(0)').should('contain', 'Task 1');
@@ -55,7 +55,7 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
cy.get('[data-id="title"]').click();
cy.get('[data-test="totalItemCount"]').should('have.text', '50');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0)').should('contain', 'Task 9');
cy.get('[data-row="1"] > .slick-cell:nth(0)').should('contain', 'Task 8');
@@ -68,17 +68,17 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
cy.get('[data-test="totalItemCount"]').should('have.text', '50');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-toggle.expanded').should('have.length', 1);
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-title').contains(/Duration: [0-9]/);
});
it('should scroll to the bottom "Group by Duration" and expect 50 more items for a total of 100 items grouped', () => {
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '100');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-toggle.expanded').should('have.length', 1);
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-title').contains(/Duration: [0-9]/);
});
@@ -103,12 +103,12 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
it('should load 200 items and filter "Start" column with <=2020-08-25', () => {
cy.get('[data-test="set-dynamic-filter"]').click();
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '150');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '200');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get(`[data-row=0] > .slick-cell:nth(3)`).contains(/^Aug [0-9]{2}, 2020$/);
cy.get(`[data-row=1] > .slick-cell:nth(3)`).contains(/^Aug [0-9]{2}, 2020$/);
diff --git a/demos/aurelia/test/cypress/e2e/example43.cy.ts b/demos/aurelia/test/cypress/e2e/example43.cy.ts
index bfda594730..ca0c3b17cb 100644
--- a/demos/aurelia/test/cypress/e2e/example43.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example43.cy.ts
@@ -27,15 +27,23 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 0 },
cy.get('h2').should('contain', 'Example 43: colspan/rowspan - Employees Timesheets');
});
+ it('should hide sub-title', () => {
+ cy.get('[data-test=toggle-subtitle]').click();
+ });
+
it('should have exact column titles', () => {
cy.get('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should expect 1st column to be frozen (frozen)', () => {
- cy.get('.grid-canvas-left .slick-cell.frozen').should('have.length', 10);
- cy.get('.grid-canvas-right .slick-cell:not(.frozen)').should('have.length.above', 50);
+ it('should expect 1st column to be pinned', () => {
+ // Pinning uses one live canvas and splits each row into left/center/right
+ // regions; the old grid-canvas-left/right pinned panes no longer exist.
+ cy.get('.slick-pinned-left-cells .slick-cell.slick-cell-pinned-left').should('have.length', 10);
+ // The shared Vue Cypress viewport is 1200px wide, but its route sidebar
+ // leaves less room for center-column virtualization than the Vanilla app.
+ cy.get('.slick-scrolling-cells .slick-cell').should('have.length.above', 50);
});
it('should not display any Column Picker in the Grid Menu', () => {
@@ -47,32 +55,32 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 0 },
describe('Spanning', () => {
it('should expect "Davolio", "Check Mail", and "Development" to all have rowspan of 2 in morning hours', () => {
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should(($el) =>
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should(($el) =>
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
});
it('should expect "Lunch Break" to span over 3 columns and over all rows', () => {
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10)
);
});
it('should expect a large "Development" section that spans over multiple columns & rows in the afternoon', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should(($el) =>
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5)
);
});
@@ -80,334 +88,340 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 0 },
describe('Basic Key Navigations', () => {
it('should start at Employee 10001, then type "End" key and expect to be in "Team Meeting" between 4:30-5:00pm', () => {
- cy.get('[data-row=0] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l0.r0.active').should('contain', '10001');
+ cy.get('[data-row=0] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l0.r0.active').should('contain', '10001');
cy.get('@active_cell').type('{end}');
- cy.get('[data-row=0] > .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
});
it('should start at Employee 10002, then type "End" key and also expect to be in "Team Meeting" between 4:30-5:00pm', () => {
- cy.get('[data-row=1] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=1] > .slick-cell.l0.r0.active').should('contain', '10002');
+ cy.get('[data-row=1] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=1] .slick-cell.l0.r0.active').should('contain', '10002');
cy.get('@active_cell').type('{end}');
- cy.get('[data-row=0] > .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
});
it('should start at Employee 10004, then type "ArrowRight" key twice and expect to be in "Check Mail" between 9:00-10:30am', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}');
- cy.get('[data-row=2] > .slick-cell.l2.r4.active').should('contain', 'Check Mail');
+ cy.get('[data-row=2] .slick-cell.l2.r4.active').should('contain', 'Check Mail');
});
it('should start at Employee 10004, then type "ArrowRight" key 4x times and expect to be in "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}{rightarrow}{rightarrow}');
- cy.get('[data-row=3] > .slick-cell.l6.r9.active').should('contain', 'Testing');
+ cy.get('[data-row=3] .slick-cell.l6.r9.active').should('contain', 'Testing');
});
it('should start at Employee 10004, then type "ArrowRight" key 5x times and expect to be in "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}{rightarrow}{rightarrow}{rightarrow}');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, then type "ArrowRight" key 6x times and expect to be in "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}{rightarrow}{rightarrow}{rightarrow}{rightarrow}');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
// then rollback by going backward
it('should be on Employee 10004 row at previous "Development" cell, then type "ArrowLeft" key once and expect to be in "Lunch Break"', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).as('active_cell').click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ // The proxy scrollbar is a sibling of the canvas, so native
+ // scrollIntoView() cannot reveal a horizontally virtualized cell.
+ cy.get('.slick-horizontal-scroller').scrollTo('right', { ensureScrollable: false });
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).as('active_cell').scrollIntoView().click();
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
cy.get('@active_cell').type('{leftarrow}');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key once and expect to be in "Conference" between 4:00-5:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).type('{leftarrow}');
- cy.get(`[data-row=3] > .slick-cell.l16.r17.active`).should('contain', 'Conference');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).type('{leftarrow}');
+ cy.get(`[data-row=3] .slick-cell.l16.r17.active`).should('contain', 'Conference');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key 3x times and expect to be back to "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).type('{leftarrow}{leftarrow}{leftarrow}');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).type('{leftarrow}{leftarrow}{leftarrow}');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key 4x times and expect to be back to "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key 5x times and expect to be back to "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}');
- cy.get(`[data-row=3] > .slick-cell.l6.r9.active`).should('contain', 'Testing');
+ cy.get(`[data-row=3] .slick-cell.l6.r9.active`).should('contain', 'Testing');
});
// going down
it('should start at 10am "Team Meeting, then type "ArrowDown" key once and expect to be in "Support" between 9:30-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}');
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key twice and expect to be in "Check Email" between 9:00-10:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 3x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}');
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}');
- cy.get(`[data-row=5] > .slick-cell.l4.r6.active`).should('contain', 'Support');
+ cy.get(`[data-row=5] .slick-cell.l4.r6.active`).should('contain', 'Support');
});
// going up from inverse
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" once and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}');
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 2x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}{uparrow}');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 3x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}{uparrow}{uparrow}');
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 4x times and expect to be back to same "Team Meeting"', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}{uparrow}{uparrow}{uparrow}');
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
});
});
describe('Grid Navigate Functions', () => {
it('should start at Employee 10004, then type "Navigate Right" twice and expect to be in "Check Mail" between 9:00-10:30am', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
cy.get('[data-test="goto-next"]').click().click();
- cy.get('[data-row=2] > .slick-cell.l2.r4.active').should('contain', 'Check Mail');
+ cy.get('[data-row=2] .slick-cell.l2.r4.active').should('contain', 'Check Mail');
});
it('should start at Employee 10004, then type "Navigate Right" 4x times and expect to be in "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('[data-test="goto-next"]').click().click().click().click();
- cy.get('[data-row=3] > .slick-cell.l6.r9.active').should('contain', 'Testing');
+ cy.get('[data-row=3] .slick-cell.l6.r9.active').should('contain', 'Testing');
});
it('should start at Employee 10004, then type "Navigate Right" 5x times and expect to be in "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('[data-test="goto-next"]').click().click().click().click().click();
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, then type "Navigate Right" 6x times and expect to be in "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('[data-test="goto-next"]').click().click().click().click().click().click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
// then rollback by going backward
it('should be on Employee 10004 row at previous "Development" cell, then type "Navigate Left" once and expect to be in "Lunch Break"', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).as('active_cell').click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ cy.get('.slick-horizontal-scroller').scrollTo('right', { ensureScrollable: false });
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).as('active_cell').scrollIntoView().click();
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
cy.get('[data-test="goto-prev"]').click();
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" once and expect to be in "Conference" between 4:00-5:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click();
- cy.get(`[data-row=3] > .slick-cell.l16.r17.active`).should('contain', 'Conference');
+ cy.get(`[data-row=3] .slick-cell.l16.r17.active`).should('contain', 'Conference');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" 3x times and expect to be back to "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click().click().click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" 4x times and expect to be back to "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click().click().click().click();
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" 5x times and expect to be back to "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click().click().click().click().click();
- cy.get(`[data-row=3] > .slick-cell.l6.r9.active`).should('contain', 'Testing');
+ cy.get(`[data-row=3] .slick-cell.l6.r9.active`).should('contain', 'Testing');
});
// going down
it('should start at 10am "Team Meeting, then type "ArrowDown" key once and expect to be in "Support" between 9:30-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click();
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key twice and expect to be in "Check Email" between 9:00-10:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click();
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 3x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click();
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
- cy.get(`[data-row=5] > .slick-cell.l4.r6.active`).should('contain', 'Support');
+ cy.get(`[data-row=5] .slick-cell.l4.r6.active`).should('contain', 'Support');
});
// going up from inverse
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" once and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click();
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 2x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click().click();
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 3x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click().click().click();
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 4x times and expect to be back to same "Team Meeting"', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click().click().click().click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
});
});
describe('Grid Editing', () => {
it('should toggle editing', () => {
cy.get('#isEditable').contains('false');
- cy.get('[data-row=0] > .slick-cell.l4.r4').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active .editor-text').should('not.exist');
+ cy.get('[data-row=0] .slick-cell.l4.r4').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active .editor-text').should('not.exist');
cy.get('[data-test=toggle-editing]').click();
cy.get('#isEditable').contains('true');
- cy.get('[data-row=0] > .slick-cell.l4.r4').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active.editable .editor-text').should('exist');
- cy.get('[data-row=0] > .slick-cell.l4.r4.active.editable .editor-text').type('Team Meeting.xyz{enter}');
+ cy.get('[data-row=0] .slick-cell.l4.r4').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active.editable .editor-text').should('exist');
+ cy.get('[data-row=0] .slick-cell.l4.r4.active.editable .editor-text').type('Team Meeting.xyz{enter}');
});
// going down
it('should have changed active cell to "Support" between 9:30-11:00am', () => {
- cy.get('[data-row=1] > .slick-cell.l3.r5.active.editable .editor-text')
+ cy.get('[data-row=1] .slick-cell.l3.r5.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Support'));
- cy.get('[data-row=1] > .slick-cell.l3.r5.active.editable .editor-text').type('Support.xyz{enter}');
+ cy.get('[data-row=1] .slick-cell.l3.r5.active.editable .editor-text').type('Support.xyz{enter}');
});
it('should have changed active cell to "Check Email" between 9:00-10:30am', () => {
- cy.get('[data-row=2] > .slick-cell.l2.r4.active.editable .editor-text')
+ cy.get('[data-row=2] .slick-cell.l2.r4.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Check Mail'));
- cy.get('[data-row=2] > .slick-cell.l2.r4.active.editable .editor-text').type('Check Mail.xyz{enter}');
+ cy.get('[data-row=2] .slick-cell.l2.r4.active.editable .editor-text').type('Check Mail.xyz{enter}');
});
it('should have changed active cell to "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=4] > .slick-cell.l2.r5.active.editable .editor-text')
+ cy.get('[data-row=4] .slick-cell.l2.r5.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Task Assign'));
- cy.get('[data-row=4] > .slick-cell.l2.r5.active.editable .editor-text').type('Task Assign.xyz{enter}');
+ cy.get('[data-row=4] .slick-cell.l2.r5.active.editable .editor-text').type('Task Assign.xyz{enter}');
});
it('should have changed active cell to "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=5] > .slick-cell.l4.r6.active.editable .editor-text')
+ cy.get('[data-row=5] .slick-cell.l4.r6.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Support'));
- cy.get('[data-row=5] > .slick-cell.l4.r6.active.editable .editor-text').type('Support.xyz{enter}');
+ cy.get('[data-row=5] .slick-cell.l4.r6.active.editable .editor-text').type('Support.xyz{enter}');
});
it('should have changed active cell to "Testing" and cancel editing when typing "Escape" key', () => {
- cy.get('[data-row=6] > .slick-cell.l4.r4.active.editable .editor-text')
+ cy.get('[data-row=6] .slick-cell.l4.r4.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Testing'));
- cy.get('[data-row=6] > .slick-cell.l4.r4.active.editable .editor-text').type('{esc}');
- cy.get('[data-row=6] > .slick-cell.l4.r4.active.editable .editor-text').should('not.exist');
+ cy.get('[data-row=6] .slick-cell.l4.r4.active.editable .editor-text').type('{esc}');
+ cy.get('[data-row=6] .slick-cell.l4.r4.active.editable .editor-text').should('not.exist');
});
});
@@ -418,32 +432,32 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 0 },
});
it('should expect EmployeeID to follow columns at index 0 column index', () => {
- cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should('contain', 'Davolio');
- cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l0.r0.rowspan`).should('contain', 'Davolio');
+ cy.get(`[data-row=0] .slick-cell.l0.r0.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should('contain', 'Check Mail');
- cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should(($el) =>
+ cy.get(`[data-row=2] .slick-cell.l1.r3.rowspan`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l1.r3.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should(($el) =>
+ cy.get(`[data-row=8] .slick-cell.l6.r8.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=8] .slick-cell.l6.r8.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
});
it('should expect "Lunch Break" to be moved to the left by 1 index less', () => {
- cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should('contain', 'Lunch Break');
- cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l9.r11.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l9.r11.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10)
);
});
it('should expect "Development" to be moved to the left by 1 index less', () => {
- cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should(($el) =>
+ cy.get(`[data-row=1] .slick-cell.l12.r13.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l12.r13.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5)
);
});
@@ -455,32 +469,32 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 0 },
});
it('should expect EmployeeID to follow columns at index 1 column index', () => {
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should(($el) =>
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should(($el) =>
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
});
it('should expect "Lunch Break" to be moved to the right by 1 index less', () => {
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10)
);
});
it('should expect "Development" to be moved to the right by 1 index less and a large "Development" section that spans over multiple columns & rows in the afternoon', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should(($el) =>
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5)
);
});
diff --git a/demos/aurelia/test/cypress/e2e/example44.cy.ts b/demos/aurelia/test/cypress/e2e/example44.cy.ts
index 5d5bf6f477..451c07efd7 100644
--- a/demos/aurelia/test/cypress/e2e/example44.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example44.cy.ts
@@ -30,8 +30,14 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
cy.get('h2').should('contain', 'Example 44: colspan/rowspan with large dataset');
});
+ it('should hide sub-title', () => {
+ cy.get('[data-test=toggle-subtitle]').click();
+ });
+
it('should calculate a height that fits the wrapped Revenue Growth header', () => {
- cy.get('.slick-header-auto-height').should('have.length', 2);
+ // The pinning POC uses one live header instead of separate left/right
+ // header panes, so auto-height is applied to a single header element.
+ cy.get('.slick-header-auto-height').should('have.length', 1);
cy.get('.slick-header-auto-height')
.first()
.should(($header) => {
@@ -58,7 +64,7 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
let draggedColumn: HTMLElement;
cy.clock();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0).its('0.scrollLeft').should('equal', 0);
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0).its('0.scrollLeft').should('equal', 0);
cy.get('.slick-header-columns-left').then(($header) => {
const sortableProperty = Object.keys($header[0]).find((property) => property.startsWith('Sortable'));
@@ -75,12 +81,12 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
cy.tick(300);
- cy.get('.slick-viewport-top.slick-viewport-left').its('0.scrollLeft').should('be.greaterThan', 0);
+ cy.get('.slick-horizontal-scroller').its('0.scrollLeft').should('be.greaterThan', 0);
cy.then(() => sortInstance.options.onEnd({ item: draggedColumn, stopPropagation: () => {} }));
cy.get('.slick-header-column:nth(0)').should('contain', 'Title');
cy.get('.slick-header-column:nth(1)').should('contain', 'Revenue Growth');
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0);
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0);
});
it('should drag Title column to swap with 2nd column "Revenue Growth" in the grid and expect rowspan to stay at same position with Task 0 to spread instead', () => {
@@ -208,7 +214,7 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
it('should scroll to the right and still expect spans without any extra texts', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(400, 0).wait(10);
+ cy.get('.slick-horizontal-scroller').scrollTo(400, 0).wait(10);
cy.get(`[data-row=3] > .slick-cell:nth(1)`).contains(/\d+$/);
cy.get(`[data-row=3] > .slick-cell.l1.r2.rowspan`).should('exist');
@@ -229,7 +235,7 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
it('should scroll back to left and expect Task 8 to have 2 different spans (Revenue Grow: rowspan=80, Policy Index: rowspan=2000,colspan=2)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0).wait(10);
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0).wait(10);
cy.get(`[data-row=8] > .slick-cell.l0.r0`).should('contain', 'Task 8');
cy.get(`[data-row=8] > .slick-cell.l1.r1.rowspan`).should(($el) => {
@@ -350,6 +356,10 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
it('should start at RevenueGrowth column on first dashed cell, then type "Ctrl+End" then "Ctrl+Home" keys and expect active cell to go to bottom/top of grid on same column', () => {
+ // The preceding span/scroll cases share state. Reset both axes through
+ // the POC's actual scroll owners before interacting with the first row.
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0);
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0);
cy.get('[data-row=0] > .slick-cell.l2.r2').as('active_cell').click();
cy.get('[data-row=0] > .slick-cell.l2.r2.active').should('have.length', 1);
cy.get('@active_cell').type('{ctrl}{end}', { release: false });
diff --git a/demos/aurelia/test/cypress/e2e/example45.cy.ts b/demos/aurelia/test/cypress/e2e/example45.cy.ts
index 6f56e1a753..b4485b498b 100644
--- a/demos/aurelia/test/cypress/e2e/example45.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example45.cy.ts
@@ -224,9 +224,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
});
it('should scroll down when the row detail is just barely visible and then scroll back up and still expect same filters/sorting', () => {
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 350);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 350);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should('contain', '10281');
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(1)`).should('contain', 'Madrid');
@@ -236,9 +236,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
it('should scroll down by 2 pages down and then scroll back up and no longer the same filters/sorting', () => {
cy.get('#grid45 [data-row="0"] .slick-cell.r2.l2').first().click().type('{pagedown}');
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 2000);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 2000);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should(
'not.contain',
@@ -419,7 +419,7 @@ describe('Example 45 - Row Detail with inner Grid', () => {
cy.get('#grid45').type('{pageDown}{pageDown}', { release: false });
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 350);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 350);
// expect same grid details for both grids
// 2nd row detail
@@ -520,9 +520,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
});
it('should scroll far down (out of viewport) and back up and expect inner grid sort/filter state is PRESERVED (keepComponentAlive)', () => {
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 800);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 800);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
// state should be PRESERVED because keepComponentAlive is enabled
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should('contain', '10281');
@@ -532,9 +532,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
});
it('should scroll out of viewport a second time and back up and still expect inner grid sort/filter state is PRESERVED', () => {
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 800);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 800);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should('contain', '10281');
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(1)`).should('contain', 'Madrid');
diff --git a/demos/aurelia/test/cypress/e2e/example47.cy.ts b/demos/aurelia/test/cypress/e2e/example47.cy.ts
index 936cb3002e..3e5480a883 100644
--- a/demos/aurelia/test/cypress/e2e/example47.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example47.cy.ts
@@ -101,7 +101,7 @@ describe('Example 47 - Row Detail View + Grouping', () => {
cy.get('.detail-label label').should('contain', 'Assignee:');
cy.get('.detail-label input').should('exist');
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('.dynamic-cell-detail').find('[data-test=delete-btn]').click();
cy.get('.toast.text-bg-danger').contains(/Deleted row with Task [0-9]*/);
cy.get('.dynamic-cell-detail').should('have.length', 0);
@@ -112,7 +112,7 @@ describe('Example 47 - Row Detail View + Grouping', () => {
cy.on('window:alert', stub);
let assigneeName = '';
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="1"] > .slick-cell.l1').contains(/Task [0-9]*/);
cy.get('[data-row="1"] > .slick-cell.l0').click().wait(40);
diff --git a/demos/aurelia/test/cypress/e2e/example48.cy.ts b/demos/aurelia/test/cypress/e2e/example48.cy.ts
index 5e7f317681..329aac187e 100644
--- a/demos/aurelia/test/cypress/e2e/example48.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example48.cy.ts
@@ -153,7 +153,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
it('should auto scroll take effect to display the selecting element when dragging', { scrollBehavior: false }, () => {
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo('top');
testScroll('#grid48-1', '#grid48-1', 0, 1).then((scrollDistance: { cell: any; row: any }) => {
expect(scrollDistance.cell.scrollBefore).to.be.lte(scrollDistance.cell.scrollAfter);
@@ -161,11 +161,11 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
cy.get('#selectionRange1').contains(/"fromRow":0,"fromCell":1,"toRow":1[45],"toCell":3/);
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo(0, 13 * 35);
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo(0, 13 * 35);
});
it('should toggle multiple cell selection ranges with the checkbox', () => {
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo('top');
cy.get('[data-test="enable-multi-selection"]').check();
cy.get('#grid48-1 .slick-row[data-row="1"] .slick-cell.l1.r1').click();
@@ -201,7 +201,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
it('should preserve row and column offsets when copying multiple cell ranges', () => {
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo('top');
cy.get('[data-test="enable-multi-selection"]').should('be.checked');
cy.window().then((win) => {
cy.stub(win.navigator.clipboard, 'writeText').as('clipboardWriteText');
@@ -264,7 +264,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
cy.get('#selectionRange2').contains(/"fromRow":0,"fromCell":0,"toRow":1[0-9],"toCell":7/);
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo(0, 12 * 35);
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo(0, 12 * 35);
});
it('should click on a cell outside of the selected range and expect previous selection to remain', () => {
@@ -272,7 +272,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
cy.get('@task1x')
.contains(/Task 1[0-9]/)
.click();
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-cell.selected').should('have.length.gte', 60);
cy.get('#selectionRange2').contains(/"fromRow":0,"fromCell":0,"toRow":1[0-9],"toCell":7/);
});
@@ -284,20 +284,20 @@ describe('Example 48 - Hybrid Selection Model', () => {
it('should click on row 4 and 5 row checkbox and expect 5 full rows to be selected', () => {
cy.get('#grid48-2 .slick-row[data-row="4"] .slick-cell.l1.r1').should('contain', '4');
cy.get('#grid48-2 .slick-row[data-row="4"] input[type=checkbox]').click({ force: true });
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-row[data-row="4"] .slick-cell.l0.r0').should('have.class', 'selected');
cy.get('#grid48-2 .slick-cell.selected').should('have.length', 8 * 1);
// select another row
cy.get('#grid48-2 .slick-row[data-row="5"] .slick-cell.l1.r1').should('contain', '5');
cy.get('#grid48-2 .slick-row[data-row="5"] input[type=checkbox]').click({ force: true });
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-row[data-row="5"] .slick-cell.l0.r0').should('have.class', 'selected');
cy.get('#grid48-2 .slick-cell.selected').should('have.length', 8 * 2);
});
it('should toggle multiple row selection ranges with the checkbox', () => {
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-row[data-row="4"] input[type=checkbox]').uncheck({ force: true });
cy.get('#grid48-2 .slick-row[data-row="5"] input[type=checkbox]').uncheck({ force: true });
cy.get('[data-test="enable-multi-selection"]').should('be.checked');
@@ -321,7 +321,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
const secondRange = '{"fromRow":3,"fromCell":0,"toRow":4,"toCell":7}';
const combinedRanges = `${firstRange}${secondRange}`;
- cy.get(`${gridSelector} .slick-viewport-top.slick-viewport-left`).scrollTo('top');
+ cy.get(`${gridSelector} .slick-vertical-scroller`).scrollTo('top');
cy.get(`${gridSelector} .slick-row[data-row="1"] input[type=checkbox]`).uncheck({ force: true });
cy.get(`${gridSelector} .slick-row[data-row="2"] input[type=checkbox]`).uncheck({ force: true });
cy.get(`${gridSelector} .slick-row[data-row="4"] input[type=checkbox]`).uncheck({ force: true });
diff --git a/demos/aurelia/test/cypress/e2e/example55.cy.ts b/demos/aurelia/test/cypress/e2e/example55.cy.ts
index 37ecd02a59..3a8477ecf3 100644
--- a/demos/aurelia/test/cypress/e2e/example55.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example55.cy.ts
@@ -38,7 +38,7 @@ describe('Example 55 - Variable Row Height (provider)', { retries: 1 }, () => {
it('should keep row 90 aligned at top after clicking scroll button', () => {
cy.get('[data-test="scroll-row-90-example55"]').click();
- cy.get('.slick-viewport-top.slick-viewport-left')
+ cy.get('.slick-vertical-scroller')
.invoke('scrollTop')
.then((scrollTop) => {
expect(Number(scrollTop)).to.be.closeTo(topOf(90), 2);
diff --git a/demos/aurelia/test/cypress/e2e/example56.cy.ts b/demos/aurelia/test/cypress/e2e/example56.cy.ts
index c02518e284..e30d1b7f00 100644
--- a/demos/aurelia/test/cypress/e2e/example56.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example56.cy.ts
@@ -1,6 +1,6 @@
describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, () => {
const BASE_ROW_HEIGHT = 40;
- const FROZEN_ROW_COUNT = 2;
+ const PINNED_ROW_COUNT = 2;
const hDefault = (r: number) => {
const cycle = [33, 44, 44, 80];
@@ -18,36 +18,41 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
return t;
};
- const frozenTopHeight = (hOf: (row: number) => number) => topOf(FROZEN_ROW_COUNT, hOf);
+ const pinnedTopHeight = (hOf: (row: number) => number) => topOf(PINNED_ROW_COUNT, hOf);
const relativeTopInCanvas = (r: number, hOf: (row: number) => number) => {
- if (r < FROZEN_ROW_COUNT) {
- return topOf(r, hOf);
- }
- return topOf(r, hOf) - frozenTopHeight(hOf);
+ // Pinned rows are moved into the overlay, but center rows retain their
+ // natural document coordinates behind that overlay.
+ return topOf(r, hOf);
};
- const canvasSelector = (r: number) => (r < FROZEN_ROW_COUNT ? '.grid-canvas-top' : '.grid-canvas-bottom');
+ const rowHostSelector = (r: number) => (r < PINNED_ROW_COUNT ? '.slick-docking-overlay' : '.grid-canvas-top');
const assertRowStyle = (row: number, hOf: (row: number) => number) => {
const expectedHeight = hOf(row);
const expectedTop = relativeTopInCanvas(row, hOf);
- cy.get(`${canvasSelector(row)} .slick-row[data-row=${row}]`)
+ cy.get(`${rowHostSelector(row)} .slick-row[data-row=${row}]`)
.should('have.attr', 'style')
.and('contain', `transform: translateY(${expectedTop}px)`)
.then((style) => {
if (expectedHeight !== BASE_ROW_HEIGHT) {
expect(style).to.contain(`height: ${expectedHeight}px`);
} else {
- expect(style).not.to.contain('height:');
+ // Docked rows carry their resolved height inline so editor/content
+ // styles cannot collapse the pinned row. The base-height case is
+ // therefore valid with either the stylesheet fallback or an
+ // explicit `height: 40px` declaration.
+ expect(style).to.match(/(?:height: 40px;|^(?!.*height:))/);
}
});
- cy.get(`[data-row="${row}"] > .slick-cell:nth(3)`).should('contain', `${expectedHeight}px`);
+ // Rows are split into left/center/right docking regions, so cells are
+ // nested under their region wrapper rather than being direct row children.
+ cy.get(`[data-row="${row}"] .slick-cell:nth(3)`).should('contain', `${expectedHeight}px`);
};
const ensureDefaultDensity = () => {
- cy.get('.grid-canvas-top .slick-row[data-row=1]')
+ cy.get('.slick-docking-overlay .slick-row[data-row=1]')
.invoke('attr', 'style')
.then((style) => {
if ((style ?? '').includes('height: 50px')) {
@@ -55,7 +60,7 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
}
});
- cy.get('.grid-canvas-top .slick-row[data-row=1]').should('have.attr', 'style').and('contain', 'height: 44px');
+ cy.get('.slick-docking-overlay .slick-row[data-row=1]').should('have.attr', 'style').and('contain', 'height: 44px');
};
beforeEach(() => {
@@ -67,7 +72,7 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
cy.get('h2').should('contain', 'Example 56: Variable Row Height (item metadata)');
});
- it('should render frozen and scrollable rows with expected transform and row heights from metadata fallback', () => {
+ it('should render pinned and scrollable rows with expected transform and row heights from metadata fallback', () => {
for (const r of [0, 1, 2, 3, 4, 5, 6]) {
assertRowStyle(r, hDefault);
}
@@ -85,12 +90,12 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
}
});
- it('should scroll row 90 to top of scrollable pane with frozen top rows', () => {
- const expectedScrollTop = topOf(90, hDefault) - frozenTopHeight(hDefault);
+ it('should scroll row 90 to top of scrollable pane with pinned top rows', () => {
+ const expectedScrollTop = topOf(90, hDefault) - pinnedTopHeight(hDefault);
cy.get('[data-test="scroll-row-90-example56"]').click();
- cy.get('.slick-viewport-bottom.slick-viewport-left').should(($viewport) => {
+ cy.get('.slick-vertical-scroller').should(($viewport) => {
expect($viewport.scrollTop()).to.be.closeTo(expectedScrollTop, 2);
});
diff --git a/demos/aurelia/test/cypress/e2e/example57.cy.ts b/demos/aurelia/test/cypress/e2e/example57.cy.ts
index df73fe98f8..7055d540b1 100644
--- a/demos/aurelia/test/cypress/e2e/example57.cy.ts
+++ b/demos/aurelia/test/cypress/e2e/example57.cy.ts
@@ -54,14 +54,14 @@ describe('Example 57 - RTL (Right-to-Left)', () => {
describe('Scrolling Behavior', () => {
it('should have horizontal scroll enabled', () => {
- cy.get('#grid57 .slick-viewport').then(($viewport) => {
+ cy.get('#grid57 .slick-horizontal-scroller').then(($viewport) => {
const viewport = $viewport[0] as HTMLElement;
expect(viewport.scrollWidth).to.be.greaterThan(viewport.clientWidth);
});
});
it('should update visible header columns when scrolling', () => {
- cy.get('#grid57 .slick-viewport').then(($viewport) => {
+ cy.get('#grid57 .slick-horizontal-scroller').then(($viewport) => {
const viewport = $viewport[0] as HTMLElement;
const maxScroll = viewport.scrollWidth - viewport.clientWidth;
viewport.scrollLeft = maxScroll;
@@ -72,7 +72,7 @@ describe('Example 57 - RTL (Right-to-Left)', () => {
cy.wait(150);
- cy.get('#grid57 .slick-viewport').then(($viewport) => {
+ cy.get('#grid57 .slick-horizontal-scroller').then(($viewport) => {
const viewport = $viewport[0] as HTMLElement;
expect(Math.abs(viewport.scrollLeft)).to.be.greaterThan(0);
});
diff --git a/demos/aurelia/test/cypress/support/commands.ts b/demos/aurelia/test/cypress/support/commands.ts
index 3be5a3685b..1f58e699f1 100644
--- a/demos/aurelia/test/cypress/support/commands.ts
+++ b/demos/aurelia/test/cypress/support/commands.ts
@@ -32,19 +32,19 @@ declare global {
namespace Cypress {
interface Chainable {
// triggerHover: (elements: NodeListOf) => void;
- convertPosition(viewport: string): Chainable | { x: string; y: string }>;
+ convertPosition(viewport: string): Chainable<{ x: string; y: string }>;
getCell(
row: number,
col: number,
viewport?: string,
options?: { parentSelector?: string; rowHeight?: number }
- ): Chainable>;
+ ): Chainable>;
getNthCell(
row: number,
nthCol: number,
viewport?: string,
options?: { parentSelector?: string; rowHeight?: number }
- ): Chainable>;
+ ): Chainable>;
saveLocalStorage: () => void;
restoreLocalStorage: () => void;
getTransformValue(cssTransformMatrix: string, absoluteValue: boolean, transformType?: 'rotate' | 'scale'): Chainable;
diff --git a/demos/aurelia/test/cypress/support/drag.ts b/demos/aurelia/test/cypress/support/drag.ts
index 8228176a5a..b26012a988 100644
--- a/demos/aurelia/test/cypress/support/drag.ts
+++ b/demos/aurelia/test/cypress/support/drag.ts
@@ -82,15 +82,22 @@ export function getScrollDistanceWhenDragOutsideGrid(
return (cy as any).convertPosition(viewport).then((_viewportPosition: { x: number; y: number }) => {
const viewportSelector = `${selector} .slick-viewport-${_viewportPosition.x}.slick-viewport-${_viewportPosition.y}`;
(cy as any).getNthCell(fromRow, fromCol, viewport, { parentSelector: selector }).dragStart();
- return cy.get(viewportSelector).then(($viewport) => {
- const scrollTopBefore = $viewport.scrollTop();
- const scrollLeftBefore = $viewport.scrollLeft();
+ return cy.get(selector).then(($grid) => {
+ const viewport = ($grid.find(viewportSelector)[0] || $grid.find('.slick-vertical-scroller')[0]) as HTMLElement;
+ const horizontalScroller = $grid.find('.slick-horizontal-scroller')[0] as HTMLElement | undefined;
+ const horizontalOwner = horizontalScroller || viewport;
+ const scrollTopBefore = viewport.scrollTop;
+ const scrollLeftBefore = horizontalOwner.scrollLeft;
cy.dragOutside(dragDirection, 300, px, { parentSelector: selector });
- return cy.get(viewportSelector).then(($viewportAfter) => {
+ return cy.get(selector).then(($gridAfter) => {
+ const viewportAfter = ($gridAfter.find(viewportSelector)[0] || $gridAfter.find('.slick-vertical-scroller')[0]) as HTMLElement;
+ const horizontalScrollerAfter = $gridAfter.find('.slick-horizontal-scroller')[0] as HTMLElement | undefined;
+ const horizontalOwnerAfter = horizontalScrollerAfter || viewportAfter;
cy.dragEnd(selector);
- const scrollTopAfter = $viewportAfter.scrollTop();
- const scrollLeftAfter = $viewportAfter.scrollLeft();
- cy.get(viewportSelector).scrollTo(0, 0, { ensureScrollable: false });
+ const scrollTopAfter = viewportAfter.scrollTop;
+ const scrollLeftAfter = horizontalOwnerAfter.scrollLeft;
+ horizontalOwnerAfter.scrollLeft = 0;
+ viewportAfter.scrollTop = 0;
return cy.wrap({
scrollTopBefore,
scrollLeftBefore,
diff --git a/demos/react-fluent/src/examples/slickgrid/Example05.tsx b/demos/react-fluent/src/examples/slickgrid/Example05.tsx
index e5c9206e1d..127472e9c3 100644
--- a/demos/react-fluent/src/examples/slickgrid/Example05.tsx
+++ b/demos/react-fluent/src/examples/slickgrid/Example05.tsx
@@ -22,9 +22,9 @@ const Example05: React.FC = () => {
const [dataset] = useState(getData());
const [gridOptions, setGridOptions] = useState(undefined);
const [darkModeGrid, setDarkModeGrid] = useState(false);
- const [frozenColumnCount, setFrozenColumnCount] = useState(2);
- const [frozenRowCount, setFrozenRowCount] = useState(3);
- const [isFrozenBottom, setIsFrozenBottom] = useState(false);
+ const [pinnedColumnCount, setPinnedColumnCount] = useState(2);
+ const [pinnedRowCount, setPinnedRowCount] = useState(3);
+ const [isPinnedBottom, setIsPinnedBottom] = useState(false);
const reactGridRef = useRef(null);
const slickEventHandler = new SlickEventHandler();
@@ -41,8 +41,7 @@ const Example05: React.FC = () => {
function reactGridReady(reactGrid: SlickgridReactInstance) {
reactGridRef.current = reactGrid;
- // with frozen (pinned) grid, in order to see the entire row being highlighted when hovering
- // we need to do some extra tricks (that is because frozen grids use 2 separate div containers)
+ // With a pinned grid, the entire row is highlighted through its shared row regions.
// the trick is to use row selection to highlight when hovering current row and remove selection once we're not
slickEventHandler.subscribe(reactGridRef.current?.slickGrid.onMouseEnter, (event) => highlightRow(event, true));
slickEventHandler.subscribe(reactGridRef.current?.slickGrid.onMouseLeave, (event) => highlightRow(event, false));
@@ -253,13 +252,11 @@ const Example05: React.FC = () => {
editable: true,
autoEdit: true,
enableExcelCopyBuffer: true,
- frozenColumn: 2,
- frozenRow: 3,
- // frozenBottom: true, // if you want to freeze the bottom instead of the top, you can enable this property
+ pinning: { columns: { left: 2 }, rows: { top: [0, 1, 2] } },
- // show both Frozen Columns in HeaderMenu & GridMenu, these are opt-in commands so they're disabled by default
- gridMenu: { hideClearFrozenColumnsCommand: false },
- headerMenu: { hideFreezeColumnsCommand: false },
+ // show both single-column and bulk pinning commands in HeaderMenu & GridMenu; these are opt-in commands
+ gridMenu: { hideClearPinningCommand: false },
+ headerMenu: { hidePinColumnCommand: false, hidePinningColumnsCommand: false },
...baseFluentGridOption,
};
@@ -290,26 +287,26 @@ const Example05: React.FC = () => {
}
/** change dynamically, through slickgrid "setOptions()" the number of pinned columns */
- function changeFrozenColumnCount(e: React.FormEvent) {
- const frozenColumn = +((e.target as HTMLInputElement)?.value ?? 0);
- setFrozenColumnCount(frozenColumn);
+ function changePinnedColumnCount(e: React.FormEvent) {
+ const pinnedColumn = +((e.target as HTMLInputElement)?.value ?? 0);
+ setPinnedColumnCount(pinnedColumn);
}
- function updateFrozenColumnCount() {
+ function updatePinnedColumnCount() {
reactGridRef.current?.slickGrid?.setOptions({
- frozenColumn: frozenColumnCount,
+ pinning: { columns: { left: pinnedColumnCount } },
});
}
/** change dynamically, through slickgrid "setOptions()" the number of pinned rows */
- function changeFrozenRowCount(e: React.FormEvent) {
- const frozenRow = +((e.target as HTMLInputElement)?.value ?? 0);
- setFrozenRowCount(frozenRow);
+ function changePinnedRowCount(e: React.FormEvent) {
+ const pinnedRow = +((e.target as HTMLInputElement)?.value ?? 0);
+ setPinnedRowCount(pinnedRow);
}
- function updateFrozenRowCount() {
+ function updatePinnedRowCount() {
reactGridRef.current?.slickGrid?.setOptions({
- frozenRow: frozenRowCount,
+ pinning: { rows: { top: Array.from({ length: Math.max(0, pinnedRowCount) }, (_value, index) => index) } },
});
}
@@ -330,8 +327,8 @@ const Example05: React.FC = () => {
showToast(args.validationResults.msg, 'danger');
}
- function setFrozenColumns(frozenCols: number) {
- reactGridRef.current?.slickGrid.setOptions({ frozenColumn: frozenCols });
+ function setPinnedColumns(pinnedCols: number) {
+ reactGridRef.current?.slickGrid.setOptions({ pinning: { columns: { left: pinnedCols } } });
const updatedGridOptions = reactGridRef.current?.slickGrid.getOptions();
setGridOptions(updatedGridOptions);
}
@@ -348,20 +345,20 @@ const Example05: React.FC = () => {
}
/** toggle dynamically, through slickgrid "setOptions()" the top/bottom pinned location */
- function toggleFrozenBottomRows() {
+ function togglePinnedBottomRows() {
reactGridRef.current?.slickGrid.setOptions({
- frozenBottom: !isFrozenBottom,
+ pinning: { rows: { top: isPinnedBottom ? [0, 1, 2] : [], bottom: isPinnedBottom ? [] : [0, 1, 2] } },
});
- const newIsFrozenBottom = !isFrozenBottom;
- setIsFrozenBottom(newIsFrozenBottom);
+ const newIsPinnedBottom = !isPinnedBottom;
+ setIsPinnedBottom(newIsPinnedBottom);
}
return !gridOptions ? (
''
) : (
-
Example 5: Pinned (frozen) Columns/Rows
+
Example 5: Pinned Columns/Rows
diff --git a/demos/react-fluent/src/examples/slickgrid/base-fluent-grid-options.ts b/demos/react-fluent/src/examples/slickgrid/base-fluent-grid-options.ts
index b6503efedb..e521dcf8de 100644
--- a/demos/react-fluent/src/examples/slickgrid/base-fluent-grid-options.ts
+++ b/demos/react-fluent/src/examples/slickgrid/base-fluent-grid-options.ts
@@ -16,7 +16,7 @@ export const baseFluentGridOption: GridOption = {
iconCssClass: 'fi fi-navigation',
iconClearAllFiltersCommand: 'fi fi-filter-dismiss',
iconClearAllSortingCommand: 'fi fi-arrow-sort',
- iconClearFrozenColumnsCommand: 'fi fi-pin-off',
+ iconClearPinningCommand: 'fi fi-pin-off',
iconExportCsvCommand: 'fi fi-arrow-download',
iconExportExcelCommand: 'fi fi-arrow-download',
iconExportPdfCommand: 'fi fi-arrow-download',
@@ -31,8 +31,8 @@ export const baseFluentGridOption: GridOption = {
iconClearFilterCommand: 'fi fi-filter-dismiss',
iconClearSortCommand: 'fi fi-arrow-sort',
iconFilterShortcutSubMenu: 'fi fi-filter',
- iconFreezeColumns: 'fi fi-pin',
- iconUnfreezeColumns: 'fi fi-pin-off',
+ iconPinningColumns: 'fi fi-pin',
+ iconUnpinningColumns: 'fi fi-pin-off',
iconSortAscCommand: 'fi fi-sort-arrow-up',
iconSortDescCommand: 'fi fi-sort-arrow-down',
iconColumnHideCommand: 'fi fi-dismiss',
diff --git a/demos/react-fluent/src/examples/slickgrid/example05.scss b/demos/react-fluent/src/examples/slickgrid/example05.scss
index 6e31054384..e41265a0e7 100644
--- a/demos/react-fluent/src/examples/slickgrid/example05.scss
+++ b/demos/react-fluent/src/examples/slickgrid/example05.scss
@@ -1,8 +1,8 @@
-/** You can change the pinned/frozen border styling through this css override */
+/** You can change the pinned/pinned border styling through this css override */
-.slick-row .slick-cell.frozen:last-child,
-.slick-headerrow-column.frozen:last-child,
-.slick-footerrow-column.frozen:last-child {
+.slick-row .slick-cell.pinned:last-child,
+.slick-headerrow-column.pinned:last-child,
+.slick-footerrow-column.pinned:last-child {
border-right: 1px solid #969696 !important;
}
diff --git a/demos/react/src/assets/locales/en/translation.json b/demos/react/src/assets/locales/en/translation.json
index b412eea6d6..600e68cdc1 100644
--- a/demos/react/src/assets/locales/en/translation.json
+++ b/demos/react/src/assets/locales/en/translation.json
@@ -7,7 +7,7 @@
"CLEAR_ALL_FILTERS": "Clear all Filters",
"CLEAR_ALL_GROUPING": "Clear all Grouping",
"CLEAR_ALL_SORTING": "Clear all Sorting",
- "CLEAR_PINNING": "Unfreeze Columns/Rows",
+ "CLEAR_PINNING": "Unpin Columns/Rows",
"CLONE": "Clone",
"COLLAPSE_ALL_GROUPS": "Collapse all Groups",
"COLUMNS": "Columns",
@@ -28,7 +28,10 @@
"FILTER_SHORTCUTS": "Filter Shortcuts",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} of {{totalItems}} items",
"FORCE_FIT_COLUMNS": "Force fit columns",
- "FREEZE_COLUMNS": "Freeze Columns",
+ "PIN_COLUMN": "Column Pinning",
+ "PIN_COLUMNS": "Pin Through Here",
+ "PIN_LEFT": "Pin Left",
+ "PIN_RIGHT": "Pin Right",
"INVALID_FLOAT": "The number must be valid and have a maximum of {{maxDecimal}} decimals.",
"GREATER_THAN": "Greater than",
"GREATER_THAN_OR_EQUAL_TO": "Greater than or equal to",
@@ -63,7 +66,8 @@
"SYNCHRONOUS_RESIZE": "Synchronous resize",
"TOGGLE_FILTER_ROW": "Toggle Filter Row",
"TOGGLE_PRE_HEADER_ROW": "Toggle Pre-Header Row",
- "UNFREEZE_COLUMNS": "Unfreeze Columns",
+ "UNPIN_COLUMN": "Unpin Column",
+ "UNPIN_COLUMNS": "Unpin All Columns",
"X_OF_Y_SELECTED": "# of % selected",
"X_OF_Y_MASS_SELECTED": "{{x}} of {{y}} selected",
"BILLING": {
diff --git a/demos/react/src/assets/locales/fr/translation.json b/demos/react/src/assets/locales/fr/translation.json
index c957bb46b8..832f0207b7 100644
--- a/demos/react/src/assets/locales/fr/translation.json
+++ b/demos/react/src/assets/locales/fr/translation.json
@@ -7,7 +7,7 @@
"CLEAR_ALL_FILTERS": "Supprimer tous les filtres",
"CLEAR_ALL_GROUPING": "Supprimer tous les groupes",
"CLEAR_ALL_SORTING": "Supprimer tous les tris",
- "CLEAR_PINNING": "Dégeler les colonnes/rangées",
+ "CLEAR_PINNING": "Désépingler les colonnes/rangées",
"CLONE": "Cloner",
"COLLAPSE_ALL_GROUPS": "Réduire tous les groupes",
"COLUMNS": "Colonnes",
@@ -28,7 +28,10 @@
"FILTER_SHORTCUTS": "Raccourcis de filtre",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} de {{totalItems}} éléments",
"FORCE_FIT_COLUMNS": "Ajustement forcé des colonnes",
- "FREEZE_COLUMNS": "Geler les colonnes",
+ "PIN_COLUMN": "Épinglage de colonnes",
+ "PIN_COLUMNS": "Épingler jusqu'ici",
+ "PIN_LEFT": "Épingler à gauche",
+ "PIN_RIGHT": "Épingler à droite",
"GREATER_THAN": "Plus grand que",
"GREATER_THAN_OR_EQUAL_TO": "Plus grand ou égal à",
"GROUP_BY": "Grouper par",
@@ -63,7 +66,8 @@
"SYNCHRONOUS_RESIZE": "Redimension synchrone",
"TOGGLE_FILTER_ROW": "Basculer la ligne des filtres",
"TOGGLE_PRE_HEADER_ROW": "Basculer la ligne de pré-en-tête",
- "UNFREEZE_COLUMNS": "Dégeler les colonnes",
+ "UNPIN_COLUMN": "Désépingler la colonne",
+ "UNPIN_COLUMNS": "Désépingler toutes les colonnes",
"X_OF_Y_SELECTED": "# de % sélectionnés",
"X_OF_Y_MASS_SELECTED": "{{x}} de {{y}} sélectionnés",
"BILLING": {
diff --git a/demos/react/src/examples/slickgrid/Example07.tsx b/demos/react/src/examples/slickgrid/Example07.tsx
index 96db83d625..71a44a2f5d 100644
--- a/demos/react/src/examples/slickgrid/Example07.tsx
+++ b/demos/react/src/examples/slickgrid/Example07.tsx
@@ -58,8 +58,6 @@ const Example7: React.FC = () => {
...gridOptions1,
enableHeaderMenu: true,
enableFiltering: true,
- // frozenColumn: 2,
- // frozenRow: 2,
headerButton: {
onCommand: (_e, args) => handleOnCommand(_e, args, 2),
},
diff --git a/demos/react/src/examples/slickgrid/Example14.tsx b/demos/react/src/examples/slickgrid/Example14.tsx
index b0c88d91de..0b0ba6a73f 100644
--- a/demos/react/src/examples/slickgrid/Example14.tsx
+++ b/demos/react/src/examples/slickgrid/Example14.tsx
@@ -49,6 +49,7 @@ const Example14: React.FC = () => {
createPreHeaderPanel: true,
showPreHeaderPanel: true,
preHeaderPanelHeight: 28,
+ rowHeight: 33,
gridHeight: 275,
gridWidth: 800,
enableExcelExport: true,
@@ -101,14 +102,15 @@ const Example14: React.FC = () => {
explicitInitialization: true,
gridHeight: 275,
gridWidth: 800,
- frozenColumn: 2,
+ rowHeight: 33,
+ pinning: { columns: { left: 2 } },
enableExcelExport: true,
excelExportOptions: {
exportWithFormatter: false,
},
externalResources: [new ExcelExportService(), new PdfExportService()],
- gridMenu: { hideClearFrozenColumnsCommand: false },
- headerMenu: { hideFreezeColumnsCommand: false },
+ gridMenu: { hideClearPinningCommand: false },
+ headerMenu: { hidePinColumnCommand: false, hidePinningColumnsCommand: false },
};
setColumns2(columns2);
@@ -133,8 +135,8 @@ const Example14: React.FC = () => {
return mockDataset;
}
- function setFrozenColumns2(frozenCols: number) {
- reactGridRef2.current?.slickGrid.setOptions({ frozenColumn: frozenCols });
+ function setPinnedColumns2(pinnedCols: number) {
+ reactGridRef2.current?.slickGrid.setOptions({ pinning: { columns: { left: pinnedCols } } });
const updatedGridOptions = reactGridRef2.current?.slickGrid.getOptions();
setGridOptions2(updatedGridOptions);
}
@@ -230,23 +232,23 @@ const Example14: React.FC = () => {
- Grid 2 (with Header Grouping & Frozen/Pinned Columns)
+ Grid 2 (with Header Grouping & Pinned Columns)
setFrozenColumns2(-1)}
- data-test="remove-frozen-column-button"
+ onClick={() => setPinnedColumns2(-1)}
+ data-test="remove-pinned-column-button"
>
- Remove Frozen Columns
+ Remove Pinned Columns
setFrozenColumns2(2)}
- data-test="set-3frozen-columns"
+ onClick={() => setPinnedColumns2(2)}
+ data-test="set-3pinned-columns"
>
- Set 3 Frozen Columns
+ Set 3 Pinned Columns
diff --git a/demos/react/src/examples/slickgrid/Example15.tsx b/demos/react/src/examples/slickgrid/Example15.tsx
index 82c2889f62..c9264c6a16 100644
--- a/demos/react/src/examples/slickgrid/Example15.tsx
+++ b/demos/react/src/examples/slickgrid/Example15.tsx
@@ -72,10 +72,11 @@ const Example15: React.FC = () => {
},
gridMenu: {
hideForceFitButton: true,
- hideClearFrozenColumnsCommand: false,
+ hideClearPinningCommand: false,
},
headerMenu: {
- hideFreezeColumnsCommand: false,
+ hidePinColumnCommand: false,
+ hidePinningColumnsCommand: false,
},
enablePagination: true,
pagination: {
diff --git a/demos/react/src/examples/slickgrid/Example20.tsx b/demos/react/src/examples/slickgrid/Example20.tsx
index b785c6bd6a..8ad3093fc8 100644
--- a/demos/react/src/examples/slickgrid/Example20.tsx
+++ b/demos/react/src/examples/slickgrid/Example20.tsx
@@ -1,10 +1,10 @@
+import { ExcelExportService } from '@slickgrid-universal/excel-export';
import React, { useEffect, useRef, useState } from 'react';
import {
Editors,
Filters,
formatNumber,
Formatters,
- SlickEventHandler,
SlickgridReact,
type Column,
type ColumnEditorDualInput,
@@ -18,54 +18,31 @@ const Example20: React.FC = () => {
const [columns, setColumns] = useState
([]);
const [dataset] = useState(getData());
const [gridOptions, setGridOptions] = useState(undefined);
- const [frozenColumnCount, setFrozenColumnCount] = useState(2);
- const [frozenRowCount, setFrozenRowCount] = useState(3);
- const [isFrozenBottom, setIsFrozenBottom] = useState(false);
+ const [pinnedColumnCount, setPinnedColumnCount] = useState(2);
+ const [pinnedRowCount, setPinnedRowCount] = useState(3);
+ const [pinnedRightColumnCount, setPinnedRightColumnCount] = useState(1);
+ const [isPinnedBottom, setIsPinnedBottom] = useState(false);
const [hideSubTitle, setHideSubTitle] = useState(false);
+ const [isSelectAllShownAsColumnTitle, setIsSelectAllShownAsColumnTitle] = useState(false);
+ const checkboxSelectorRef = useRef(null);
+ const pinnedColumnCountRef = useRef(2);
+ const pinnedRowCountInputRef = useRef(null);
+ const pinnedRightColumnInputRef = useRef(null);
+ const pinnedRightColumnCountRef = useRef(1);
const reactGridRef = useRef(null);
- const slickEventHandler = new SlickEventHandler();
useEffect(() => {
defineGrid();
-
- // when unmounting
- return () => {
- slickEventHandler.unsubscribeAll();
- };
}, []);
function reactGridReady(reactGrid: SlickgridReactInstance) {
reactGridRef.current = reactGrid;
-
- // with frozen (pinned) grid, in order to see the entire row being highlighted when hovering
- // we need to do some extra tricks (that is because frozen grids use 2 separate div containers)
- // the trick is to use row selection to highlight when hovering current row and remove selection once we're not
- slickEventHandler.subscribe(reactGridRef.current?.slickGrid.onMouseEnter, (event) => highlightRow(event, true));
- slickEventHandler.subscribe(reactGridRef.current?.slickGrid.onMouseLeave, (event) => highlightRow(event, false));
- }
-
- function highlightRow(event: any, isMouseEnter: boolean) {
- const cell = reactGridRef.current?.slickGrid.getCellFromEvent(event);
- const rows = isMouseEnter ? [cell?.row ?? 0] : [];
- reactGridRef.current?.slickGrid.setSelectedRows(rows); // highlight current row
- event.preventDefault();
}
/* Define grid Options and Columns */
function defineGrid() {
const columns: Column[] = [
- {
- id: 'sel',
- name: '#',
- field: 'id',
- minWidth: 40,
- width: 40,
- maxWidth: 40,
- cannotTriggerInsert: true,
- resizable: false,
- unselectable: true,
- },
{
id: 'title',
name: 'Title',
@@ -82,7 +59,6 @@ const Example20: React.FC = () => {
resizable: false,
minWidth: 130,
width: 140,
- formatter: Formatters.percentCompleteBar,
type: 'number',
filterable: true,
filter: { model: Filters.slider, operator: '>=' },
@@ -92,29 +68,44 @@ const Example20: React.FC = () => {
id: 'start',
name: 'Start',
field: 'start',
- minWidth: 100,
- width: 120,
+ type: 'dateIso',
filterable: true,
sortable: true,
formatter: Formatters.dateIso,
+ filter: { model: Filters.compoundDate },
},
{
id: 'finish',
name: 'Finish',
field: 'finish',
- minWidth: 100,
- width: 120,
+ type: 'dateIso',
filterable: true,
sortable: true,
formatter: Formatters.dateIso,
+ filter: { model: Filters.compoundDate },
+ },
+ {
+ id: 'completed',
+ name: 'Completed',
+ field: 'completed',
+ sortable: true,
+ filterable: true,
+ formatter: Formatters.checkmarkMaterial,
+ editor: { model: Editors.checkbox },
+ filter: {
+ model: Filters.singleSelect,
+ collection: [
+ { value: '', label: '' },
+ { value: true, label: 'True' },
+ { value: false, label: 'False' },
+ ],
+ },
},
{
id: 'cost',
name: 'Cost | Duration',
field: 'cost',
formatter: costDurationFormatter,
- minWidth: 150,
- width: 170,
sortable: true,
// filterable: true,
filter: {
@@ -184,58 +175,37 @@ const Example20: React.FC = () => {
},
},
{
- id: 'effortDriven',
- name: 'Effort Driven',
- field: 'effortDriven',
+ id: 'cityOfOrigin',
+ name: 'City of Origin',
+ field: 'cityOfOrigin',
minWidth: 100,
- width: 120,
- formatter: Formatters.checkmarkMaterial,
filterable: true,
- filter: {
- collection: [
- { value: '', label: '' },
- { value: true, label: 'True' },
- { value: false, label: 'False' },
- ],
- model: Filters.singleSelect,
- },
sortable: true,
},
{
- id: 'title1',
- name: 'Title 1',
- field: 'title1',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
- },
- {
- id: 'title2',
- name: 'Title 2',
- field: 'title2',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
- },
- {
- id: 'title3',
- name: 'Title 3',
- field: 'title3',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
- },
- {
- id: 'title4',
- name: 'Title 4',
- field: 'title4',
- minWidth: 100,
- width: 120,
- filterable: true,
- sortable: true,
+ id: 'action',
+ name: 'Action',
+ field: 'action',
+ width: 100,
+ maxWidth: 100,
+ excludeFromExport: true,
+ formatter: () => '',
+ cellMenu: {
+ commandTitle: 'Commands',
+ commandItems: [
+ { command: 'command1', title: 'Command 1' },
+ { command: 'command2', title: 'Command 2', itemUsabilityOverride: (args: any) => !args.dataContext.completed },
+ { command: 'delete-row', title: 'Delete Row', itemVisibilityOverride: (args: any) => !args.dataContext.completed },
+ { divider: true, command: '' },
+ { command: 'help', title: 'Help' },
+ { command: 'something', title: 'Disabled Command', disabled: true },
+ ],
+ optionTitle: 'Change Complete Flag',
+ optionItems: [
+ { option: true, title: 'True' },
+ { option: false, title: 'False' },
+ ],
+ },
},
];
@@ -244,18 +214,49 @@ const Example20: React.FC = () => {
container: '#demo-container',
rightPadding: 10,
},
- gridWidth: 920,
+ // Keep the left-pinned columns compact so two right-pinned columns fit
+ // beside the framework demo's route sidebar.
+ autoFitColumnsOnFirstLoad: false,
enableCellNavigation: true,
editable: true,
autoEdit: true,
enableExcelCopyBuffer: true,
- frozenColumn: 2,
- frozenRow: 3,
- // frozenBottom: true, // if you want to freeze the bottom instead of the top, you can enable this property
-
- // show both Frozen Columns in HeaderMenu & GridMenu, these are opt-in commands so they're disabled by default
- gridMenu: { hideClearFrozenColumnsCommand: false },
- headerMenu: { hideFreezeColumnsCommand: false },
+ enableExcelExport: true,
+ externalResources: [new ExcelExportService()],
+ enableFiltering: true,
+ enableSelection: true,
+ enableCheckboxSelector: true,
+ selectionOptions: { selectActiveRow: false },
+ checkboxSelector: {
+ hideInColumnTitleRow: !isSelectAllShownAsColumnTitle,
+ hideInFilterHeaderRow: isSelectAllShownAsColumnTitle,
+ name: 'Sel',
+ onExtensionRegistered: (instance: any) => (checkboxSelectorRef.current = instance),
+ },
+ pinning: { columns: { left: ['_checkbox_selector', 'title', 'percentComplete'], right: ['action'] }, rows: { top: [0, 1, 2] } },
+ // pinnedBottom: true, // if you want to pin the bottom instead of the top, you can enable this property
+
+ // show both single-column and bulk pinning commands in HeaderMenu & GridMenu; these are opt-in commands
+ gridMenu: {
+ hideClearPinningCommand: false,
+ // Grid Menu visibility updates rebuild the column layout. Reassert the
+ // demo's current ID-based pinning after that rebuild so React's right
+ // pinning state cannot briefly fall back to the scrolling band.
+ onColumnsChanged: () => reapplyPinnedColumns(),
+ },
+ headerMenu: { hidePinColumnCommand: false, hidePinningColumnsCommand: false },
+ enableCellMenu: true,
+ cellMenu: {
+ onCommand: (_e: unknown, args: any) => executeCommand(args),
+ onOptionSelected: (_e: unknown, args: any) => {
+ if (args?.dataContext) {
+ args.dataContext.completed = args.item.option;
+ reactGridRef.current?.gridService?.updateItem(args.dataContext);
+ }
+ },
+ },
+ enableContextMenu: true,
+ contextMenu: getContextMenuOptions(),
};
setColumns(columns);
@@ -274,38 +275,114 @@ const Example20: React.FC = () => {
percentComplete: Math.round(Math.random() * 100),
start: new Date(2009, 0, 1),
finish: new Date(2009, 4, 5),
- effortDriven: i % 5 === 0,
- title1: `Some Text ${Math.round(Math.random() * 25)}`,
- title2: `Some Text ${Math.round(Math.random() * 25)}`,
- title3: `Some Text ${Math.round(Math.random() * 25)}`,
- title4: `Some Text ${Math.round(Math.random() * 25)}`,
+ completed: i % 5 === 0,
+ cityOfOrigin: i % 2 ? 'Vancouver, BC, Canada' : 'Boston, MA, United States',
};
}
return mockDataset;
}
/** change dynamically, through slickgrid "setOptions()" the number of pinned columns */
- function changeFrozenColumnCount(e: React.FormEvent) {
- const frozenColumn = +((e.target as HTMLInputElement)?.value ?? 0);
- setFrozenColumnCount(frozenColumn);
+ function changePinnedColumnCount(e: React.FormEvent) {
+ const value = +(e.currentTarget.value || 0);
+ setPinnedColumnCount(value);
}
- function updateFrozenColumnCount() {
- reactGridRef.current?.slickGrid?.setOptions({
- frozenColumn: frozenColumnCount,
- });
+ function updatePinnedColumnCount() {
+ setPinnedColumns(pinnedColumnCount, pinnedRightColumnCount);
}
/** change dynamically, through slickgrid "setOptions()" the number of pinned rows */
- function changeFrozenRowCount(e: React.FormEvent) {
- const frozenRow = +((e.target as HTMLInputElement)?.value ?? 0);
- setFrozenRowCount(frozenRow);
+ function updatePinnedRowCount() {
+ const inputValue = pinnedRowCountInputRef.current?.value;
+ const nextPinnedRowCount = Math.max(0, Number(inputValue ?? pinnedRowCount) || 0);
+ const rows = Array.from({ length: nextPinnedRowCount }, (_v, i) => i);
+
+ const slickGrid = reactGridRef.current?.slickGrid;
+ slickGrid?.setOptions({
+ pinning: { rows: isPinnedBottom ? { top: [], bottom: rows } : { top: rows, bottom: [] } },
+ });
+
+ setPinnedRowCount(nextPinnedRowCount);
}
- function updateFrozenRowCount() {
- reactGridRef.current?.slickGrid?.setOptions({
- frozenRow: frozenRowCount,
- });
+ function getContextMenuOptions(): any {
+ const percentItems = [
+ { option: 0, title: 'Not Started (0%)' },
+ { option: 50, title: 'Half Completed (50%)' },
+ { option: 100, title: 'Completed (100%)' },
+ ];
+ return {
+ optionShownOverColumnIds: ['percentComplete'],
+ hideCloseButton: true,
+ dropSide: 'right',
+ optionTitle: 'Change Percent Complete',
+ optionItems: [
+ ...percentItems,
+ 'divider',
+ { option: null, title: 'Sub-Options (demo)', subMenuTitle: 'Set Percent Complete', optionItems: percentItems },
+ ],
+ commandItems: [
+ { command: '', divider: true, positionOrder: 98 },
+ {
+ command: 'export',
+ title: 'Exports',
+ positionOrder: 99,
+ commandItems: [
+ { command: 'exports-txt', title: 'Text (tab delimited)' },
+ {
+ command: 'sub-menu',
+ title: 'Excel',
+ subMenuTitle: 'available formats',
+ commandItems: [
+ { command: 'exports-csv', title: 'Excel (csv)' },
+ { command: 'exports-xlsx', title: 'Excel (xlsx)' },
+ ],
+ },
+ ],
+ },
+ {
+ command: 'feedback',
+ title: 'Feedback',
+ positionOrder: 100,
+ commandItems: [
+ { command: 'request-update', title: 'Request update from supplier' },
+ 'divider',
+ {
+ command: 'sub-menu',
+ title: 'Contact Us',
+ subMenuTitle: 'contact us...',
+ commandItems: [
+ { command: 'contact-email', title: 'Email us' },
+ { command: 'contact-chat', title: 'Chat with us' },
+ { command: 'contact-meeting', title: 'Book an appointment' },
+ ],
+ },
+ ],
+ },
+ ],
+ onOptionSelected: (_e: unknown, args: any) => {
+ if (args?.dataContext) {
+ args.dataContext.percentComplete = args.item.option;
+ reactGridRef.current?.slickGrid?.updateRow(args.row || 0);
+ }
+ },
+ onCommand: (_e: unknown, args: any) => executeCommand(args),
+ };
+ }
+
+ function executeCommand(args: any) {
+ if (args.command === 'delete-row') {
+ if (confirm(`Do you really want to delete row (${args.row + 1}) with "${args.dataContext.title}"?`)) {
+ reactGridRef.current?.gridService?.deleteItemById(args.dataContext.id);
+ }
+ } else if (['command1', 'command2', 'help'].includes(args.command)) {
+ alert(args.item.title);
+ } else if (['exports-csv', 'exports-txt', 'exports-xlsx'].includes(args.command)) {
+ alert(`Exporting as ${args.item.title}`);
+ } else {
+ alert(`Command: ${args.command}`);
+ }
}
function costDurationFormatter(_row: number, _cell: number, _value: any, _columnDef: Column, dataContext: any) {
@@ -325,21 +402,75 @@ const Example20: React.FC = () => {
showToast(args.validationResults.msg, 'danger');
}
- function setFrozenColumns(frozenCols: number) {
- reactGridRef.current?.slickGrid.setOptions({ frozenColumn: frozenCols });
- const updatedGridOptions = reactGridRef.current?.slickGrid.getOptions();
- setGridOptions(updatedGridOptions);
- setFrozenColumnCount(frozenCols);
+ function removePinnedColumns() {
+ setPinnedColumns(-1, 0);
+ setPinnedColumnCount(0);
}
- /** toggle dynamically, through slickgrid "setOptions()" the top/bottom pinned location */
- function toggleFrozenBottomRows() {
+ function setPinnedColumns(left: number, right = pinnedRightColumnCount) {
+ const nextRight = Math.max(0, Number(right) || 0);
+ const rightIds = ['cityOfOrigin', 'action'].slice(Math.max(0, 2 - nextRight));
+ pinnedColumnCountRef.current = left;
+ pinnedRightColumnCountRef.current = nextRight;
reactGridRef.current?.slickGrid.setOptions({
- frozenBottom: !isFrozenBottom,
+ pinning: { columns: { left: left >= 0 ? left : [], right: rightIds } },
});
+ setPinnedColumnCount(left);
+ setPinnedRightColumnCount(nextRight);
+ if (pinnedRightColumnInputRef.current) {
+ pinnedRightColumnInputRef.current.value = `${nextRight}`;
+ }
+ }
+
+ function reapplyPinnedColumns() {
+ const left = pinnedColumnCountRef.current;
+ const right = pinnedRightColumnCountRef.current;
+ const rightIds = ['cityOfOrigin', 'action'].slice(Math.max(0, 2 - right));
+ reactGridRef.current?.slickGrid.setOptions({ pinning: { columns: { left: left >= 0 ? left : [], right: rightIds } } });
+ }
+
+ function updatePinnedRightColumnCount() {
+ const nextRight = Math.max(0, Number(pinnedRightColumnInputRef.current?.value ?? pinnedRightColumnCount) || 0);
+ setPinnedColumns(pinnedColumnCount, nextRight);
+ }
+
+ function toggleRightPinning() {
+ setPinnedColumns(pinnedColumnCount, pinnedRightColumnCount > 0 ? 0 : 1);
+ }
+
+ function toggleSelectAllRow() {
+ const next = !isSelectAllShownAsColumnTitle;
+ setIsSelectAllShownAsColumnTitle(next);
+ checkboxSelectorRef.current?.setOptions({ hideInColumnTitleRow: !next, hideInFilterHeaderRow: next });
+ }
- const newIsFrozenBottom = !isFrozenBottom;
- setIsFrozenBottom(newIsFrozenBottom);
+ function setLargePinnedColumns() {
+ reactGridRef.current?.gridStateService?.applyColumnLayout?.(
+ [
+ { columnId: '_checkbox_selector', cssClass: 'slick-cell-checkboxsel', headerCssClass: '', width: 40 },
+ { columnId: 'title', cssClass: '', headerCssClass: '', width: 220 },
+ { columnId: 'percentComplete', cssClass: '', headerCssClass: '', width: 280 },
+ { columnId: 'start', cssClass: '', headerCssClass: '', width: 150 },
+ { columnId: 'finish', cssClass: '', headerCssClass: '', width: 280 },
+ { columnId: 'completed', cssClass: '', headerCssClass: '', width: 180 },
+ { columnId: 'cost', cssClass: '', headerCssClass: '', width: 220 },
+ { columnId: 'cityOfOrigin', cssClass: '', headerCssClass: '', width: 180 },
+ { columnId: 'action', cssClass: '', headerCssClass: '', width: 110 },
+ ],
+ false,
+ false
+ );
+ setPinnedColumns(pinnedColumnCount, pinnedRightColumnCount);
+ }
+
+ /** toggle dynamically, through slickgrid "setOptions()" the top/bottom pinned location */
+ function togglePinnedBottomRows() {
+ const newIsPinnedBottom = !isPinnedBottom;
+ const rows = Array.from({ length: Math.max(0, pinnedRowCount) }, (_value, index) => index);
+ reactGridRef.current?.slickGrid.setOptions({
+ pinning: { rows: newIsPinnedBottom ? { top: [], bottom: rows } : { top: rows, bottom: [] } },
+ });
+ setIsPinnedBottom(newIsPinnedBottom);
}
function toggleSubTitle() {
@@ -355,7 +486,7 @@ const Example20: React.FC = () => {
) : (
- Example 20: Pinned (frozen) Columns/Rows
+ Example 20: Pinned Columns/Rows
see
{
- This example demonstrates the use of Pinned (aka frozen) Columns and/or Rows (
-
+ This example demonstrates the use of Pinned (aka pinned) Columns and/or Rows (
+
Docs
)
@@ -395,15 +526,37 @@ const Example20: React.FC = () => {
diff --git a/demos/react/src/examples/slickgrid/Example43.tsx b/demos/react/src/examples/slickgrid/Example43.tsx
index 2521e1e0ef..fbc350e3e1 100644
--- a/demos/react/src/examples/slickgrid/Example43.tsx
+++ b/demos/react/src/examples/slickgrid/Example43.tsx
@@ -130,7 +130,6 @@ export default function Example43() {
autoResize: {
container: '#demo-container',
bottomPadding: 30,
- rightPadding: 50,
},
enableCellNavigation: true,
enableColumnReorder: true,
@@ -142,7 +141,7 @@ export default function Example43() {
autoEdit: true,
editable: false,
datasetIdPropertyName: 'employeeID',
- frozenColumn: 0,
+ pinning: { columns: { left: 0 } },
gridHeight: 348,
rowHeight: 30,
dataView: {
@@ -443,7 +442,7 @@ export default function Example43() {
newMetadata[row].columns[Number(col) + colDirIdx] = (this.metadata as any)[row].columns[col];
}
}
- reactGrid?.slickGrid?.setOptions({ frozenColumn: newShowEmployeeId ? 0 : 1 });
+ reactGrid?.slickGrid?.setOptions({ pinning: { columns: { left: newShowEmployeeId ? 0 : 1 } } });
reactGrid?.slickGrid?.updateColumnById('employeeID', { hidden: !newShowEmployeeId });
reactGrid?.slickGrid?.updateColumns();
*/
diff --git a/demos/react/src/examples/slickgrid/Example55.tsx b/demos/react/src/examples/slickgrid/Example55.tsx
index 099865443b..553bc4eaca 100644
--- a/demos/react/src/examples/slickgrid/Example55.tsx
+++ b/demos/react/src/examples/slickgrid/Example55.tsx
@@ -84,7 +84,7 @@ const Example55: React.FC = () => {
const owners = ['Alex', 'Priya', 'Mia', 'Sam', 'Chris'];
const fragments = [
'Refactor keyboard shortcut handling for better readability.',
- 'Adjust frozen rows when view-model updates after grouping.',
+ 'Adjust pinned rows when view-model updates after grouping.',
'Improve screen-reader labels on grid menu actions.',
'Align batch editor validation with backend constraints.',
'Capture edge-case around hidden columns and row-span.',
diff --git a/demos/react/src/examples/slickgrid/Example56.tsx b/demos/react/src/examples/slickgrid/Example56.tsx
index 5af54c812a..b15f7c5cd9 100644
--- a/demos/react/src/examples/slickgrid/Example56.tsx
+++ b/demos/react/src/examples/slickgrid/Example56.tsx
@@ -79,7 +79,7 @@ const Example56: React.FC = () => {
includeColumnWidth: true,
},
rowHeight: 40,
- frozenRow: 2,
+ pinning: { rows: { top: [0, 1] } },
gridHeight: 560,
gridWidth: 1080,
dataView: {
@@ -113,7 +113,7 @@ const Example56: React.FC = () => {
const statuses: Array
= ['Todo', 'In Progress', 'Done'];
const notesPool = [
'Short note.',
- 'Need to validate keyboard navigation and ensure screen reader output remains stable across frozen panes.',
+ 'Need to validate keyboard navigation and ensure screen reader output remains stable across pinned panes.',
'Review row height invalidation path when data changes quickly due to live updates from backend polling.',
'Longer QA note: validate scrolling behavior at top and bottom boundaries, compare rendered range against expected rows, and confirm no visual clipping for wrapped cells.',
];
diff --git a/demos/react/src/examples/slickgrid/example14.scss b/demos/react/src/examples/slickgrid/example14.scss
index 6e31054384..e41265a0e7 100644
--- a/demos/react/src/examples/slickgrid/example14.scss
+++ b/demos/react/src/examples/slickgrid/example14.scss
@@ -1,8 +1,8 @@
-/** You can change the pinned/frozen border styling through this css override */
+/** You can change the pinned/pinned border styling through this css override */
-.slick-row .slick-cell.frozen:last-child,
-.slick-headerrow-column.frozen:last-child,
-.slick-footerrow-column.frozen:last-child {
+.slick-row .slick-cell.pinned:last-child,
+.slick-headerrow-column.pinned:last-child,
+.slick-footerrow-column.pinned:last-child {
border-right: 1px solid #969696 !important;
}
diff --git a/demos/react/src/examples/slickgrid/example20.scss b/demos/react/src/examples/slickgrid/example20.scss
index 6e31054384..e41265a0e7 100644
--- a/demos/react/src/examples/slickgrid/example20.scss
+++ b/demos/react/src/examples/slickgrid/example20.scss
@@ -1,8 +1,8 @@
-/** You can change the pinned/frozen border styling through this css override */
+/** You can change the pinned/pinned border styling through this css override */
-.slick-row .slick-cell.frozen:last-child,
-.slick-headerrow-column.frozen:last-child,
-.slick-footerrow-column.frozen:last-child {
+.slick-row .slick-cell.pinned:last-child,
+.slick-headerrow-column.pinned:last-child,
+.slick-footerrow-column.pinned:last-child {
border-right: 1px solid #969696 !important;
}
diff --git a/demos/react/test/cypress/e2e/example03.cy.ts b/demos/react/test/cypress/e2e/example03.cy.ts
index f488efd517..a08337a57c 100644
--- a/demos/react/test/cypress/e2e/example03.cy.ts
+++ b/demos/react/test/cypress/e2e/example03.cy.ts
@@ -61,8 +61,8 @@ describe('Example 3 - Grid with Editors', () => {
.click();
// change Title & Custom Title
- cy.get('.editor-title > textarea').type('Task 2222');
- cy.get('.editor-title .btn-save').click();
+ cy.get('.editor-title:visible > textarea').type('Task 2222');
+ cy.get('.editor-title:visible .btn-save').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 2222');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(3)`).should('contain', 'Task 2222');
@@ -98,7 +98,7 @@ describe('Example 3 - Grid with Editors', () => {
`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(11) > input.editor-checkbox.editor-effort-driven`
).check();
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
});
it('should dynamically add 2x new "Title" columns', () => {
@@ -147,8 +147,8 @@ describe('Example 3 - Grid with Editors', () => {
.click();
// change Title & Custom Title
- cy.get('.editor-title > textarea').type('Task 0000');
- cy.get('.editor-title .btn-save').click();
+ cy.get('.editor-title:visible > textarea').type('Task 0000');
+ cy.get('.editor-title:visible .btn-save').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 0000');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(3)`).should('contain', 'Task 0000');
@@ -180,7 +180,7 @@ describe('Example 3 - Grid with Editors', () => {
.blur();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(10)`).click(); // the blur seems to not always work, so just click on another cell
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(11)`).find('.mdi-check.checkmark-icon');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
});
it('should be able to filter and search "Task 2222" in the new column and expect only 1 row showing in the grid', () => {
@@ -258,7 +258,7 @@ describe('Example 3 - Grid with Editors', () => {
});
it('should open the "Prerequisites" Filter and expect to have Task 500 & 101 in the Filter', () => {
- cy.get('div.ms-filter.filter-prerequisites').trigger('click', { force: true });
+ cy.get('div.ms-filter.filter-prerequisites').trigger('click');
cy.get('.ms-drop').find('span:nth(1)').contains('Task 101');
@@ -270,7 +270,7 @@ describe('Example 3 - Grid with Editors', () => {
it('should open the "Prerequisites" Editor and expect to have Task 100 & 101 in the Editor', () => {
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(12)`)
.should('contain', '')
- .click({ force: true });
+ .click();
cy.get('.ms-drop').find('span:nth(1)').contains('Task 101');
@@ -284,11 +284,11 @@ describe('Example 3 - Grid with Editors', () => {
});
it('should delete the last item "Task 101" and expect it to be removed from the Filter', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('right').wait(50);
+ cy.get('.slick-horizontal-scroller').scrollTo('right').wait(50);
cy.get('[data-test="delete-item-btn"]').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0).wait(50);
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0).wait(50);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 100');
cy.get('div.ms-filter.filter-prerequisites').trigger('click');
diff --git a/demos/react/test/cypress/e2e/example07.cy.ts b/demos/react/test/cypress/e2e/example07.cy.ts
index 048c260d9b..446c389b24 100644
--- a/demos/react/test/cypress/e2e/example07.cy.ts
+++ b/demos/react/test/cypress/e2e/example07.cy.ts
@@ -75,7 +75,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should go over the last "Column J" and expect to find the button to have the disabled class and clicking it should not turn the negative numbers to red neither expect console log after clicking the disabled button', () => {
- cy.get('#grid7-1 .slick-viewport-top.slick-viewport-left').scrollTo('right').wait(50);
+ cy.get('#grid7-1 .slick-horizontal-scroller').scrollTo('right').wait(50);
cy.get('#grid7-1 .slick-header-columns')
.children('.slick-header-column:nth(9)')
@@ -109,7 +109,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should resize 1st column and make it wider', () => {
- cy.get('#grid7-1 .slick-viewport-top.slick-viewport-left').scrollTo('left').wait(50);
+ cy.get('#grid7-1 .slick-horizontal-scroller').scrollTo('left').wait(50);
cy.get('#grid7-1 .slick-header-columns').children('.slick-header-column:nth(0)').should('contain', 'Resize me!');
@@ -220,7 +220,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should go over the last "Column J" and expect to find the button to have the disabled class and clicking it should not turn the negative numbers to red neither expect console log after clicking the disabled button', () => {
- cy.get('#grid7-2 .slick-viewport-top.slick-viewport-left').scrollTo('right').wait(50);
+ cy.get('#grid7-2 .slick-horizontal-scroller').scrollTo('right').wait(50);
cy.get('#grid7-2 .slick-header-columns')
.children('.slick-header-column:nth(9)')
@@ -254,7 +254,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should resize 1st column and make it wider', () => {
- cy.get('#grid7-2 .slick-viewport-top.slick-viewport-left').scrollTo('left').wait(50);
+ cy.get('#grid7-2 .slick-horizontal-scroller').scrollTo('left').wait(50);
cy.get('#grid7-2 .slick-header-columns').children('.slick-header-column:nth(0)').should('contain', 'Resize me!');
@@ -364,7 +364,7 @@ describe('Example 7 - Header Button Plugin', () => {
});
it('should expect first few items of "Column C" to be negative numbers and be red', () => {
- cy.get('#grid7-2 .slick-viewport-top.slick-viewport-left').scrollTo('top').wait(50);
+ cy.get('#grid7-2 .slick-vertical-scroller').scrollTo('top').wait(50);
cy.get('#grid7-2 .slick-row').each(($row, index) => {
if (index > 10) {
diff --git a/demos/react/test/cypress/e2e/example10.cy.ts b/demos/react/test/cypress/e2e/example10.cy.ts
index f65cc30eeb..fb67e74664 100644
--- a/demos/react/test/cypress/e2e/example10.cy.ts
+++ b/demos/react/test/cypress/e2e/example10.cy.ts
@@ -389,14 +389,14 @@ describe('Example 10 - Multiple Grids with Row Selection', () => {
it('should scroll to the bottom of 2nd Grid and still have 5 rows (Task 1,Task 3,Task 12,Task 13,Task 522) selected and find 2 row selected because we now have 2 rows that got rendered (first and last)', () => {
cy.get('#slickGridContainer-grid2').as('grid2');
cy.get('[data-test=grid2-selections]').should('contain', 'Task 1,Task 3,Task 12,Task 13,Task 522');
- cy.get('@grid2').find('.slick-viewport-top.slick-viewport-left').scrollTo('bottom').wait(10);
+ cy.get('@grid2').find('.slick-vertical-scroller').scrollTo('bottom').wait(10);
cy.get('@grid2').find('.slick-row').children().filter('.slick-cell-checkboxsel.selected').should('have.length', 2);
});
it('should have 2 rows (Task 3,Task 13) selected in 2nd grid after typing in a search filter (3)', () => {
cy.get('#slickGridContainer-grid2').as('grid2');
cy.get('@grid2').find('.filter-title').type('3');
- cy.get('@grid2').find('.slick-viewport-top.slick-viewport-left').scrollTo('top').wait(10);
+ cy.get('@grid2').find('.slick-vertical-scroller').scrollTo('top').wait(10);
cy.get('@grid2').find('.slick-row').should('not.have.length', 0);
cy.wait(50);
diff --git a/demos/react/test/cypress/e2e/example12.cy.ts b/demos/react/test/cypress/e2e/example12.cy.ts
index ec11ba1405..7ed1cab4e7 100644
--- a/demos/react/test/cypress/e2e/example12.cy.ts
+++ b/demos/react/test/cypress/e2e/example12.cy.ts
@@ -229,7 +229,7 @@ describe('Example 12: Localization (i18n)', () => {
it('should scroll to bottom of the grid then select "Task 4"', () => {
cy.get('#slickGridContainer-grid12').as('grid12');
- cy.get('@grid12').find('.slick-viewport-top.slick-viewport-left').scrollTo('bottom').wait(10);
+ cy.get('@grid12').find('.slick-vertical-scroller').scrollTo('bottom').wait(10);
cy.get('#grid12').contains('Task 4').parent().children('.slick-cell-checkboxsel').find('input[type=checkbox]').click({ force: true });
@@ -259,7 +259,7 @@ describe('Example 12: Localization (i18n)', () => {
cy.get('.grid-canvas').find('.slick-row').should('be.visible');
- cy.get('@grid12').find('.slick-viewport-top.slick-viewport-left').scrollTo('top').wait(10);
+ cy.get('@grid12').find('.slick-vertical-scroller').scrollTo('top').wait(10);
cy.get('@grid12').find('.slick-row').children().filter('.slick-cell-checkboxsel.selected').should('have.length', 1);
diff --git a/demos/react/test/cypress/e2e/example14.cy.ts b/demos/react/test/cypress/e2e/example14.cy.ts
index 91f7db34b6..32b529fd3b 100644
--- a/demos/react/test/cypress/e2e/example14.cy.ts
+++ b/demos/react/test/cypress/e2e/example14.cy.ts
@@ -1,5 +1,4 @@
describe('Example 14 - Column Span & Header Grouping', () => {
- // NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const fullPreTitles = ['', 'Common Factor', 'Period', 'Analysis'];
const fullTitles = ['#', 'Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
@@ -20,17 +19,18 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should have a frozen grid on page load with 3 columns on the left and 4 columns on the right', () => {
- cy.get('#grid2').find('[data-row=0]').should('have.length', 2);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 3);
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]').children().should('have.length', 4);
+ it('should have a pinned grid on page load with 3 pinned columns and 4 scrolling columns', () => {
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell`).should('have.length', 3);
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell`).should('have.length', 4);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]> .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]> .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]> .slick-cell:nth(2)').should('contain', '5 days');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(2)`).should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]> .slick-cell:nth(0)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]> .slick-cell:nth(1)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(0)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(1)`).should('contain', '01/05/2009');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid again', () => {
@@ -45,17 +45,18 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should click on the "Remove Frozen Columns" button to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
- cy.get('[data-test="remove-frozen-column-button"]').click();
+ it('should click on the "Remove Pinned Columns" button to switch to a regular grid without pinned columns', () => {
+ cy.get('[data-test="remove-pinned-column-button"]').click();
- cy.get('#grid2').find('[data-row=0]').should('have.length', 1);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 7);
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-cell`).should('have.length', 7);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(2)').should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(3)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(4)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-cell:nth(2)`).should('contain', '5 days');
+ cy.get(`${firstRow} .slick-cell:nth(3)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-cell:nth(4)`).should('contain', '01/05/2009');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid once again', () => {
@@ -70,19 +71,20 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should click on the "Set 3 Frozen Columns" button to switch frozen columns grid and expect 3 frozen columns on the left and 4 columns on the right', () => {
- cy.contains('Set 3 Frozen Columns').click({ force: true });
+ it('should click on the "Set 3 Pinned Columns" button to pin 3 columns and leave 4 scrolling columns', () => {
+ cy.contains('Set 3 Pinned Columns').click({ force: true });
- cy.get('#grid2').find('[data-row=0]').should('have.length', 2);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 3);
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0]').children().should('have.length', 4);
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell`).should('have.length', 3);
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell`).should('have.length', 4);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(2)').should('contain', '5 days');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-pinned-left-cells .slick-cell:nth(2)`).should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0] > .slick-cell:nth(0)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-right > [data-row=0] > .slick-cell:nth(1)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(0)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-scrolling-cells .slick-cell:nth(1)`).should('contain', '01/05/2009');
});
it('should have still exact Column Pre-Header & Column Header Titles in the grid', () => {
@@ -97,56 +99,49 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should click on the Grid Menu command "Unfreeze Columns/Rows" to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
+ it('should click on the Grid Menu command "Unpin Columns/Rows" to switch to a regular grid without pinned columns', () => {
cy.get('#grid2').find('button.slick-grid-menu-button').click({ force: true });
- cy.contains('Unfreeze Columns/Rows').click({ force: true });
+ cy.contains('Unpin Columns/Rows').click({ force: true });
- cy.get('#grid2').find('[data-row=0]').should('have.length', 1);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0]').children().should('have.length', 7);
+ const firstRow = '#grid2 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-cell`).should('have.length', 7);
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(2)').should('contain', '5 days');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(3)').should('contain', '01/01/2009');
- cy.get('#grid2').find('.grid-canvas-left > [data-row=0] > .slick-cell:nth(4)').should('contain', '01/05/2009');
+ cy.get(`${firstRow} .slick-cell:nth(0)`).should('contain', '0');
+ cy.get(`${firstRow} .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${firstRow} .slick-cell:nth(2)`).should('contain', '5 days');
+ cy.get(`${firstRow} .slick-cell:nth(3)`).should('contain', '01/01/2009');
+ cy.get(`${firstRow} .slick-cell:nth(4)`).should('contain', '01/05/2009');
});
- it('should reapply 3 frozen columns on 2nd grid', () => {
- cy.contains('Set 3 Frozen Columns').click({ force: true });
+ it('should reapply 3 pinned columns on 2nd grid', () => {
+ cy.contains('Set 3 Pinned Columns').click({ force: true });
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 3);
-
- cy.get('#grid2')
- .find('.slick-pane-right .slick-header.slick-header-right .slick-header-columns .slick-header-column')
- .should('have.length', 4);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-column-pinned-left').should('have.length', 3);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column:not(.slick-column-pinned-left)').should(
+ 'have.length',
+ 4
+ );
});
- it('should be able to "Unfreeze Columns" from header menu', () => {
+ it('should be able to "Unpin All Columns" from header menu', () => {
cy.get('#grid2')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
+ .find('.slick-header.slick-header-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
.click();
- cy.get('.slick-header-menu .slick-menu-command-list')
- .should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Unfreeze Columns')
- .click();
+ cy.get('.slick-header-menu .slick-menu-command-list').should('be.visible').find('[data-command="pin-column"]').click();
+ cy.get('.slick-submenu [data-command="unpin-columns"]').should('contain', 'Unpin All Columns').click();
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 7);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column').should('have.length', 7);
});
- it('should be able to "Freeze Columns" back from header menu', () => {
+ it('should be able to "Pin Through Here" back from header menu', () => {
cy.get('#grid2')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
+ .find('.slick-header.slick-header-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(2)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
@@ -154,57 +149,72 @@ describe('Example 14 - Column Span & Header Grouping', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Freeze Columns')
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Column Pinning')
.click();
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 3);
+ cy.get('.slick-submenu [data-command="pin-columns"]').should('contain', 'Pin Through Here').click();
- cy.get('#grid2')
- .find('.slick-pane-right .slick-header.slick-header-right .slick-header-columns .slick-header-column')
- .should('have.length', 4);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-column-pinned-left').should('have.length', 3);
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column:not(.slick-column-pinned-left)').should(
+ 'have.length',
+ 4
+ );
});
describe('Basic Key Navigations', () => {
it('should remove any freezing', () => {
- cy.get('[data-test="remove-frozen-column-button"]').click();
+ cy.get('[data-test="remove-pinned-column-button"]').click();
+
+ cy.get('#grid2 .slick-header.slick-header-left .slick-header-columns .slick-header-column').should('have.length', 7);
+ });
+
+ it('should start at Task 1 on Duration colspan 5 days and type "PageDown" key once and land on a full colspan', () => {
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('@active_cell').type('{pagedown}');
+ cy.get('#grid1 .slick-cell.l0.r5.active').should('have.length', 1);
+ });
+
+ it('should start at Task 1 on Duration colspan 5 days and type "PageDown" key 2x times and land on a colspan of 3', () => {
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('@active_cell').type('{pagedown}{pagedown}');
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
+ });
- cy.get('#grid2')
- .find('.slick-pane-left .slick-header.slick-header-left .slick-header-columns .slick-header-column')
- .should('have.length', 7);
+ it('should navigate PageUp twice from a colspan of 3 back to the starting colspan of 3', () => {
+ cy.get('#grid1 [data-row=15] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('@active_cell').type('{pageup}{pageup}');
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
it('should start at Task 2 on Duration colspan 5 days and type "PageDown" key 2x times and "PageUp" twice and be back to Task 1 with colspan of 3', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{pagedown}{pagedown}{pageup}{pageup}');
- cy.get('[data-row=1] > .slick-cell.l1.r3.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
it('should start at Task 2 on Duration colspan 5 days and type "PageDown" key 2x times and "PageUp" 3x times and be on Task 0 with full colspan', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{pagedown}{pagedown}{pageup}{pageup}{pageup}');
- cy.get('[data-row=0] > .slick-cell.l0.r5.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l0.r5.active').should('have.length', 1);
});
it('should start at Task 1 on Duration colspan 5 days and type "ArrowDown" key once and be on Task 2 with full colspan', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{downarrow}');
- cy.get('[data-row=2] > .slick-cell.l0.r5.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l0.r5.active').should('have.length', 1);
});
it('should start at Task 1 on Duration colspan 5 days and type "ArrowDown" key 2x times and be on Task 1 with colspan of 3', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{downarrow}{downarrow}');
- cy.get('[data-row=3] > .slick-cell.l1.r3.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
it('should start at Task 1 on Duration colspan 5 days and type "ArrowDown" key 2x times, then "ArrowUp" key 2x times and be back on Task 1 with colspan of 3', () => {
- cy.get('[data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
+ cy.get('#grid1 [data-row=1] > .slick-cell.l1.r3').as('active_cell').click();
cy.get('@active_cell').type('{downarrow}{downarrow}{uparrow}{uparrow}');
- cy.get('[data-row=1] > .slick-cell.l1.r3.active').should('have.length', 1);
+ cy.get('#grid1 .slick-cell.l1.r3.active').should('have.length', 1);
});
});
@@ -219,7 +229,7 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.contains(/(true|false)+$/);
cy.get('#grid1')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
+ .find('.slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
@@ -232,6 +242,11 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.should('contain', 'Hide Column')
.click();
+ // The colspan still spans the logical Duration/Start/Finish range, but
+ // the hidden Finish track is zero-width. The host cell must remain
+ // rendered and visibly cover the two remaining columns.
+ cy.get('#grid1 [data-row=1] .slick-cell.l1.r3').should('contain', '5 days').and('be.visible');
+
// goto right
cy.get('#grid1').find('[data-row=1] .slick-cell.l0.r0').click();
cy.get('#grid1').find('[data-row=1] .slick-cell.l0.r0.active').should('contain', 'Task 1').type('{rightArrow}');
@@ -272,7 +287,7 @@ describe('Example 14 - Column Span & Header Grouping', () => {
.contains(/(true|false)+$/);
cy.get('#grid1')
- .find('.slick-pane-left .slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
+ .find('.slick-header-columns .slick-header-column[role="columnheader"]:nth(3)')
.trigger('mouseover')
.children('.slick-header-menu-button')
.invoke('show')
diff --git a/demos/react/test/cypress/e2e/example15.cy.ts b/demos/react/test/cypress/e2e/example15.cy.ts
index 2792dbeac6..5a7e09da9d 100644
--- a/demos/react/test/cypress/e2e/example15.cy.ts
+++ b/demos/react/test/cypress/e2e/example15.cy.ts
@@ -1,7 +1,6 @@
import { format } from '@formkit/tempo';
describe('Example 15: Grid State & Presets using Local Storage', () => {
- const GRID_ROW_HEIGHT = 35;
const fullEnglishTitles = ['', 'Title', 'Description', 'Duration', '% Complete', 'Start', 'Completed'];
beforeEach(() => {
@@ -12,16 +11,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.saveLocalStorage();
});
- it('should display Example title', () => {
- cy.visit(`${Cypress.config('baseUrl')}/example15`);
+ it('should display Example title from a clean local-storage state', () => {
+ cy.visit(`${Cypress.config('baseUrl')}/example15`, {
+ onBeforeLoad: (window) => window.localStorage.clear(),
+ });
cy.get('h2').should('contain', 'Example 15: Grid State & Presets using Local Storage');
-
- cy.clearLocalStorage();
- cy.get('[data-test=reset-button]').click();
- });
-
- it('should reload the page', () => {
- cy.reload().wait(50);
});
it('should have exact Column Titles in the grid', () => {
@@ -348,7 +342,7 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
.each(($child, index) => expect($child.find('.slick-column-name').text()).to.eq(expectedTitles[index]));
});
- it('should be able to freeze "Description" column', () => {
+ it('should be able to pin "Description" column', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.trigger('mouseover')
@@ -359,10 +353,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Geler les colonnes')
- .click();
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Épinglage de colonnes')
+ .trigger('mouseover');
+
+ cy.get('.slick-submenu:visible [data-command="pin-columns"]').should('contain', "Épingler jusqu'ici").click();
});
it('should reload the page', () => {
@@ -423,10 +418,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
});
});
- it('should have a persisted frozen column after "Description" and a grid with 4 containers on page load with 2 columns on the left and 3 columns on the right', () => {
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]').children().should('have.length', 3);
+ it('should have a persisted pinned column after "Description" with 2 pinned and 3 scrolling columns', () => {
+ const firstRow = '#grid15 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells > .slick-cell`).should('have.length', 2);
+ cy.get(`${firstRow} .slick-scrolling-cells > .slick-cell`).should('have.length', 3);
});
it('should click on the reset button and have exact Column Titles position as in beginning', () => {
@@ -453,7 +449,7 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
.each(($child, index) => expect($child.text()).to.eq(expectedTitles[index]));
});
- it('should be able to freeze "Description" 3rd column', () => {
+ it('should be able to pin "Description" 3rd column', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(2)')
.trigger('mouseover')
@@ -464,10 +460,11 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Freeze Columns')
- .click();
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Column Pinning')
+ .trigger('mouseover');
+
+ cy.get('.slick-submenu:visible [data-command="pin-columns"]').should('contain', 'Pin Through Here').click();
});
it('should swap "Duration" and "% Complete" columns', () => {
@@ -481,7 +478,7 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
.each(($child, index) => expect($child.text()).to.eq(expectedTitles[index]));
});
- it('should be able to freeze "% Complete" and expect 4th column to be freezed', () => {
+ it('should be able to pin "% Complete" and expect 4th column to be pinned', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(3)')
.trigger('mouseover')
@@ -492,16 +489,18 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(1)')
- .children('.slick-menu-content')
- .should('contain', 'Freeze Columns')
- .click();
+ .find('[data-command="pin-column"]')
+ .should('contain', 'Column Pinning')
+ .trigger('mouseover');
+
+ cy.get('.slick-submenu:visible [data-command="pin-columns"]').should('contain', 'Pin Through Here').click();
});
- it('should have a persisted frozen column after "Description" and a grid with 4 containers on page load with 2 columns on the left and 3 columns on the right', () => {
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 4);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]').children().should('have.length', 3);
+ it('should have a persisted pinned column after "Description" with 4 pinned and 3 scrolling columns', () => {
+ const firstRow = '#grid15 .slick-row[data-row="0"]';
+ cy.get(firstRow).should('have.length', 1);
+ cy.get(`${firstRow} .slick-pinned-left-cells > .slick-cell`).should('have.length', 4);
+ cy.get(`${firstRow} .slick-scrolling-cells > .slick-cell`).should('have.length', 3);
});
describe('Filter Shortcuts', () => {
@@ -599,9 +598,9 @@ describe('Example 15: Grid State & Presets using Local Storage', () => {
expect(Number($span.text())).to.gt(80);
});
- cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).contains('desc');
- cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).contains('desc');
- cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(2)`).contains('desc');
+ cy.get('#grid15 .slick-row[data-row="0"] .slick-cell.l2').contains('desc');
+ cy.get('#grid15 .slick-row[data-row="1"] .slick-cell.l2').contains('desc');
+ cy.get('#grid15 .slick-row[data-row="2"] .slick-cell.l2').contains('desc');
});
});
});
diff --git a/demos/react/test/cypress/e2e/example16.cy.ts b/demos/react/test/cypress/e2e/example16.cy.ts
index d9eb35e061..87d69f920c 100644
--- a/demos/react/test/cypress/e2e/example16.cy.ts
+++ b/demos/react/test/cypress/e2e/example16.cy.ts
@@ -39,7 +39,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', () => {
});
it('should expect the row to have moved to another row index', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 1');
@@ -76,7 +76,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', () => {
cy.get('@moveIconTask5').trigger('mousemove', 'bottomRight').trigger('mouseup', 'bottomRight', { which: 1, force: true });
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).should('contain', 'Task 1');
diff --git a/demos/react/test/cypress/e2e/example19.cy.ts b/demos/react/test/cypress/e2e/example19.cy.ts
index babe74c51a..d17f2c9055 100644
--- a/demos/react/test/cypress/e2e/example19.cy.ts
+++ b/demos/react/test/cypress/e2e/example19.cy.ts
@@ -80,7 +80,7 @@ describe('Example 19 - Row Detail View', () => {
cy.get('@detailContainer').find('[data-test=delete-btn]').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('#grid19')
.find('.slick-row')
@@ -111,7 +111,7 @@ describe('Example 19 - Row Detail View', () => {
cy.get('[data-test=collapse-all-btn]').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('#grid19').find('.dynamic-cell-detail .innerDetailView_0 .container_0').should('not.exist');
@@ -175,7 +175,7 @@ describe('Example 19 - Row Detail View', () => {
cy.get('#grid19').find('.slick-header-column:nth(1)').find('.slick-sort-indicator-asc').should('have.length', 1);
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('#grid19').find('.dynamic-cell-detail .innerDetailView_0 .container_0').should('not.exist');
diff --git a/demos/react/test/cypress/e2e/example20.cy.ts b/demos/react/test/cypress/e2e/example20.cy.ts
index 11481d0d77..91c8f4b076 100644
--- a/demos/react/test/cypress/e2e/example20.cy.ts
+++ b/demos/react/test/cypress/e2e/example20.cy.ts
@@ -1,102 +1,172 @@
-describe('Example 20 - Frozen Grid', () => {
- // NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
-
- const fullTitles = [
- '#',
- 'Title',
- '% Complete',
- 'Start',
- 'Finish',
- 'Cost | Duration',
- 'Effort Driven',
- 'Title 1',
- 'Title 2',
- 'Title 3',
- 'Title 4',
- ];
+describe('Example 20 - Pinned Grid', () => {
+ before(() => {
+ // The framework demos include a 250px route sidebar. Use enough width for
+ // the two-column pinning scenario to remain valid with that sidebar.
+ cy.viewport(1440, 900);
+ });
+
+ const withTitleRowTitles = ['Sel', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ const withoutTitleRowTitles = ['', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ const getCell = (rowIndex: number, columnIndex: number) =>
+ cy.get(`#grid20 .slick-row[data-row="${rowIndex}"] .slick-cell.l${columnIndex}`);
+ const setRightPinning = (count: number) => {
+ cy.get('.pinned-right-column-count').clear().type(`${count}`);
+ cy.get('[data-test="set-pinned-right-column"]').click();
+ };
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/example20`);
- cy.get('h2').should('contain', 'Example 20: Pinned (frozen) Columns/Rows');
+ cy.get('h2').should('contain', 'Example 20: Pinned Columns/Rows');
});
it('should have exact column titles on 1st grid', () => {
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
+ });
+
+ it('should hide sub-title to provide more space for the grid', () => {
+ cy.get('[data-test="toggle-subtitle"]').click();
});
it('should have exact Column Header Titles in the grid', () => {
cy.get('#grid20')
- .find('.slick-header-columns:nth(0)')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns:nth(0) .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
- it('should have a frozen grid with 4 containers on page load with 3 columns on the left and 4 columns on the right', () => {
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2 * 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ it('should have three top-pinned rows and left/center/right cells on page load', () => {
+ const row0 = '#grid20 .slick-row[data-row="0"]';
+
+ // Pinning uses one row node split into regions and a single docking overlay;
+ // it no longer duplicates rows into legacy left/right pinned canvases.
+ cy.get('#grid20 .slick-docking-overlay > .slick-row.slick-row-pinned-top').should('have.length', 3);
+ cy.get(`${row0} .slick-pinned-left-cells > .slick-cell`).should('have.length', 3);
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell`).should('have.length', 5);
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell`).should('have.length', 1);
+
+ cy.get(`${row0} .slick-pinned-left-cells > .slick-cell:nth(0)`).should('contain', '');
+ cy.get(`${row0} .slick-pinned-left-cells > .slick-cell:nth(1)`).should('contain', 'Task 0');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(0)`).should('contain', '2009-01-01');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(1)`).should('contain', '2009-05-05');
+
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell:nth(0) .cell-menu-dropdown`).should('contain', 'Action');
+ });
+
+ it('should pin multiple columns on the right and render matching header and filter regions', () => {
+ setRightPinning(2);
+
+ const row0 = '#grid20 .slick-row[data-row="0"]';
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell`).should('have.length', 2);
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell.l7`).should('contain', 'Boston');
+ cy.get(`${row0} .slick-pinned-right-cells > .slick-cell.l8 .cell-menu-dropdown`).should('contain', 'Action');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('#grid20 .slick-header-columns-right .slick-header-column').should('have.length', 2);
+ cy.get('#grid20 .slick-header-columns-right [data-id="cityOfOrigin"]').should('contain', 'City of Origin');
+ cy.get('#grid20 .slick-header-columns-right [data-id="action"]').should('contain', 'Action');
+ cy.get('#grid20 .slick-headerrow-columns-right .slick-headerrow-column').should('have.length', 2);
+ cy.get('#grid20 .slick-headerrow-columns-right .slick-headerrow-column.l7 input').should('exist');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ setRightPinning(1);
+ });
+
+ it('should keep multiple right-pinned columns fixed while scrolling', () => {
+ setRightPinning(2);
+ // The default fixture fits in the viewport, so use the demo's wide layout
+ // to exercise an actual horizontal scroll rather than a no-op scroll.
+ cy.get('[data-test="set-large-pinned-columns"]').click();
+ const actionCell = '#grid20 .slick-row[data-row="10"] .slick-pinned-right-cells .slick-cell.l8';
+
+ cy.get(actionCell).then(($cell) => {
+ const rightEdge = $cell[0].getBoundingClientRect().right;
+ cy.get('#grid20 .slick-horizontal-scroller').scrollTo('right');
+ cy.get(actionCell).should(($scrolledCell) => {
+ expect(Math.abs($scrolledCell[0].getBoundingClientRect().right - rightEdge)).to.be.lessThan(2);
+ });
+ });
+
+ cy.get('#grid20 .slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ // Restore the initial fixture after exercising the wide layout so the
+ // following serial tests do not inherit resized columns.
+ cy.visit(`${Cypress.config('baseUrl')}/example20`);
+ });
+
+ it('should resize columns while left and right pinning are active', () => {
+ cy.visit(`${Cypress.config('baseUrl')}/example20`);
+
+ const resizeColumn = (columnSelector: string, pinClass: string) => {
+ cy.get(columnSelector).should('have.class', pinClass);
+ cy.get(`${columnSelector} .slick-resizable-handle`)
+ .should('exist')
+ .then(($handle) => {
+ const header = $handle.closest('.slick-header-column')[0] as HTMLElement;
+ const initialWidth = header.getBoundingClientRect().width;
+
+ cy.wrap($handle).trigger('mousedown', { which: 1, pageX: 100, clientX: 100, force: true });
+ cy.get('body').trigger('mousemove', { which: 1, pageX: 125, clientX: 125, force: true });
+ cy.get('body').trigger('mousemove', { which: 1, pageX: 150, clientX: 150, force: true });
+ cy.get('body').trigger('mouseup', { which: 1, pageX: 150, clientX: 150, force: true });
+
+ cy.get(columnSelector).should(($updatedHeader) => {
+ expect($updatedHeader[0].getBoundingClientRect().width).to.be.greaterThan(initialWidth);
+ });
+ });
+ };
+
+ resizeColumn('#grid20 .slick-header-columns-left [data-id="title"]', 'slick-column-pinned-left');
+
+ // Use City of Origin because Action has a maxWidth of 100px and would refuse a wider resize.
+ setRightPinning(2);
+ resizeColumn('#grid20 .slick-header-columns-right [data-id="cityOfOrigin"]', 'slick-column-pinned-right');
+
+ // Keep the following serial tests on the demo's default configuration.
+ cy.visit(`${Cypress.config('baseUrl')}/example20`);
});
- it('should hide "Title" column from Grid Menu and expect last frozen column to be "% Complete"', () => {
- const newColumnList = [
- '#',
- '% Complete',
- 'Start',
- 'Finish',
- 'Cost | Duration',
- 'Effort Driven',
- 'Title 1',
- 'Title 2',
- 'Title 3',
- 'Title 4',
- ];
+ it('should disable and re-enable right pinning through the numeric grid control', () => {
+ setRightPinning(0);
+ cy.get('#grid20 .slick-row[data-row="0"] .slick-pinned-right-cells').should('exist');
+ cy.get('#grid20 .slick-row[data-row="0"] .slick-pinned-right-cells > .slick-cell').should('not.exist');
+ cy.get('#grid20 .slick-header-columns-right .slick-header-column').should('not.exist');
+
+ setRightPinning(1);
+ cy.get('#grid20 .slick-row[data-row="0"] .slick-pinned-right-cells > .slick-cell.l8').should('contain', 'Action');
+ cy.get('#grid20 .slick-header-columns-right [data-id="action"]').should('contain', 'Action');
+ });
+
+ it('should hide "Title" column from Grid Menu and expect last pinned column to be "% Complete"', () => {
+ const newColumnList = ['Sel', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ const row0 = '#grid20 .slick-row[data-row="0"]';
cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
cy.get('#grid20')
.get('.slick-grid-menu:visible')
.find('.slick-column-picker-list')
- .children('li:visible:nth(1)')
+ .children('li:visible:nth(0)')
.children('label')
.should('contain', 'Title')
.click({ force: true });
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
+ .find('.slick-header-columns .slick-header-column')
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 2 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 2);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 5);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').children().should('have.length', 1);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(0)`).should('contain', '2009-01-01');
+ cy.get(`${row0} .slick-scrolling-cells > .slick-cell:nth(1)`).should('contain', '2009-05-05');
});
- it('should show again "Title" column from Grid Menu and expect last frozen column to still be "% Complete"', () => {
+ it('should show again "Title" column from Grid Menu and expect last pinned column to still be "% Complete"', () => {
cy.get('#grid20')
.get('.slick-grid-menu:visible')
.find('.slick-column-picker-list')
- .children('li:visible:nth(1)')
+ .children('li:visible:nth(0)')
.children('label')
.should('contain', 'Title')
.click({ force: true });
@@ -104,77 +174,60 @@ describe('Example 20 - Frozen Grid', () => {
cy.get('#grid20').get('.slick-grid-menu:visible').find('.close').click({ force: true });
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 3);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 5);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').children().should('have.length', 1);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ cy.get('.slick-scrolling-cells .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-scrolling-cells .slick-cell:nth(1)').should('contain', '2009-05-05');
});
- it('should hide "Title" column from Header Menu and expect last frozen column to be "% Complete"', () => {
- const newColumnList = [
- '#',
- '% Complete',
- 'Start',
- 'Finish',
- 'Cost | Duration',
- 'Effort Driven',
- 'Title 1',
- 'Title 2',
- 'Title 3',
- 'Title 4',
- ];
+ it('should hide "Title" column from Header Menu and expect last pinned column to be "% Complete"', () => {
+ const newColumnList = ['Sel', '% Complete', 'Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
- cy.get('#grid20')
- .find('.slick-header-column:nth(1)')
- .trigger('mouseover')
- .children('.slick-header-menu-button')
- .should('be.hidden')
- .invoke('show')
- .click();
+ cy.get('#grid20').find('.slick-header-column:nth(1)').trigger('mouseover').children('.slick-header-menu-button').invoke('show').click();
cy.get('.slick-header-menu .slick-menu-command-list')
.should('be.visible')
- .children('.slick-menu-item:nth-of-type(8)')
+ .children('.slick-menu-item:nth-of-type(9)')
.children('.slick-menu-content')
.should('contain', 'Hide Column')
.click();
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
+ .find('.slick-header-columns .slick-header-column')
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 2 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 2);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 5);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').children().should('have.length', 1);
+
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ });
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ it('should toggle right pinned column and expect only 2 left/center containers to be visible', () => {
+ cy.get('[data-test="toggle-pinned-right"]').click();
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 2);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 6);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells').should('exist').and('not.have.class', 'slick-pinned-right-cells-active');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-right-cells > .slick-cell').should('not.exist');
});
- it('should show again "Title" column from Column Picker and expect last frozen column to still be "% Complete"', () => {
- cy.get('#grid20').find('.slick-header-column:nth(5)').trigger('mouseover').trigger('contextmenu').invoke('show');
+ it('should show again "Title" column from Column Picker and expect last pinned column to still be "% Complete"', () => {
+ cy.get('#grid20').find('.slick-header-column:nth(4)').trigger('mouseover').trigger('contextmenu').invoke('show');
cy.get('.slick-column-picker')
.find('.slick-column-picker-list')
- .children('li:nth-child(2)')
+ .children('li:nth-of-type(2)')
.children('label')
.should('contain', 'Title')
.click();
@@ -182,83 +235,769 @@ describe('Example 20 - Frozen Grid', () => {
cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
cy.get('#grid20')
- .find('.slick-header-columns')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 3);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 6);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(1)').should('contain', 'Task 0');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(1)').should('contain', '2009-05-05');
});
- it('should click on the "Remove Frozen Columns" button to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
- cy.get('[data-test=remove-frozen-column-button]').click({ force: true });
+ it('should click on the "Remove Pinned Columns" button to switch to a regular grid view without pinned columns and expect 7 columns on the left container', () => {
+ cy.get('[data-test=remove-pinned-column-button]').click({ force: true });
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 1 * 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 11 * 2);
+ cy.get('#grid20 .slick-row[data-row="0"]').should('have.length.at.least', 1);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').should('exist').and('not.have.class', 'slick-pinned-left-cells-active');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell').should('have.length', 9);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ getCell(0, 0).should('contain', '');
+ getCell(0, 1).should('contain', 'Task 0');
+ getCell(0, 3).should('contain', '2009-01-01');
+ getCell(0, 4).should('contain', '2009-05-05');
+ });
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(3)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '2009-05-05');
+ it('should expect to have exact Column Header Titles in the grid', () => {
+ cy.get('#grid20')
+ .find('.slick-header-columns:nth(0) .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
- it('should have exact Column Header Titles in the grid', () => {
+ it('should click on the "Set 3 Pinned Columns" button to switch pinned columns grid and expect 3 pinned columns on the left and 4 columns on the right', () => {
+ cy.get('[data-test=set-3pinned-columns]').click({ force: true });
+
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').children().should('have.length', 3);
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells').children().should('have.length', 6);
+
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(0)').should('contain', '');
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells > .slick-cell:nth(1)').should('contain', 'Task 0');
+
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(0)').should('contain', '2009-01-01');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ });
+
+ it('should recheck again and still have exact Column Header Titles in the grid', () => {
cy.get('#grid20')
- .find('.slick-header-columns:nth(0)')
- .children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .find('.slick-header-columns:nth(0) .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
- it('should click on the "Set 3 Frozen Columns" button to switch frozen columns grid and expect 3 frozen columns on the left and 4 columns on the right', () => {
- cy.get('[data-test=set-3frozen-columns]').click({ force: true });
+ it('should click on the Grid Menu command "Unpin Columns/Rows" to switch to a regular grid without pinned columns/rows', () => {
+ cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 2 * 2);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 3 * 2);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"]')
- .children()
- .should('have.length', 8 * 2);
+ cy.contains('Unpin Columns/Rows').click({ force: true });
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('#grid20 .slick-row[data-row="0"]').should('have.length.at.least', 1);
+ cy.get('.slick-row[data-row="0"] .slick-pinned-left-cells').should('exist').and('not.have.class', 'slick-pinned-left-cells-active');
+ cy.get('.slick-row[data-row="0"] .slick-scrolling-cells > .slick-cell').should('have.length', 9);
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-right > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', '2009-05-05');
+ getCell(0, 0).should('contain', '');
+ getCell(0, 1).should('contain', 'Task 0');
+ getCell(0, 3).should('contain', '2009-01-01');
+ getCell(0, 4).should('contain', '2009-05-05');
});
- it('should have exact Column Header Titles in the grid', () => {
+ it('should open the Cell Menu on 2nd and 3rd row and change the Effort-Driven to "True" and expect the cell to be updated and have checkmark icon', () => {
+ getCell(1, 1).should('contain', 'Task 1');
+ getCell(1, 8).find('.checkmark-icon').should('have.length', 0);
+ getCell(2, 1).should('contain', 'Task 2');
+ getCell(2, 8).find('.checkmark-icon').should('have.length', 0);
+
+ getCell(1, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('True').click();
+ getCell(2, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('True').click();
+
+ getCell(1, 5).find('.checkmark-icon').should('have.length', 1);
+ getCell(2, 5).find('.checkmark-icon').should('have.length', 1);
+ });
+
+ it('should open the Cell Menu on 2nd and 3rd row and change the Effort-Driven to "False" and expect the cell to be updated and no longer have checkmark', () => {
+ getCell(1, 5).find('.checkmark-icon').should('have.length', 1);
+ getCell(2, 5).find('.checkmark-icon').should('have.length', 1);
+
+ getCell(1, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('False').click();
+ getCell(2, 8).contains('Action').click({ force: true });
+ cy.get('.slick-cell-menu .slick-menu-option-list .slick-menu-item').contains('False').click();
+
+ getCell(1, 5).find('.checkmark-icon').should('have.length', 0);
+ getCell(2, 5).find('.checkmark-icon').should('have.length', 0);
+ });
+
+ it('should open the Cell Menu and delete Row 3 and 4 from the Cell Menu', () => {
+ cy.window().then((win) => {
+ const stub = cy.stub(win, 'confirm').returns(true);
+ cy.wrap(stub).as('confirmStub');
+ });
+
+ getCell(3, 1).should('contain', 'Task 3');
+ getCell(4, 1).should('contain', 'Task 4');
+
+ getCell(3, 8).contains('Action').click({ force: true });
+
+ cy.get('.slick-cell-menu .slick-menu-command-list .slick-menu-item').contains('Delete Row').click();
+ cy.get('@confirmStub').should('have.been.calledWith', 'Do you really want to delete row (4) with "Task 3"?');
+ getCell(3, 1).should('contain', 'Task 4');
+ });
+
+ it.skip('should filter autocomplete by typing Vancouver in the "City of Origin" and expect only filtered rows to show up', () => {
+ cy.get('.search-filter.filter-cityOfOrigin').type('Vancouver');
+
+ cy.get('.slick-autocomplete').should('be.visible');
+ cy.get('.slick-autocomplete div').should('have.length', 2);
+ cy.get('.slick-autocomplete').find('div:nth(0)').click();
+
+ getCell(0, 1).should('contain', 'Task 1');
+ getCell(1, 1).should('contain', 'Task 5');
+ getCell(2, 1).should('contain', 'Task 7');
+ getCell(3, 1).should('contain', 'Task 9');
+ getCell(4, 1).should('contain', 'Task 11');
+ });
+
+ it('should Clear all Filters', () => {
+ cy.get('#grid20').find('button.slick-grid-menu-button').trigger('click').click({ force: true });
+
+ cy.get(`.slick-grid-menu:visible`).find('.slick-menu-item').first().find('span').contains('Clear all Filters').click();
+ });
+
+ it.skip('should edit first row (Task 1) and change its city by choosing it inside the autocomplete editor list', () => {
+ getCell(0, 7).click();
+ cy.get('input.autocomplete.editor-cityOfOrigin').type('Sydney');
+
+ cy.get('.slick-autocomplete').should('be.visible');
+ cy.get('.slick-autocomplete div').should('have.length', 3);
+ cy.get('.slick-autocomplete').find('div:nth(1)').click();
+
+ getCell(0, 1).should('contain', 'Task 0');
+ getCell(0, 7).should('contain', 'Sydney, NS, Australia');
+ });
+
+ it('should open Context Menu hover "% Complete" column then select "Not Started (0%)" option and expect Task to be at 0', () => {
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu .slick-menu-option-list').should('exist').contains('Not Started (0%)').click();
+
+ getCell(0, 2).should('contain', '0');
+ });
+
+ it('should reopen Context Menu hover "% Complete" column then open options sub-menu & select "Half Completed (50%)" option and expect Task to be at 50', () => {
+ const subOptions = ['Not Started (0%)', 'Half Completed (50%)', 'Completed (100%)'];
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-option-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Sub-Options (demo)')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-option-list').as('subMenuList');
+ cy.get('@subMenuList').find('.slick-menu-title').contains('Set Percent Complete');
+ cy.get('@subMenuList')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.eq(subOptions[index]));
+
+ cy.get('@subMenuList').find('.slick-menu-item .slick-menu-content').contains('Half Completed (50%)').click();
+
+ getCell(0, 2).should('contain', '50');
+ });
+
+ it('should be able to open Context Menu and click on Export->Text and expect alert triggered with Text Export', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list').find('.slick-menu-item').contains('Text').click();
+ cy.get('@alertStub').should('have.been.calledWith', 'Exporting as Text (tab delimited)');
+ });
+
+ it('should be able to open Context Menu and click on Export->Excel-> sub-commands to see 1 context menu + 1 sub-menu then clicking on Text should call alert action', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ const subCommands2 = ['Excel (csv)', 'Excel (xlsx)'];
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Excel')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list').as('subMenuList2');
+
+ cy.get('@subMenuList2').find('.slick-menu-title').contains('available formats');
+
+ cy.get('@subMenuList2')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Excel (xlsx)')
+ .click();
+ cy.get('@alertStub').should('have.been.calledWith', 'Exporting as Excel (xlsx)');
+ });
+
+ it('should open Export->Excel sub-menu & open again Sub-Options on top and expect sub-menu to be recreated with that Sub-Options list instead of the Export->Excel list', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ const subCommands2 = ['Excel (csv)', 'Excel (xlsx)'];
+ const subOptions = ['Not Started (0%)', 'Half Completed (50%)', 'Completed (100%)'];
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick();
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Excel')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-option-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Sub-Options')
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-option-list').as('optionSubList2');
+
+ cy.get('@optionSubList2').find('.slick-menu-title').contains('Set Percent Complete');
+
+ cy.get('@optionSubList2')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($option, index) => expect($option.text()).to.contain(subOptions[index]));
+ });
+
+ it('should open Export->Excel context sub-menu then open Feedback->ContactUs sub-menus and expect previous Export menu to no longer exists', () => {
+ const subCommands1 = ['Text', 'Excel'];
+ const subCommands2 = ['Request update from supplier', '', 'Contact Us'];
+ const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment'];
+
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+
+ getCell(0, 2).should('contain', '0');
+ getCell(0, 2).rightclick({ force: true });
+
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains(/^Exports$/)
+ .click();
+
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
+
+ // click different sub-menu
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Feedback')
+ .should('exist')
+ .click();
+
+ cy.get('.slick-submenu').should('have.length', 1);
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list')
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
+
+ // click on Feedback->ContactUs
+ cy.get('.slick-context-menu.slick-menu-level-1.dropright') // right align
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Contact Us')
+ .should('exist')
+ .trigger('mouseover'); // mouseover or click should work
+
+ cy.get('.slick-submenu').should('have.length', 2);
+ cy.get('.slick-context-menu.slick-menu-level-2.dropright') // right align
+ .should('exist')
+ .find('.slick-menu-item .slick-menu-content')
+ .each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index]));
+
+ cy.get('.slick-context-menu.slick-menu-level-2');
+
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list')
+ .find('.slick-menu-item .slick-menu-content')
+ .contains('Chat with us')
+ .click();
+ cy.get('@alertStub').should('have.been.calledWith', 'Command: contact-chat');
+
+ cy.get('.slick-submenu').should('have.length', 0);
+ });
+
+ it('should toggle Select All checkbox and expect back "Sel" column title to show when Select All checkbox is shown in the header row', () => {
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('contain', 'Sel');
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
+
+ cy.get('[data-test="toggle-select-all-row"]').click();
+
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('not.contain', 'Sel');
+
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withoutTitleRowTitles[index]));
+ });
+
+ it('should toggle back Select All checkbox and expect back "Sel" column title to show when Select All checkbox is shown in the header row', () => {
+ cy.get('[data-test="toggle-select-all-row"]').click();
+
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('contain', 'Sel');
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
+
+ cy.get('[data-test="toggle-select-all-row"]').click();
+
+ cy.get('.slick-header-column:nth(0)').find('.slick-column-name').should('not.contain', 'Sel');
+
+ cy.get('.slick-header-columns .slick-header-column').each(($child, index) => expect($child.text()).to.eq(withoutTitleRowTitles[index]));
+ });
+
+ it('should open Column Picker and try unchecked all the columns on the right of the column pinning and expect an error and abort of the execution', () => {
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+ cy.get('[data-test=set-3pinned-columns]').click({ force: true });
+
+ const leftColumns = ['', 'Title', '% Complete'];
+ const rightColumns = ['Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+ cy.get('#grid20').find('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+
+ cy.get('.slick-column-picker')
+ .find('.slick-column-picker-list')
+ .children()
+ .each(($child, index) => {
+ if (index >= leftColumns.length) {
+ if ($child.text() === rightColumns[index - leftColumns.length]) {
+ expect($child.text()).to.eq(rightColumns[index - leftColumns.length]);
+ if (index <= rightColumns.length + 1) {
+ cy.wrap($child).children('label').click();
+ } else {
+ cy.wrap($child)
+ .children('label')
+ .click()
+ .then(() => {
+ cy.get('@alertStub').should(
+ 'have.been.calledWith',
+ '[SlickGrid] Action not allowed and aborted, you need to have at least one or more column in the center section of the grid. ' +
+ 'You could alternatively unpin columns before trying again.'
+ );
+ });
+ }
+ }
+ }
+ });
+
+ cy.get('button[data-dismiss="slick-column-picker"]').click();
+ });
+
+ it('should also not be able to "Hide Column" via the Header Menu', () => {
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+ const newColumnList = ['', 'Title', '% Complete', 'Action'];
+
+ cy.get('#grid20').find('.slick-header-column:nth(3)').trigger('mouseover').children('.slick-header-menu-button').invoke('show').click();
+
+ cy.get('.slick-header-menu .slick-menu-command-list')
+ .should('be.visible')
+ .children('.slick-menu-item')
+ .contains('Hide Column')
+ .click()
+ .then(() => {
+ cy.get('@alertStub').should(
+ 'have.been.calledWith',
+ '[SlickGrid] Action not allowed and aborted, you need to have at least one or more column in the center section of the grid. ' +
+ 'You could alternatively unpin columns before trying again.'
+ );
+ });
+
cy.get('#grid20')
- .find('.slick-header-columns:nth(0)')
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
+ });
+
+ it('should be able to uncheck "Title" column without any alert', () => {
+ cy.get('#grid20').find('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+ const updatedColumns = ['', '% Complete', 'Action'];
+ cy.get('.slick-column-picker-list li:not(.hidden) .checkbox-picker-label').first().click();
+ cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
+ cy.get('.slick-header-columns:nth(0) .slick-header-column').each(($child, index) => expect($child.text()).to.eq(updatedColumns[index]));
+ });
+
+ it('should be able to add back hidden "Title" column without any alert', () => {
+ const updatedColumns = ['', 'Title', '% Complete', 'Action'];
+ cy.get('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+ cy.get('.slick-column-picker-list li:not(.hidden) .checkbox-picker-label').first().click();
+ cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
+ cy.get('.slick-header-columns:nth(0) .slick-header-column').each(($child, index) => expect($child.text()).to.eq(updatedColumns[index]));
+ });
+
+ it('should reset hidden column from the Column Picker and expect all columns to be back', () => {
+ const leftColumns = ['', 'Title', '% Complete'];
+ const rightColumns = ['Start', 'Finish', 'Completed', 'Cost | Duration', 'City of Origin', 'Action'];
+
+ cy.get('.slick-header-column').first().trigger('mouseover').trigger('contextmenu').invoke('show');
+ cy.get('.slick-column-picker')
+ .find('.slick-column-picker-list')
.children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .each(($child, index) => {
+ if (index >= leftColumns.length) {
+ if ($child.text() === rightColumns[index - leftColumns.length]) {
+ expect($child.text()).to.eq(rightColumns[index - leftColumns.length]);
+ if (index <= rightColumns.length + 1) {
+ cy.wrap($child).children('label').click();
+ }
+ }
+ }
+ });
+
+ cy.get('.slick-column-picker:visible').find('.close').trigger('click').click();
+
+ cy.get('#grid20')
+ .find('.slick-header-columns .slick-header-column')
+ .each(($child, index) => expect($child.text()).to.eq(withoutTitleRowTitles[index]));
});
- it('should click on the Grid Menu command "Unfreeze Columns/Rows" to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
- cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
+ describe('Test UI rendering after Scrolling with large columns', () => {
+ it('should unpin all columns/rows', () => {
+ cy.get('#grid20').find('button.slick-grid-menu-button').click({ force: true });
+
+ cy.contains('Unpin Columns/Rows').click({ force: true });
+ });
+
+ it('should resize all columns and make them wider', () => {
+ // resize CityOfOrigin column
+ cy.get('.slick-header-columns .slick-header-column:nth(7)').should('contain', 'City of Origin');
+
+ cy.get('.slick-resizable-handle:nth(7)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(8)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
- cy.contains('Unfreeze Columns/Rows').click({ force: true });
+ // resize Cost|Duration column
+ cy.get('.slick-header-columns .slick-header-column:nth(6)').should('contain', 'Cost | Duration');
- cy.get('[style="transform: translateY(0px);"]').should('have.length', 1);
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 11);
+ cy.get('.slick-resizable-handle:nth(6)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '0');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
+ cy.get('.slick-header-column:nth(8)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Completed column
+ cy.get('.slick-header-columns .slick-header-column:nth(5)').should('contain', 'Completed');
+
+ cy.get('.slick-resizable-handle:nth(5)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(7)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Finish column
+ cy.get('.slick-header-columns .slick-header-column:nth(4)').should('contain', 'Finish');
+
+ cy.get('.slick-resizable-handle:nth(4)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(6)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Start column
+ cy.get('.slick-header-columns .slick-header-column:nth(3)').should('contain', 'Start');
+
+ cy.get('.slick-resizable-handle:nth(3)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(6)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize %Complete column
+ cy.get('.slick-header-columns .slick-header-column:nth(2)').should('contain', '% Complete');
+
+ cy.get('.slick-resizable-handle:nth(2)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(3)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+
+ // resize Title column
+ cy.get('.slick-header-columns .slick-header-column:nth(1)').should('contain', 'Title');
+
+ cy.get('.slick-resizable-handle:nth(1)').trigger('mousedown', { which: 1, force: true }).trigger('mousemove', 'bottomRight');
+
+ cy.get('.slick-header-column:nth(3)')
+ .trigger('mousemove', 'bottomRight')
+ .trigger('mouseup', 'bottomRight', { which: 1, force: true });
+ });
+
+ it('should scroll horizontally completely to the right and expect all cell to be rendered', () => {
+ getCell(2, 1).contains(/Task [0-9]*/);
+ getCell(2, 2).contains(/[0-9]*/);
+
+ getCell(15, 1).contains(/Task [0-9]*/);
+ getCell(15, 2).contains(/[0-9]*/);
+
+ // horizontal scroll to right
+ // Pinning has one real horizontal scroll owner. Scrolling the old body
+ // viewport only exercises the compatibility bridge; target the proxy
+ // here to verify the user-facing scrollbar and all chrome move together.
+ cy.get('#grid20 .slick-horizontal-scroller').scrollTo('100%', '0%', { duration: 1500 });
+ getCell(2, 3).should('contain', '2009-01-01');
+ getCell(2, 4).should('contain', '2009-05-05');
+ getCell(2, 7).contains(/[United State|Canada]*/);
+ getCell(2, 8).should('contain', 'Action');
+
+ getCell(15, 3).should('contain', '2009-01-01');
+ getCell(15, 4).should('contain', '2009-05-05');
+ getCell(15, 7).contains(/[United State|Canada]*/);
+ getCell(15, 8).should('contain', 'Action');
+ });
+
+ it('should scroll vertically to the middle of the grid and expect all cell to be rendered', () => {
+ // vertical scroll to middle
+ cy.get('.slick-vertical-scroller').scrollTo('0%', '40%', { duration: 1500 });
+
+ getCell(200, 3).should('contain', '2009-01-01');
+ getCell(200, 4).should('contain', '2009-05-05');
+ getCell(200, 7).contains(/[United State|Canada]*/);
+ getCell(200, 8).should('contain', 'Action');
+
+ getCell(205, 3).should('contain', '2009-01-01');
+ getCell(205, 4).should('contain', '2009-05-05');
+ getCell(205, 7).contains(/[United State|Canada]*/);
+ getCell(205, 8).should('contain', 'Action');
+
+ // reset scroll
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ });
+ });
+
+ describe('accessibility sub-menus tests', () => {
+ beforeEach(() => {
+ // Open the context menu on a cell to start each test
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('[data-row="0"] .slick-cell.l3.r3').rightclick({ force: true });
+ cy.get('.slick-context-menu.slick-menu-level-0').should('be.visible');
+ });
+
+ it('should open Exports sub-menu with ArrowRight, then Excel sub-menu with ArrowRight, and close with ArrowLeft', () => {
+ // Move down to "Exports" (4th item)
+ cy.focused();
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-submenu-item[data-command="export"]').should('have.focus');
+
+ // Open "Exports" sub-menu with ArrowRight
+ cy.focused().type('{rightarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-1[data-sub-menu-parent="export"]').should('be.visible');
+
+ // Move down to "Excel" (2nd item in sub-menu)
+ cy.focused().type('{downarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-submenu-item[data-command="sub-menu"]').should('have.focus');
+
+ // Open "Excel" sub-menu with ArrowRight
+ cy.focused().type('{rightarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-2[data-sub-menu-parent="sub-menu"]').should('be.visible');
+
+ // Move down to "Excel (xlsx)" (2nd item in Excel sub-menu)
+ cy.focused().type('{downarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-item[data-command="exports-xlsx"]').should('have.focus');
+
+ // Close Excel sub-menu with ArrowLeft
+ cy.focused().type('{leftarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-2').should('not.exist');
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-submenu-item[data-command="sub-menu"]').should('have.focus');
+
+ // close all context menus
+ cy.get('[data-row="0"] .slick-cell.l0.r0').click();
+ });
+
+ it('should open sub-menus using Enter as well as ArrowRight', () => {
+ // Move down to "Exports"
+ cy.focused();
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.get('.slick-context-menu.slick-menu-level-0 .slick-submenu-item[data-command="export"]').should('have.focus');
+
+ // Open "Exports" sub-menu with Enter
+ cy.focused().type('{enter}');
+ cy.get('.slick-context-menu.slick-menu-level-1[data-sub-menu-parent="export"]').should('be.visible');
+
+ // Move down to "Excel"
+ cy.focused().type('{downarrow}');
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-submenu-item[data-command="sub-menu"]').should('have.focus');
+
+ // Open "Excel" sub-menu with Enter
+ cy.focused().type('{enter}');
+ cy.get('.slick-context-menu.slick-menu-level-2[data-sub-menu-parent="sub-menu"]').should('be.visible');
+
+ // close all context menus
+ cy.get('[data-row="0"] .slick-cell.l0.r0').click();
+ });
+
+ it('should activate a sub-menu leaf item with Enter', () => {
+ // Move down to "Exports"
+ cy.window().then((win) => {
+ cy.stub(win, 'alert').as('alertStub');
+ });
+ cy.focused();
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.DOWN);
+ cy.press(Cypress.Keyboard.Keys.ENTER);
+ cy.get('.slick-context-menu.slick-menu-level-1[data-sub-menu-parent="export"]').should('be.visible');
+
+ // "Text (tab delimited)" is first item, should have focus
+ cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-item[data-command="exports-txt"]').should('have.focus');
+ // Activate with Enter (add your assertion for the result)
+ cy.focused().type('{enter}');
+ });
+
+ it('should reapply 3 Pinned Columns and expect to be able to focus on first filter and go left/right between both viewports without problems', () => {
+ cy.get('[data-test="set-3pinned-columns"]').click();
+ cy.get('.slick-headerrow-column.l1 input').focus();
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l2 input').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l3 select').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l3 input').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l4 select').should('have.focus');
+ cy.press(Cypress.Keyboard.Keys.TAB);
+ cy.get('.slick-headerrow-column.l4 input').should('have.focus');
+
+ // Shift+Tab dosn't work in Cypress, so we can't go further with tests
+ });
+ });
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(3)').should('contain', '2009-01-01');
- cy.get('.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '2009-05-05');
+ describe('drag & drop column reordering with auto-scroll', () => {
+ it('should auto-scroll right viewport and reorder columns when "Start" is dragged well past the right edge (ending up after "Finish")', () => {
+ // Close the context menu opened by beforeEach
+ cy.get('body').type('{esc}');
+
+ // Control app timers to make drag auto-scroll deterministic in CI.
+ cy.clock();
+
+ // Normalize right viewport scroll so this test is isolated from previous test state.
+ cy.get('.slick-horizontal-scroller').then(($viewport) => {
+ $viewport[0].scrollLeft = 0;
+ $viewport[0].dispatchEvent(new Event('scroll', { bubbles: true }));
+ });
+ cy.get('.slick-horizontal-scroller').its('0.scrollLeft').should('equal', 0);
+ cy.get('[data-test="set-large-pinned-columns"]').click();
+
+ // Step 1: call SortableJS onStart for the "Start" column (1st center-section column).
+ // This binds the document 'drag' auto-scroll listener for the shared proxy scrollbar.
+ cy.get('.slick-header-columns-center').then(($rightHeader) => {
+ let sortInstance: any;
+ Object.keys($rightHeader[0]).forEach((prop) => {
+ if (prop.startsWith('Sortable')) {
+ sortInstance = ($rightHeader[0] as any)[prop];
+ }
+ });
+ expect(sortInstance).to.exist;
+ const startColumnEl = $rightHeader[0].querySelectorAll('.slick-header-column')[0] as HTMLElement;
+ sortInstance.options.onStart({ item: startColumnEl });
+ });
+
+ // Step 2: fire a document drag event well past the right edge (viewport-relative)
+ // to avoid CI flakiness caused by environment-dependent viewport widths.
+ cy.window().then((win) => {
+ const dragX = win.innerWidth + 1200;
+ cy.document().trigger('drag', { pageX: dragX, clientX: dragX, clientY: 50 });
+ });
+
+ // Step 3: advance mocked time so the 30ms scroll interval ticks several times.
+ cy.tick(350);
+
+ // Auto-scroll should have moved the right viewport to the right
+ cy.get('.slick-horizontal-scroller').its('0.scrollLeft').should('be.greaterThan', 0);
+
+ // Step 4: simulate the drag result — "Start" was moved to the right, past "Finish".
+ // SortableJS reads the DOM order via toArray() inside onEnd, so physically reorder the children first.
+ cy.get('.slick-header-columns-center').then(($rightHeader) => {
+ let sortInstance: any;
+ Object.keys($rightHeader[0]).forEach((prop) => {
+ if (prop.startsWith('Sortable')) {
+ sortInstance = ($rightHeader[0] as any)[prop];
+ }
+ });
+ expect(sortInstance).to.exist;
+ const startColumnEl = $rightHeader[0].querySelector('[data-id="start"]') as HTMLElement;
+ const finishColumnEl = $rightHeader[0].querySelector('[data-id="finish"]') as HTMLElement;
+ expect(startColumnEl).to.exist;
+ expect(finishColumnEl).to.exist;
+
+ // Move "Finish" before "Start" → mirrors dragging Start past Finish
+ $rightHeader[0].insertBefore(finishColumnEl, startColumnEl);
+
+ // onEnd reads the new DOM order via toArray() and calls setColumns() if the order changed
+ sortInstance.options.onEnd({ item: startColumnEl, stopPropagation: () => {} });
+ });
+
+ // The center region should now place Finish before Start. The exact
+ // region membership can vary when a large requested pin band does not
+ // fit the current viewport, so assert semantic order by column id.
+ cy.get('.slick-header-column').then(($headers) => {
+ const ids = [...$headers].map((header) => header.dataset.id);
+ expect(ids.indexOf('finish')).to.be.lessThan(ids.indexOf('start'));
+ });
+
+ // When a left band is active, its order must remain unchanged.
+ cy.get('.slick-header-columns-left').then(($leftRegion) => {
+ const left = $leftRegion.find('.slick-header-column');
+ if (left.length) {
+ expect([...left].map((header) => header.dataset.id)).to.deep.equal(['_checkbox_selector', 'title', 'percentComplete']);
+ }
+ });
+ });
});
});
diff --git a/demos/react/test/cypress/e2e/example24.cy.ts b/demos/react/test/cypress/e2e/example24.cy.ts
index c2ea74764b..b73ab056b1 100644
--- a/demos/react/test/cypress/e2e/example24.cy.ts
+++ b/demos/react/test/cypress/e2e/example24.cy.ts
@@ -232,7 +232,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => {
});
it('should check Context Menu "menuUsabilityOverride" condition and expect to not be able to open Context Menu from rows than are >= to Task 21', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('bottom').wait(25);
+ cy.get('.slick-vertical-scroller').scrollTo('bottom').wait(25);
cy.get('#grid24').find('.slick-row:nth(3) .slick-cell:nth(1)').rightclick({ force: true });
@@ -240,7 +240,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => {
});
it('should scroll back to top row and be able to open Context Menu', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top').wait(25);
+ cy.get('.slick-vertical-scroller').scrollTo('top').wait(25);
cy.get('#grid24').find('.slick-row:nth(1) .slick-cell:nth(1)').rightclick({ force: true });
diff --git a/demos/react/test/cypress/e2e/example27.cy.ts b/demos/react/test/cypress/e2e/example27.cy.ts
index 74b4750874..a6a3c1b699 100644
--- a/demos/react/test/cypress/e2e/example27.cy.ts
+++ b/demos/react/test/cypress/e2e/example27.cy.ts
@@ -157,7 +157,7 @@ describe('Example 27 - Tree Data (from a flat dataset with parentId references)'
it('should be able to update the 1st row item (Task 0)', () => {
cy.get('[data-test=update-item-btn]').contains('Update 1st Row Item').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
const now = new Date();
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
@@ -198,7 +198,7 @@ describe('Example 27 - Tree Data (from a flat dataset with parentId references)'
cy.get(`.slick-grid-menu:visible`).find('.slick-menu-item').first().find('span').contains('Clear all Filters').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
});
it('should be able to open "Task 1" and "Task 3" parents', () => {
diff --git a/demos/react/test/cypress/e2e/example28.cy.ts b/demos/react/test/cypress/e2e/example28.cy.ts
index 8f8f5e2228..123830953d 100644
--- a/demos/react/test/cypress/e2e/example28.cy.ts
+++ b/demos/react/test/cypress/e2e/example28.cy.ts
@@ -84,7 +84,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
it('should expand "pdf" folder and expect all folders to be expanded', () => {
cy.get('[data-row="4"] > .slick-cell:nth(0) .slick-group-toggle.collapsed').click();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('top', { force: true } as any);
});
it('should have default Files list', () => {
@@ -97,7 +97,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with aggregations of Sum(53.3MB) / Avg(26.65MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('center', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('center', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 151.3 MB / avg: 50.43 MB');
@@ -118,7 +118,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with updated aggregations including new pop songs of Sum(218.3MB) / Avg(54.58MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 316.3 MB / avg: 63.26 MB');
@@ -225,7 +225,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with updated aggregations including 4 pop songs of Sum(400.3MB) / Avg(66.72MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 400.3 MB / avg: 66.72 MB');
@@ -308,7 +308,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have again the pop songs folder with updated aggregations including 4 pop songs of Sum(400.3MB) / Avg(66.72MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('center', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('center', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 400.3 MB / avg: 66.72 MB');
@@ -336,7 +336,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have pop songs folder with aggregation reflecting what is displayed, Sum(316.3MB) / Avg(63.26MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('center', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('center', { force: true } as any);
cy.get('[data-row="16"] > .slick-cell:nth(0)').should('contain', 'music');
cy.get('[data-row="16"] > .slick-cell:nth(3)').should('contain', 'sum: 316.3 MB / avg: 63.26 MB');
@@ -347,7 +347,7 @@ describe('Example 28 - Tree Data (from a Hierarchical Dataset)', () => {
});
it('should have documents with same Sum as the beginning since auto-recalc is disabled, aggregation should be Sum(14.46MB) / Avg(1.45MB)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top', { force: true } as any);
+ cy.get('.slick-vertical-scroller').scrollTo('top', { force: true } as any);
cy.get('[data-row="1"] > .slick-cell:nth(0)').should('contain', 'documents');
cy.get('[data-row="1"] > .slick-cell:nth(3)').should('contain', 'sum: 14.46 MB / avg: 1.45 MB (total)');
diff --git a/demos/react/test/cypress/e2e/example38.cy.ts b/demos/react/test/cypress/e2e/example38.cy.ts
index a179cdc5cb..02b700180d 100644
--- a/demos/react/test/cypress/e2e/example38.cy.ts
+++ b/demos/react/test/cypress/e2e/example38.cy.ts
@@ -20,7 +20,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -32,7 +32,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a new total of 90 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '60');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '90');
@@ -48,7 +48,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
cy.get('[data-test="data-loaded-tag"]').should('not.have.class', 'fully-loaded');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '100');
@@ -78,7 +78,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom again and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -104,7 +104,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
it('should scroll to bottom again and expect next batch to be only 20 females appended to current dataset for a total of 50 items found in DB', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '50');
@@ -119,7 +119,7 @@ describe('Example 38 - Infinite Scroll with OData', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-test=odata-query-result]').should(($span) => {
expect($span.text()).to.eq(`$count=true&$top=30`);
@@ -130,11 +130,11 @@ describe('Example 38 - Infinite Scroll with OData', () => {
});
it('should scroll to the bottom "Group by Gender" and expect 30 more items for a total of 60 items grouped', () => {
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-test=odata-query-result]').should(($span) => {
expect($span.text()).to.eq(`$count=true&$top=30&$skip=30`);
diff --git a/demos/react/test/cypress/e2e/example39.cy.ts b/demos/react/test/cypress/e2e/example39.cy.ts
index d7091726f6..a87b8ef667 100644
--- a/demos/react/test/cypress/e2e/example39.cy.ts
+++ b/demos/react/test/cypress/e2e/example39.cy.ts
@@ -29,7 +29,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -44,7 +44,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom of the grid and expect next batch of 30 items appended to current dataset for a new total of 90 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '60');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '90');
@@ -63,7 +63,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
cy.get('[data-test="data-loaded-tag"]').should('not.have.class', 'fully-loaded');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '100');
@@ -100,7 +100,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom again and expect next batch of 30 items appended to current dataset for a total of 60 items', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '60');
@@ -135,7 +135,7 @@ describe('Example 39 - Infinite Scroll with GraphQL', () => {
it('should scroll to bottom again and expect next batch to be only 20 females appended to current dataset for a total of 50 items found in DB', () => {
cy.get('[data-test="itemCount"]').should('have.text', '30');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom');
+ cy.get('.slick-vertical-scroller').scrollTo('bottom');
cy.get('[data-test="itemCount"]').should('have.text', '50');
diff --git a/demos/react/test/cypress/e2e/example40.cy.ts b/demos/react/test/cypress/e2e/example40.cy.ts
index 4f8eeb96e2..4ef56ccdec 100644
--- a/demos/react/test/cypress/e2e/example40.cy.ts
+++ b/demos/react/test/cypress/e2e/example40.cy.ts
@@ -25,14 +25,14 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
it('should scroll to bottom of the grid and expect next batch of 50 items appended to current dataset for a total of 100 items', () => {
cy.get('[data-test="totalItemCount"]').should('have.text', '50');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '100');
});
it('should scroll to bottom of the grid again and expect 50 more items for a total of now 150 items', () => {
cy.get('[data-test="totalItemCount"]').should('have.text', '100');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '150');
});
@@ -42,7 +42,7 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
cy.get('[data-id="title"]').click();
cy.get('[data-test="totalItemCount"]').should('have.text', '150');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0)').should('contain', 'Task 0');
cy.get('[data-row="1"] > .slick-cell:nth(0)').should('contain', 'Task 1');
@@ -55,7 +55,7 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
cy.get('[data-id="title"]').click();
cy.get('[data-test="totalItemCount"]').should('have.text', '50');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0)').should('contain', 'Task 9');
cy.get('[data-row="1"] > .slick-cell:nth(0)').should('contain', 'Task 8');
@@ -68,17 +68,17 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
cy.get('[data-test="totalItemCount"]').should('have.text', '50');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-toggle.expanded').should('have.length', 1);
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-title').contains(/Duration: [0-9]/);
});
it('should scroll to the bottom "Group by Duration" and expect 50 more items for a total of 100 items grouped', () => {
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '100');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-toggle.expanded').should('have.length', 1);
cy.get('[data-row="0"] > .slick-cell:nth(0) .slick-group-title').contains(/Duration: [0-9]/);
});
@@ -103,12 +103,12 @@ describe('Example 40 - Infinite Scroll from JSON data', () => {
it('should load 200 items and filter "Start" column with <=2020-08-25', () => {
cy.get('[data-test="set-dynamic-filter"]').click();
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '150');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('bottom', { timeout: 100 });
+ cy.get('.slick-vertical-scroller').scrollTo('bottom', { timeout: 100 });
cy.get('[data-test="totalItemCount"]').should('have.text', '200');
- cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get(`[data-row=0] > .slick-cell:nth(3)`).contains(/^Aug [0-9]{2}, 2020$/);
cy.get(`[data-row=1] > .slick-cell:nth(3)`).contains(/^Aug [0-9]{2}, 2020$/);
diff --git a/demos/react/test/cypress/e2e/example43.cy.ts b/demos/react/test/cypress/e2e/example43.cy.ts
index c184db9802..ca0c3b17cb 100644
--- a/demos/react/test/cypress/e2e/example43.cy.ts
+++ b/demos/react/test/cypress/e2e/example43.cy.ts
@@ -1,4 +1,4 @@
-describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 1 }, () => {
+describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 0 }, () => {
const GRID_ROW_HEIGHT = 30;
const fullTitles = [
'Employee ID',
@@ -27,15 +27,23 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 1 },
cy.get('h2').should('contain', 'Example 43: colspan/rowspan - Employees Timesheets');
});
+ it('should hide sub-title', () => {
+ cy.get('[data-test=toggle-subtitle]').click();
+ });
+
it('should have exact column titles', () => {
cy.get('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
- it('should expect 1st column to be frozen (frozen)', () => {
- cy.get('.grid-canvas-left .slick-cell.frozen').should('have.length', 10);
- cy.get('.grid-canvas-right .slick-cell:not(.frozen)').should('have.length.above', 50);
+ it('should expect 1st column to be pinned', () => {
+ // Pinning uses one live canvas and splits each row into left/center/right
+ // regions; the old grid-canvas-left/right pinned panes no longer exist.
+ cy.get('.slick-pinned-left-cells .slick-cell.slick-cell-pinned-left').should('have.length', 10);
+ // The shared Vue Cypress viewport is 1200px wide, but its route sidebar
+ // leaves less room for center-column virtualization than the Vanilla app.
+ cy.get('.slick-scrolling-cells .slick-cell').should('have.length.above', 50);
});
it('should not display any Column Picker in the Grid Menu', () => {
@@ -47,32 +55,32 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 1 },
describe('Spanning', () => {
it('should expect "Davolio", "Check Mail", and "Development" to all have rowspan of 2 in morning hours', () => {
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should(($el) =>
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should(($el) =>
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
});
it('should expect "Lunch Break" to span over 3 columns and over all rows', () => {
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10)
);
});
it('should expect a large "Development" section that spans over multiple columns & rows in the afternoon', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should(($el) =>
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5)
);
});
@@ -80,334 +88,340 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 1 },
describe('Basic Key Navigations', () => {
it('should start at Employee 10001, then type "End" key and expect to be in "Team Meeting" between 4:30-5:00pm', () => {
- cy.get('[data-row=0] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l0.r0.active').should('contain', '10001');
+ cy.get('[data-row=0] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l0.r0.active').should('contain', '10001');
cy.get('@active_cell').type('{end}');
- cy.get('[data-row=0] > .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
});
it('should start at Employee 10002, then type "End" key and also expect to be in "Team Meeting" between 4:30-5:00pm', () => {
- cy.get('[data-row=1] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=1] > .slick-cell.l0.r0.active').should('contain', '10002');
+ cy.get('[data-row=1] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=1] .slick-cell.l0.r0.active').should('contain', '10002');
cy.get('@active_cell').type('{end}');
- cy.get('[data-row=0] > .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l17.r18.active').should('contain', 'Team Meeting');
});
it('should start at Employee 10004, then type "ArrowRight" key twice and expect to be in "Check Mail" between 9:00-10:30am', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}');
- cy.get('[data-row=2] > .slick-cell.l2.r4.active').should('contain', 'Check Mail');
+ cy.get('[data-row=2] .slick-cell.l2.r4.active').should('contain', 'Check Mail');
});
it('should start at Employee 10004, then type "ArrowRight" key 4x times and expect to be in "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}{rightarrow}{rightarrow}');
- cy.get('[data-row=3] > .slick-cell.l6.r9.active').should('contain', 'Testing');
+ cy.get('[data-row=3] .slick-cell.l6.r9.active').should('contain', 'Testing');
});
it('should start at Employee 10004, then type "ArrowRight" key 5x times and expect to be in "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}{rightarrow}{rightarrow}{rightarrow}');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, then type "ArrowRight" key 6x times and expect to be in "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{rightarrow}{rightarrow}{rightarrow}{rightarrow}{rightarrow}{rightarrow}');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
// then rollback by going backward
it('should be on Employee 10004 row at previous "Development" cell, then type "ArrowLeft" key once and expect to be in "Lunch Break"', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).as('active_cell').click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ // The proxy scrollbar is a sibling of the canvas, so native
+ // scrollIntoView() cannot reveal a horizontally virtualized cell.
+ cy.get('.slick-horizontal-scroller').scrollTo('right', { ensureScrollable: false });
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).as('active_cell').scrollIntoView().click();
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
cy.get('@active_cell').type('{leftarrow}');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key once and expect to be in "Conference" between 4:00-5:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).type('{leftarrow}');
- cy.get(`[data-row=3] > .slick-cell.l16.r17.active`).should('contain', 'Conference');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).type('{leftarrow}');
+ cy.get(`[data-row=3] .slick-cell.l16.r17.active`).should('contain', 'Conference');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key 3x times and expect to be back to "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).type('{leftarrow}{leftarrow}{leftarrow}');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).type('{leftarrow}{leftarrow}{leftarrow}');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key 4x times and expect to be back to "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "ArrowLeft" key 5x times and expect to be back to "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}');
- cy.get(`[data-row=3] > .slick-cell.l6.r9.active`).should('contain', 'Testing');
+ cy.get(`[data-row=3] .slick-cell.l6.r9.active`).should('contain', 'Testing');
});
// going down
it('should start at 10am "Team Meeting, then type "ArrowDown" key once and expect to be in "Support" between 9:30-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}');
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key twice and expect to be in "Check Email" between 9:00-10:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 3x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}');
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}');
- cy.get(`[data-row=5] > .slick-cell.l4.r6.active`).should('contain', 'Support');
+ cy.get(`[data-row=5] .slick-cell.l4.r6.active`).should('contain', 'Support');
});
// going up from inverse
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" once and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}');
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 2x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}{uparrow}');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 3x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}{uparrow}{uparrow}');
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 4x times and expect to be back to same "Team Meeting"', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('@active_cell').type('{downarrow}{downarrow}{downarrow}{downarrow}{uparrow}{uparrow}{uparrow}{uparrow}');
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
});
});
describe('Grid Navigate Functions', () => {
it('should start at Employee 10004, then type "Navigate Right" twice and expect to be in "Check Mail" between 9:00-10:30am', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
cy.get('[data-test="goto-next"]').click().click();
- cy.get('[data-row=2] > .slick-cell.l2.r4.active').should('contain', 'Check Mail');
+ cy.get('[data-row=2] .slick-cell.l2.r4.active').should('contain', 'Check Mail');
});
it('should start at Employee 10004, then type "Navigate Right" 4x times and expect to be in "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('[data-test="goto-next"]').click().click().click().click();
- cy.get('[data-row=3] > .slick-cell.l6.r9.active').should('contain', 'Testing');
+ cy.get('[data-row=3] .slick-cell.l6.r9.active').should('contain', 'Testing');
});
it('should start at Employee 10004, then type "Navigate Right" 5x times and expect to be in "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('[data-test="goto-next"]').click().click().click().click().click();
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, then type "Navigate Right" 6x times and expect to be in "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('[data-test="goto-next"]').click().click().click().click().click().click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
// then rollback by going backward
it('should be on Employee 10004 row at previous "Development" cell, then type "Navigate Left" once and expect to be in "Lunch Break"', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).as('active_cell').click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ cy.get('.slick-horizontal-scroller').scrollTo('right', { ensureScrollable: false });
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).as('active_cell').scrollIntoView().click();
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
cy.get('[data-test="goto-prev"]').click();
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" once and expect to be in "Conference" between 4:00-5:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click();
- cy.get(`[data-row=3] > .slick-cell.l16.r17.active`).should('contain', 'Conference');
+ cy.get(`[data-row=3] .slick-cell.l16.r17.active`).should('contain', 'Conference');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" 3x times and expect to be back to "Development" between 2:30-3:30pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click().click().click();
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan.active`).should('contain', 'Development');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" 4x times and expect to be back to "Lunch Break"', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click().click().click().click();
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan.active`).should('contain', 'Lunch Break');
});
it('should start at Employee 10004, type "End" and be at "Team Meeting" at 5pm, then type "Navigate Left" 5x times and expect to be back to "Testing" between 11:00-1:00pm', () => {
- cy.get('[data-row=3] > .slick-cell.l0.r0').as('active_cell').click();
- cy.get('[data-row=3] > .slick-cell.l0.r0.active').should('contain', '10004');
+ cy.get('[data-row=3] .slick-cell.l0.r0').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=3] .slick-cell.l0.r0.active').should('contain', '10004');
cy.get('@active_cell').type('{end}');
- cy.get(`[data-row=3] > .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
+ cy.get(`[data-row=3] .slick-cell.l18.r18.active`).as('active_cell').should('contain', 'Team Meeting');
cy.get('[data-test="goto-prev"]').click().click().click().click().click();
- cy.get(`[data-row=3] > .slick-cell.l6.r9.active`).should('contain', 'Testing');
+ cy.get(`[data-row=3] .slick-cell.l6.r9.active`).should('contain', 'Testing');
});
// going down
it('should start at 10am "Team Meeting, then type "ArrowDown" key once and expect to be in "Support" between 9:30-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0, { ensureScrollable: false });
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click();
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key twice and expect to be in "Check Email" between 9:00-10:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click();
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 3x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click();
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
- cy.get(`[data-row=5] > .slick-cell.l4.r6.active`).should('contain', 'Support');
+ cy.get(`[data-row=5] .slick-cell.l4.r6.active`).should('contain', 'Support');
});
// going up from inverse
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" once and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click();
- cy.get(`[data-row=4] > .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
+ cy.get(`[data-row=4] .slick-cell.l2.r5.active`).should('contain', 'Task Assign');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 2x times and expect to be in "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click().click();
- cy.get(`[data-row=2] > .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.active`).should('contain', 'Check Mail');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 3x times and expect to be in "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click().click().click();
- cy.get(`[data-row=1] > .slick-cell.l3.r5.active`).should('contain', 'Support');
+ cy.get(`[data-row=1] .slick-cell.l3.r5.active`).should('contain', 'Support');
});
it('should start at 10am "Team Meeting, then type "ArrowDown" key 4x times, then "ArrowUp" 4x times and expect to be back to same "Team Meeting"', () => {
- cy.get('[data-row=0] > .slick-cell.l4.r4').as('active_cell').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4').as('active_cell').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
cy.get('[data-test="goto-down"]').click().click().click().click();
cy.get('[data-test="goto-up"]').click().click().click().click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
+ cy.get('[data-row=0] .slick-cell.l4.r4.active').should('contain', 'Team Meeting');
});
});
describe('Grid Editing', () => {
it('should toggle editing', () => {
cy.get('#isEditable').contains('false');
- cy.get('[data-row=0] > .slick-cell.l4.r4').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active .editor-text').should('not.exist');
+ cy.get('[data-row=0] .slick-cell.l4.r4').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active .editor-text').should('not.exist');
cy.get('[data-test=toggle-editing]').click();
cy.get('#isEditable').contains('true');
- cy.get('[data-row=0] > .slick-cell.l4.r4').click();
- cy.get('[data-row=0] > .slick-cell.l4.r4.active.editable .editor-text').should('exist');
- cy.get('[data-row=0] > .slick-cell.l4.r4.active.editable .editor-text').type('Team Meeting.xyz{enter}');
+ cy.get('[data-row=0] .slick-cell.l4.r4').scrollIntoView().click();
+ cy.get('[data-row=0] .slick-cell.l4.r4.active.editable .editor-text').should('exist');
+ cy.get('[data-row=0] .slick-cell.l4.r4.active.editable .editor-text').type('Team Meeting.xyz{enter}');
});
// going down
it('should have changed active cell to "Support" between 9:30-11:00am', () => {
- cy.get('[data-row=1] > .slick-cell.l3.r5.active.editable .editor-text')
+ cy.get('[data-row=1] .slick-cell.l3.r5.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Support'));
- cy.get('[data-row=1] > .slick-cell.l3.r5.active.editable .editor-text').type('Support.xyz{enter}');
+ cy.get('[data-row=1] .slick-cell.l3.r5.active.editable .editor-text').type('Support.xyz{enter}');
});
it('should have changed active cell to "Check Email" between 9:00-10:30am', () => {
- cy.get('[data-row=2] > .slick-cell.l2.r4.active.editable .editor-text')
+ cy.get('[data-row=2] .slick-cell.l2.r4.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Check Mail'));
- cy.get('[data-row=2] > .slick-cell.l2.r4.active.editable .editor-text').type('Check Mail.xyz{enter}');
+ cy.get('[data-row=2] .slick-cell.l2.r4.active.editable .editor-text').type('Check Mail.xyz{enter}');
});
it('should have changed active cell to "Task Assign" between 9:00-11:00am', () => {
- cy.get('[data-row=4] > .slick-cell.l2.r5.active.editable .editor-text')
+ cy.get('[data-row=4] .slick-cell.l2.r5.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Task Assign'));
- cy.get('[data-row=4] > .slick-cell.l2.r5.active.editable .editor-text').type('Task Assign.xyz{enter}');
+ cy.get('[data-row=4] .slick-cell.l2.r5.active.editable .editor-text').type('Task Assign.xyz{enter}');
});
it('should have changed active cell to "Support" between 10:00-11:30am', () => {
- cy.get('[data-row=5] > .slick-cell.l4.r6.active.editable .editor-text')
+ cy.get('[data-row=5] .slick-cell.l4.r6.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Support'));
- cy.get('[data-row=5] > .slick-cell.l4.r6.active.editable .editor-text').type('Support.xyz{enter}');
+ cy.get('[data-row=5] .slick-cell.l4.r6.active.editable .editor-text').type('Support.xyz{enter}');
});
it('should have changed active cell to "Testing" and cancel editing when typing "Escape" key', () => {
- cy.get('[data-row=6] > .slick-cell.l4.r4.active.editable .editor-text')
+ cy.get('[data-row=6] .slick-cell.l4.r4.active.editable .editor-text')
.invoke('val')
.then((text) => expect(text).to.eq('Testing'));
- cy.get('[data-row=6] > .slick-cell.l4.r4.active.editable .editor-text').type('{esc}');
- cy.get('[data-row=6] > .slick-cell.l4.r4.active.editable .editor-text').should('not.exist');
+ cy.get('[data-row=6] .slick-cell.l4.r4.active.editable .editor-text').type('{esc}');
+ cy.get('[data-row=6] .slick-cell.l4.r4.active.editable .editor-text').should('not.exist');
});
});
@@ -418,32 +432,32 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 1 },
});
it('should expect EmployeeID to follow columns at index 0 column index', () => {
- cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should('contain', 'Davolio');
- cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l0.r0.rowspan`).should('contain', 'Davolio');
+ cy.get(`[data-row=0] .slick-cell.l0.r0.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should('contain', 'Check Mail');
- cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should(($el) =>
+ cy.get(`[data-row=2] .slick-cell.l1.r3.rowspan`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l1.r3.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should(($el) =>
+ cy.get(`[data-row=8] .slick-cell.l6.r8.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=8] .slick-cell.l6.r8.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
});
it('should expect "Lunch Break" to be moved to the left by 1 index less', () => {
- cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should('contain', 'Lunch Break');
- cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l9.r11.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l9.r11.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10)
);
});
it('should expect "Development" to be moved to the left by 1 index less', () => {
- cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should(($el) =>
+ cy.get(`[data-row=1] .slick-cell.l12.r13.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l12.r13.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5)
);
});
@@ -455,32 +469,32 @@ describe('Example 43 - colspan/rowspan - Employees Timesheets', { retries: 1 },
});
it('should expect EmployeeID to follow columns at index 1 column index', () => {
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
- cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
+ cy.get(`[data-row=0] .slick-cell.l1.r1.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
- cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should(($el) =>
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
+ cy.get(`[data-row=2] .slick-cell.l2.r4.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should(($el) =>
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=8] .slick-cell.l7.r9.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2)
);
});
it('should expect "Lunch Break" to be moved to the right by 1 index less', () => {
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
- cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should(($el) =>
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
+ cy.get(`[data-row=0] .slick-cell.l10.r12.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10)
);
});
it('should expect "Development" to be moved to the right by 1 index less and a large "Development" section that spans over multiple columns & rows in the afternoon', () => {
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
- cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should(($el) =>
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
+ cy.get(`[data-row=1] .slick-cell.l13.r14.rowspan`).should(($el) =>
expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5)
);
});
diff --git a/demos/react/test/cypress/e2e/example44.cy.ts b/demos/react/test/cypress/e2e/example44.cy.ts
index 5d5bf6f477..451c07efd7 100644
--- a/demos/react/test/cypress/e2e/example44.cy.ts
+++ b/demos/react/test/cypress/e2e/example44.cy.ts
@@ -30,8 +30,14 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
cy.get('h2').should('contain', 'Example 44: colspan/rowspan with large dataset');
});
+ it('should hide sub-title', () => {
+ cy.get('[data-test=toggle-subtitle]').click();
+ });
+
it('should calculate a height that fits the wrapped Revenue Growth header', () => {
- cy.get('.slick-header-auto-height').should('have.length', 2);
+ // The pinning POC uses one live header instead of separate left/right
+ // header panes, so auto-height is applied to a single header element.
+ cy.get('.slick-header-auto-height').should('have.length', 1);
cy.get('.slick-header-auto-height')
.first()
.should(($header) => {
@@ -58,7 +64,7 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
let draggedColumn: HTMLElement;
cy.clock();
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0).its('0.scrollLeft').should('equal', 0);
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0).its('0.scrollLeft').should('equal', 0);
cy.get('.slick-header-columns-left').then(($header) => {
const sortableProperty = Object.keys($header[0]).find((property) => property.startsWith('Sortable'));
@@ -75,12 +81,12 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
cy.tick(300);
- cy.get('.slick-viewport-top.slick-viewport-left').its('0.scrollLeft').should('be.greaterThan', 0);
+ cy.get('.slick-horizontal-scroller').its('0.scrollLeft').should('be.greaterThan', 0);
cy.then(() => sortInstance.options.onEnd({ item: draggedColumn, stopPropagation: () => {} }));
cy.get('.slick-header-column:nth(0)').should('contain', 'Title');
cy.get('.slick-header-column:nth(1)').should('contain', 'Revenue Growth');
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0);
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0);
});
it('should drag Title column to swap with 2nd column "Revenue Growth" in the grid and expect rowspan to stay at same position with Task 0 to spread instead', () => {
@@ -208,7 +214,7 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
it('should scroll to the right and still expect spans without any extra texts', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(400, 0).wait(10);
+ cy.get('.slick-horizontal-scroller').scrollTo(400, 0).wait(10);
cy.get(`[data-row=3] > .slick-cell:nth(1)`).contains(/\d+$/);
cy.get(`[data-row=3] > .slick-cell.l1.r2.rowspan`).should('exist');
@@ -229,7 +235,7 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
it('should scroll back to left and expect Task 8 to have 2 different spans (Revenue Grow: rowspan=80, Policy Index: rowspan=2000,colspan=2)', () => {
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo(0, 0).wait(10);
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0).wait(10);
cy.get(`[data-row=8] > .slick-cell.l0.r0`).should('contain', 'Task 8');
cy.get(`[data-row=8] > .slick-cell.l1.r1.rowspan`).should(($el) => {
@@ -350,6 +356,10 @@ describe('Example 44 - Column & Row Span', { retries: 0 }, () => {
});
it('should start at RevenueGrowth column on first dashed cell, then type "Ctrl+End" then "Ctrl+Home" keys and expect active cell to go to bottom/top of grid on same column', () => {
+ // The preceding span/scroll cases share state. Reset both axes through
+ // the POC's actual scroll owners before interacting with the first row.
+ cy.get('.slick-horizontal-scroller').scrollTo(0, 0);
+ cy.get('.slick-vertical-scroller').scrollTo(0, 0);
cy.get('[data-row=0] > .slick-cell.l2.r2').as('active_cell').click();
cy.get('[data-row=0] > .slick-cell.l2.r2.active').should('have.length', 1);
cy.get('@active_cell').type('{ctrl}{end}', { release: false });
diff --git a/demos/react/test/cypress/e2e/example45.cy.ts b/demos/react/test/cypress/e2e/example45.cy.ts
index 6f56e1a753..b4485b498b 100644
--- a/demos/react/test/cypress/e2e/example45.cy.ts
+++ b/demos/react/test/cypress/e2e/example45.cy.ts
@@ -224,9 +224,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
});
it('should scroll down when the row detail is just barely visible and then scroll back up and still expect same filters/sorting', () => {
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 350);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 350);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should('contain', '10281');
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(1)`).should('contain', 'Madrid');
@@ -236,9 +236,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
it('should scroll down by 2 pages down and then scroll back up and no longer the same filters/sorting', () => {
cy.get('#grid45 [data-row="0"] .slick-cell.r2.l2').first().click().type('{pagedown}');
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 2000);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 2000);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should(
'not.contain',
@@ -419,7 +419,7 @@ describe('Example 45 - Row Detail with inner Grid', () => {
cy.get('#grid45').type('{pageDown}{pageDown}', { release: false });
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 350);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 350);
// expect same grid details for both grids
// 2nd row detail
@@ -520,9 +520,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
});
it('should scroll far down (out of viewport) and back up and expect inner grid sort/filter state is PRESERVED (keepComponentAlive)', () => {
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 800);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 800);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
// state should be PRESERVED because keepComponentAlive is enabled
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should('contain', '10281');
@@ -532,9 +532,9 @@ describe('Example 45 - Row Detail with inner Grid', () => {
});
it('should scroll out of viewport a second time and back up and still expect inner grid sort/filter state is PRESERVED', () => {
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 800);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 800);
cy.wait(50);
- cy.get('#grid45 .slick-viewport-top.slick-viewport-left').first().scrollTo(0, 0);
+ cy.get('#grid45 .slick-vertical-scroller').first().scrollTo(0, 0);
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(0)`).should('contain', '10281');
cy.get(`#innergrid-1 .slick-row[style*="translateY(${GRID_ROW_HEIGHT * 0}px)"] > .slick-cell:nth(1)`).should('contain', 'Madrid');
diff --git a/demos/react/test/cypress/e2e/example47.cy.ts b/demos/react/test/cypress/e2e/example47.cy.ts
index 936cb3002e..3e5480a883 100644
--- a/demos/react/test/cypress/e2e/example47.cy.ts
+++ b/demos/react/test/cypress/e2e/example47.cy.ts
@@ -101,7 +101,7 @@ describe('Example 47 - Row Detail View + Grouping', () => {
cy.get('.detail-label label').should('contain', 'Assignee:');
cy.get('.detail-label input').should('exist');
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('.dynamic-cell-detail').find('[data-test=delete-btn]').click();
cy.get('.toast.text-bg-danger').contains(/Deleted row with Task [0-9]*/);
cy.get('.dynamic-cell-detail').should('have.length', 0);
@@ -112,7 +112,7 @@ describe('Example 47 - Row Detail View + Grouping', () => {
cy.on('window:alert', stub);
let assigneeName = '';
- cy.get('.slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('.slick-vertical-scroller').scrollTo('top');
cy.get('[data-row="1"] > .slick-cell.l1').contains(/Task [0-9]*/);
cy.get('[data-row="1"] > .slick-cell.l0').click().wait(40);
diff --git a/demos/react/test/cypress/e2e/example48.cy.ts b/demos/react/test/cypress/e2e/example48.cy.ts
index 5e7f317681..329aac187e 100644
--- a/demos/react/test/cypress/e2e/example48.cy.ts
+++ b/demos/react/test/cypress/e2e/example48.cy.ts
@@ -153,7 +153,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
it('should auto scroll take effect to display the selecting element when dragging', { scrollBehavior: false }, () => {
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo('top');
testScroll('#grid48-1', '#grid48-1', 0, 1).then((scrollDistance: { cell: any; row: any }) => {
expect(scrollDistance.cell.scrollBefore).to.be.lte(scrollDistance.cell.scrollAfter);
@@ -161,11 +161,11 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
cy.get('#selectionRange1').contains(/"fromRow":0,"fromCell":1,"toRow":1[45],"toCell":3/);
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo(0, 13 * 35);
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo(0, 13 * 35);
});
it('should toggle multiple cell selection ranges with the checkbox', () => {
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo('top');
cy.get('[data-test="enable-multi-selection"]').check();
cy.get('#grid48-1 .slick-row[data-row="1"] .slick-cell.l1.r1').click();
@@ -201,7 +201,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
it('should preserve row and column offsets when copying multiple cell ranges', () => {
- cy.get('#grid48-1 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-1 .slick-vertical-scroller').scrollTo('top');
cy.get('[data-test="enable-multi-selection"]').should('be.checked');
cy.window().then((win) => {
cy.stub(win.navigator.clipboard, 'writeText').as('clipboardWriteText');
@@ -264,7 +264,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
});
cy.get('#selectionRange2').contains(/"fromRow":0,"fromCell":0,"toRow":1[0-9],"toCell":7/);
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo(0, 12 * 35);
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo(0, 12 * 35);
});
it('should click on a cell outside of the selected range and expect previous selection to remain', () => {
@@ -272,7 +272,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
cy.get('@task1x')
.contains(/Task 1[0-9]/)
.click();
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-cell.selected').should('have.length.gte', 60);
cy.get('#selectionRange2').contains(/"fromRow":0,"fromCell":0,"toRow":1[0-9],"toCell":7/);
});
@@ -284,20 +284,20 @@ describe('Example 48 - Hybrid Selection Model', () => {
it('should click on row 4 and 5 row checkbox and expect 5 full rows to be selected', () => {
cy.get('#grid48-2 .slick-row[data-row="4"] .slick-cell.l1.r1').should('contain', '4');
cy.get('#grid48-2 .slick-row[data-row="4"] input[type=checkbox]').click({ force: true });
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-row[data-row="4"] .slick-cell.l0.r0').should('have.class', 'selected');
cy.get('#grid48-2 .slick-cell.selected').should('have.length', 8 * 1);
// select another row
cy.get('#grid48-2 .slick-row[data-row="5"] .slick-cell.l1.r1').should('contain', '5');
cy.get('#grid48-2 .slick-row[data-row="5"] input[type=checkbox]').click({ force: true });
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-row[data-row="5"] .slick-cell.l0.r0').should('have.class', 'selected');
cy.get('#grid48-2 .slick-cell.selected').should('have.length', 8 * 2);
});
it('should toggle multiple row selection ranges with the checkbox', () => {
- cy.get('#grid48-2 .slick-viewport-top.slick-viewport-left').scrollTo('top');
+ cy.get('#grid48-2 .slick-vertical-scroller').scrollTo('top');
cy.get('#grid48-2 .slick-row[data-row="4"] input[type=checkbox]').uncheck({ force: true });
cy.get('#grid48-2 .slick-row[data-row="5"] input[type=checkbox]').uncheck({ force: true });
cy.get('[data-test="enable-multi-selection"]').should('be.checked');
@@ -321,7 +321,7 @@ describe('Example 48 - Hybrid Selection Model', () => {
const secondRange = '{"fromRow":3,"fromCell":0,"toRow":4,"toCell":7}';
const combinedRanges = `${firstRange}${secondRange}`;
- cy.get(`${gridSelector} .slick-viewport-top.slick-viewport-left`).scrollTo('top');
+ cy.get(`${gridSelector} .slick-vertical-scroller`).scrollTo('top');
cy.get(`${gridSelector} .slick-row[data-row="1"] input[type=checkbox]`).uncheck({ force: true });
cy.get(`${gridSelector} .slick-row[data-row="2"] input[type=checkbox]`).uncheck({ force: true });
cy.get(`${gridSelector} .slick-row[data-row="4"] input[type=checkbox]`).uncheck({ force: true });
diff --git a/demos/react/test/cypress/e2e/example55.cy.ts b/demos/react/test/cypress/e2e/example55.cy.ts
index 37ecd02a59..3a8477ecf3 100644
--- a/demos/react/test/cypress/e2e/example55.cy.ts
+++ b/demos/react/test/cypress/e2e/example55.cy.ts
@@ -38,7 +38,7 @@ describe('Example 55 - Variable Row Height (provider)', { retries: 1 }, () => {
it('should keep row 90 aligned at top after clicking scroll button', () => {
cy.get('[data-test="scroll-row-90-example55"]').click();
- cy.get('.slick-viewport-top.slick-viewport-left')
+ cy.get('.slick-vertical-scroller')
.invoke('scrollTop')
.then((scrollTop) => {
expect(Number(scrollTop)).to.be.closeTo(topOf(90), 2);
diff --git a/demos/react/test/cypress/e2e/example56.cy.ts b/demos/react/test/cypress/e2e/example56.cy.ts
index c02518e284..e30d1b7f00 100644
--- a/demos/react/test/cypress/e2e/example56.cy.ts
+++ b/demos/react/test/cypress/e2e/example56.cy.ts
@@ -1,6 +1,6 @@
describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, () => {
const BASE_ROW_HEIGHT = 40;
- const FROZEN_ROW_COUNT = 2;
+ const PINNED_ROW_COUNT = 2;
const hDefault = (r: number) => {
const cycle = [33, 44, 44, 80];
@@ -18,36 +18,41 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
return t;
};
- const frozenTopHeight = (hOf: (row: number) => number) => topOf(FROZEN_ROW_COUNT, hOf);
+ const pinnedTopHeight = (hOf: (row: number) => number) => topOf(PINNED_ROW_COUNT, hOf);
const relativeTopInCanvas = (r: number, hOf: (row: number) => number) => {
- if (r < FROZEN_ROW_COUNT) {
- return topOf(r, hOf);
- }
- return topOf(r, hOf) - frozenTopHeight(hOf);
+ // Pinned rows are moved into the overlay, but center rows retain their
+ // natural document coordinates behind that overlay.
+ return topOf(r, hOf);
};
- const canvasSelector = (r: number) => (r < FROZEN_ROW_COUNT ? '.grid-canvas-top' : '.grid-canvas-bottom');
+ const rowHostSelector = (r: number) => (r < PINNED_ROW_COUNT ? '.slick-docking-overlay' : '.grid-canvas-top');
const assertRowStyle = (row: number, hOf: (row: number) => number) => {
const expectedHeight = hOf(row);
const expectedTop = relativeTopInCanvas(row, hOf);
- cy.get(`${canvasSelector(row)} .slick-row[data-row=${row}]`)
+ cy.get(`${rowHostSelector(row)} .slick-row[data-row=${row}]`)
.should('have.attr', 'style')
.and('contain', `transform: translateY(${expectedTop}px)`)
.then((style) => {
if (expectedHeight !== BASE_ROW_HEIGHT) {
expect(style).to.contain(`height: ${expectedHeight}px`);
} else {
- expect(style).not.to.contain('height:');
+ // Docked rows carry their resolved height inline so editor/content
+ // styles cannot collapse the pinned row. The base-height case is
+ // therefore valid with either the stylesheet fallback or an
+ // explicit `height: 40px` declaration.
+ expect(style).to.match(/(?:height: 40px;|^(?!.*height:))/);
}
});
- cy.get(`[data-row="${row}"] > .slick-cell:nth(3)`).should('contain', `${expectedHeight}px`);
+ // Rows are split into left/center/right docking regions, so cells are
+ // nested under their region wrapper rather than being direct row children.
+ cy.get(`[data-row="${row}"] .slick-cell:nth(3)`).should('contain', `${expectedHeight}px`);
};
const ensureDefaultDensity = () => {
- cy.get('.grid-canvas-top .slick-row[data-row=1]')
+ cy.get('.slick-docking-overlay .slick-row[data-row=1]')
.invoke('attr', 'style')
.then((style) => {
if ((style ?? '').includes('height: 50px')) {
@@ -55,7 +60,7 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
}
});
- cy.get('.grid-canvas-top .slick-row[data-row=1]').should('have.attr', 'style').and('contain', 'height: 44px');
+ cy.get('.slick-docking-overlay .slick-row[data-row=1]').should('have.attr', 'style').and('contain', 'height: 44px');
};
beforeEach(() => {
@@ -67,7 +72,7 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
cy.get('h2').should('contain', 'Example 56: Variable Row Height (item metadata)');
});
- it('should render frozen and scrollable rows with expected transform and row heights from metadata fallback', () => {
+ it('should render pinned and scrollable rows with expected transform and row heights from metadata fallback', () => {
for (const r of [0, 1, 2, 3, 4, 5, 6]) {
assertRowStyle(r, hDefault);
}
@@ -85,12 +90,12 @@ describe('Example 56 - Variable Row Height (item metadata)', { retries: 1 }, ()
}
});
- it('should scroll row 90 to top of scrollable pane with frozen top rows', () => {
- const expectedScrollTop = topOf(90, hDefault) - frozenTopHeight(hDefault);
+ it('should scroll row 90 to top of scrollable pane with pinned top rows', () => {
+ const expectedScrollTop = topOf(90, hDefault) - pinnedTopHeight(hDefault);
cy.get('[data-test="scroll-row-90-example56"]').click();
- cy.get('.slick-viewport-bottom.slick-viewport-left').should(($viewport) => {
+ cy.get('.slick-vertical-scroller').should(($viewport) => {
expect($viewport.scrollTop()).to.be.closeTo(expectedScrollTop, 2);
});
diff --git a/demos/react/test/cypress/e2e/example57.cy.ts b/demos/react/test/cypress/e2e/example57.cy.ts
index df73fe98f8..7055d540b1 100644
--- a/demos/react/test/cypress/e2e/example57.cy.ts
+++ b/demos/react/test/cypress/e2e/example57.cy.ts
@@ -54,14 +54,14 @@ describe('Example 57 - RTL (Right-to-Left)', () => {
describe('Scrolling Behavior', () => {
it('should have horizontal scroll enabled', () => {
- cy.get('#grid57 .slick-viewport').then(($viewport) => {
+ cy.get('#grid57 .slick-horizontal-scroller').then(($viewport) => {
const viewport = $viewport[0] as HTMLElement;
expect(viewport.scrollWidth).to.be.greaterThan(viewport.clientWidth);
});
});
it('should update visible header columns when scrolling', () => {
- cy.get('#grid57 .slick-viewport').then(($viewport) => {
+ cy.get('#grid57 .slick-horizontal-scroller').then(($viewport) => {
const viewport = $viewport[0] as HTMLElement;
const maxScroll = viewport.scrollWidth - viewport.clientWidth;
viewport.scrollLeft = maxScroll;
@@ -72,7 +72,7 @@ describe('Example 57 - RTL (Right-to-Left)', () => {
cy.wait(150);
- cy.get('#grid57 .slick-viewport').then(($viewport) => {
+ cy.get('#grid57 .slick-horizontal-scroller').then(($viewport) => {
const viewport = $viewport[0] as HTMLElement;
expect(Math.abs(viewport.scrollLeft)).to.be.greaterThan(0);
});
diff --git a/demos/react/test/cypress/support/commands.ts b/demos/react/test/cypress/support/commands.ts
index 3be5a3685b..1f58e699f1 100644
--- a/demos/react/test/cypress/support/commands.ts
+++ b/demos/react/test/cypress/support/commands.ts
@@ -32,19 +32,19 @@ declare global {
namespace Cypress {
interface Chainable {
// triggerHover: (elements: NodeListOf) => void;
- convertPosition(viewport: string): Chainable | { x: string; y: string }>;
+ convertPosition(viewport: string): Chainable<{ x: string; y: string }>;
getCell(
row: number,
col: number,
viewport?: string,
options?: { parentSelector?: string; rowHeight?: number }
- ): Chainable>;
+ ): Chainable>;
getNthCell(
row: number,
nthCol: number,
viewport?: string,
options?: { parentSelector?: string; rowHeight?: number }
- ): Chainable>;
+ ): Chainable>;
saveLocalStorage: () => void;
restoreLocalStorage: () => void;
getTransformValue(cssTransformMatrix: string, absoluteValue: boolean, transformType?: 'rotate' | 'scale'): Chainable;
diff --git a/demos/react/test/cypress/support/drag.ts b/demos/react/test/cypress/support/drag.ts
index 8228176a5a..b26012a988 100644
--- a/demos/react/test/cypress/support/drag.ts
+++ b/demos/react/test/cypress/support/drag.ts
@@ -82,15 +82,22 @@ export function getScrollDistanceWhenDragOutsideGrid(
return (cy as any).convertPosition(viewport).then((_viewportPosition: { x: number; y: number }) => {
const viewportSelector = `${selector} .slick-viewport-${_viewportPosition.x}.slick-viewport-${_viewportPosition.y}`;
(cy as any).getNthCell(fromRow, fromCol, viewport, { parentSelector: selector }).dragStart();
- return cy.get(viewportSelector).then(($viewport) => {
- const scrollTopBefore = $viewport.scrollTop();
- const scrollLeftBefore = $viewport.scrollLeft();
+ return cy.get(selector).then(($grid) => {
+ const viewport = ($grid.find(viewportSelector)[0] || $grid.find('.slick-vertical-scroller')[0]) as HTMLElement;
+ const horizontalScroller = $grid.find('.slick-horizontal-scroller')[0] as HTMLElement | undefined;
+ const horizontalOwner = horizontalScroller || viewport;
+ const scrollTopBefore = viewport.scrollTop;
+ const scrollLeftBefore = horizontalOwner.scrollLeft;
cy.dragOutside(dragDirection, 300, px, { parentSelector: selector });
- return cy.get(viewportSelector).then(($viewportAfter) => {
+ return cy.get(selector).then(($gridAfter) => {
+ const viewportAfter = ($gridAfter.find(viewportSelector)[0] || $gridAfter.find('.slick-vertical-scroller')[0]) as HTMLElement;
+ const horizontalScrollerAfter = $gridAfter.find('.slick-horizontal-scroller')[0] as HTMLElement | undefined;
+ const horizontalOwnerAfter = horizontalScrollerAfter || viewportAfter;
cy.dragEnd(selector);
- const scrollTopAfter = $viewportAfter.scrollTop();
- const scrollLeftAfter = $viewportAfter.scrollLeft();
- cy.get(viewportSelector).scrollTo(0, 0, { ensureScrollable: false });
+ const scrollTopAfter = viewportAfter.scrollTop;
+ const scrollLeftAfter = horizontalOwnerAfter.scrollLeft;
+ horizontalOwnerAfter.scrollLeft = 0;
+ viewportAfter.scrollTop = 0;
return cy.wrap({
scrollTopBefore,
scrollLeftBefore,
diff --git a/demos/vanilla/public/i18n/en.json b/demos/vanilla/public/i18n/en.json
index 600083fa11..4f039dd3c3 100644
--- a/demos/vanilla/public/i18n/en.json
+++ b/demos/vanilla/public/i18n/en.json
@@ -7,7 +7,7 @@
"CLEAR_ALL_FILTERS": "Clear all Filters",
"CLEAR_ALL_GROUPING": "Clear all Grouping",
"CLEAR_ALL_SORTING": "Clear all Sorting",
- "CLEAR_PINNING": "Unfreeze Columns/Rows",
+ "CLEAR_PINNING": "Unpin Columns/Rows",
"CLONE": "Clone",
"COLLAPSE_ALL_GROUPS": "Collapse all Groups",
"COLUMNS": "Columns",
@@ -29,7 +29,10 @@
"FILTER_SHORTCUTS": "Filter Shortcuts",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} of {{totalItems}} items",
"FORCE_FIT_COLUMNS": "Force fit columns",
- "FREEZE_COLUMNS": "Freeze Columns",
+ "PIN_COLUMN": "Column Pinning",
+ "PIN_COLUMNS": "Pin Through Here",
+ "PIN_LEFT": "Pin Left",
+ "PIN_RIGHT": "Pin Right",
"INVALID_FLOAT": "The number must be valid and have a maximum of {{maxDecimal}} decimals.",
"GREATER_THAN": "Greater than",
"GREATER_THAN_OR_EQUAL_TO": "Greater than or equal to",
@@ -68,7 +71,8 @@
"TOGGLE_DARK_MODE": "Toggle Dark Mode",
"TOGGLE_FILTER_ROW": "Toggle Filter Row",
"TOGGLE_PRE_HEADER_ROW": "Toggle Pre-Header Row",
- "UNFREEZE_COLUMNS": "Unfreeze Columns",
+ "UNPIN_COLUMN": "Unpin Column",
+ "UNPIN_COLUMNS": "Unpin All Columns",
"X_OF_Y_SELECTED": "# of % selected",
"X_OF_Y_MASS_SELECTED": "{{x}} of {{y}} selected",
"BILLING": {
diff --git a/demos/vanilla/public/i18n/fr.json b/demos/vanilla/public/i18n/fr.json
index 084d95bbb8..bc86353024 100644
--- a/demos/vanilla/public/i18n/fr.json
+++ b/demos/vanilla/public/i18n/fr.json
@@ -7,7 +7,7 @@
"CLEAR_ALL_FILTERS": "Supprimer tous les filtres",
"CLEAR_ALL_GROUPING": "Supprimer tous les groupes",
"CLEAR_ALL_SORTING": "Supprimer tous les tris",
- "CLEAR_PINNING": "Dégeler les colonnes/rangées",
+ "CLEAR_PINNING": "Désépingler les colonnes/rangées",
"CLONE": "Cloner",
"COLLAPSE_ALL_GROUPS": "Réduire tous les groupes",
"COLUMNS": "Colonnes",
@@ -29,7 +29,10 @@
"FILTER_SHORTCUTS": "Raccourcis de filtre",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} de {{totalItems}} éléments",
"FORCE_FIT_COLUMNS": "Ajustement forcé des colonnes",
- "FREEZE_COLUMNS": "Geler les colonnes",
+ "PIN_COLUMN": "Épinglage de colonnes",
+ "PIN_COLUMNS": "Épingler jusqu'ici",
+ "PIN_LEFT": "Épingler à gauche",
+ "PIN_RIGHT": "Épingler à droite",
"GREATER_THAN": "Plus grand que",
"GREATER_THAN_OR_EQUAL_TO": "Plus grand ou égal à",
"GROUP_BY": "Grouper par",
@@ -68,7 +71,8 @@
"TOGGLE_DARK_MODE": "Basculer le mode clair/sombre",
"TOGGLE_FILTER_ROW": "Basculer la ligne des filtres",
"TOGGLE_PRE_HEADER_ROW": "Basculer la ligne de pré-en-tête",
- "UNFREEZE_COLUMNS": "Dégeler les colonnes",
+ "UNPIN_COLUMN": "Désépingler la colonne",
+ "UNPIN_COLUMNS": "Désépingler toutes les colonnes",
"X_OF_Y_SELECTED": "# de % sélectionnés",
"X_OF_Y_MASS_SELECTED": "{{x}} de {{y}} sélectionnés",
"BILLING": {
diff --git a/demos/vanilla/src/app-routing.ts b/demos/vanilla/src/app-routing.ts
index 1976666f59..e62c7a9322 100644
--- a/demos/vanilla/src/app-routing.ts
+++ b/demos/vanilla/src/app-routing.ts
@@ -44,6 +44,7 @@ import Example43 from './examples/example43.js';
import Example44 from './examples/example44.js';
import Example45 from './examples/example45.js';
import Example46 from './examples/example46.js';
+import Example47 from './examples/example47.js';
import Icons from './examples/icons.js';
import type { RouterConfig } from './interfaces.js';
@@ -98,6 +99,7 @@ export class AppRouting {
{ route: 'example44', name: 'example44', view: './examples/example44.html', viewModel: Example44, title: 'Example44' },
{ route: 'example45', name: 'example45', view: './examples/example45.html', viewModel: Example45, title: 'Example45' },
{ route: 'example46', name: 'example46', view: './examples/example46.html', viewModel: Example46, title: 'Example46' },
+ { route: 'example47', name: 'example47', view: './examples/example47.html', viewModel: Example47, title: 'Example47' },
{ route: '', redirect: 'example01' },
{ route: '**', redirect: 'example01' },
];
diff --git a/demos/vanilla/src/app.html b/demos/vanilla/src/app.html
index 8756cc7cb8..b12080213d 100644
--- a/demos/vanilla/src/app.html
+++ b/demos/vanilla/src/app.html
@@ -34,7 +34,7 @@ Slickgrid-Universal
Example01 - Basic Grids
Example02 - Grouping & Aggregators
Example03 - Draggable Grouping
- Example04 - Pinned (frozen) Columns/Rows
+ Example04 - Pinned Columns/Rows
Example05 - Tree Data with Parent/Child refs
Example06 - Tree Data from Hierarchical View Dataset
Example07 - Row Move & Row Selections
@@ -87,6 +87,7 @@ Slickgrid-Universal
Example44 - Variable Row Height (provider)
Example45 - Variable Row Height (metadata)
Example46 - RTL (Right-to-Left)
+ Example47 - Sticky Financial Report
diff --git a/demos/vanilla/src/examples/example03.html b/demos/vanilla/src/examples/example03.html
index b93ea06b33..b088035254 100644
--- a/demos/vanilla/src/examples/example03.html
+++ b/demos/vanilla/src/examples/example03.html
@@ -1,7 +1,10 @@
- Example 03 - Draggable Grouping
+ Example 03 - Draggable Grouping & Aggregators
(with Salesforce Theme)
+
+
+
Toggle Light/Dark
@@ -19,7 +22,7 @@