diff --git a/examples/webpack-demo-vanilla-bundle/src/examples/example13.html b/examples/webpack-demo-vanilla-bundle/src/examples/example13.html index 74e338728..0c6773212 100644 --- a/examples/webpack-demo-vanilla-bundle/src/examples/example13.html +++ b/examples/webpack-demo-vanilla-bundle/src/examples/example13.html @@ -9,5 +9,18 @@

-
+
Grid 1
+ +
+
+ +
+ +
+
+
Grid 2 - with both Header Buttons & Menus
+
+
+ +
\ No newline at end of file diff --git a/examples/webpack-demo-vanilla-bundle/src/examples/example13.scss b/examples/webpack-demo-vanilla-bundle/src/examples/example13.scss new file mode 100644 index 000000000..fc377ce25 --- /dev/null +++ b/examples/webpack-demo-vanilla-bundle/src/examples/example13.scss @@ -0,0 +1,10 @@ +/* 1st grid */ +.grid13-2 { + --slick-header-button-float: right; +} + +/* 2nd grid */ +.grid13-2 { + --slick-header-button-margin: -2px 0 50px 0; + --slick-header-button-float: left; +} \ No newline at end of file diff --git a/examples/webpack-demo-vanilla-bundle/src/examples/example13.ts b/examples/webpack-demo-vanilla-bundle/src/examples/example13.ts index 6a345214f..cdd84fff9 100644 --- a/examples/webpack-demo-vanilla-bundle/src/examples/example13.ts +++ b/examples/webpack-demo-vanilla-bundle/src/examples/example13.ts @@ -8,51 +8,54 @@ import { Slicker, SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bu import { ExampleGridOptions } from './example-grid-options'; import '../material-styles.scss'; -import './example02.scss'; +import './example13.scss'; -let columnsWithHighlightingById = {}; - -// create a custom Formatter to highlight negative values in red -const highlightingFormatter = (_row, _cell, value, columnDef) => { - if (columnsWithHighlightingById[columnDef.id] && value < 0) { - return `
${value}
`; - } else { - return value; - } -}; +let columns1WithHighlightingById = {}; +let columns2WithHighlightingById = {}; export class Example13 { private _bindingEventService: BindingEventService; - columnDefinitions: Column[]; - gridOptions: GridOption; - dataset: any[]; - commandQueue = []; - sgb: SlickVanillaGridBundle; - excelExportService: ExcelExportService; + columnDefinitions1: Column[]; + columnDefinitions2: Column[]; + gridOptions1: GridOption; + gridOptions2: GridOption; + dataset1: any[]; + dataset2: any[]; + sgb1: SlickVanillaGridBundle; + sgb2: SlickVanillaGridBundle; + excelExportService1: ExcelExportService; + excelExportService2: ExcelExportService; constructor() { - this.excelExportService = new ExcelExportService(); + this.excelExportService1 = new ExcelExportService(); + this.excelExportService2 = new ExcelExportService(); this._bindingEventService = new BindingEventService(); - columnsWithHighlightingById = {}; + columns1WithHighlightingById = {}; + columns2WithHighlightingById = {}; } attached() { this.initializeGrid(); - this.dataset = this.loadData(); - const gridContainerElm = document.querySelector(`.grid13`); + this.dataset1 = this.loadData(200, 1); + this.dataset2 = this.loadData(200, 2); + const gridContainerElm1 = document.querySelector(`.grid13-1`); + const gridContainerElm2 = document.querySelector(`.grid13-2`); - this.sgb = new Slicker.GridBundle(gridContainerElm, this.columnDefinitions, { ...ExampleGridOptions, ...this.gridOptions }, this.dataset); + this.sgb1 = new Slicker.GridBundle(gridContainerElm1, this.columnDefinitions1, { ...ExampleGridOptions, ...this.gridOptions1 }, this.dataset1); + this.sgb2 = new Slicker.GridBundle(gridContainerElm2, this.columnDefinitions2, { ...ExampleGridOptions, ...this.gridOptions2 }, this.dataset2); } dispose() { - this.sgb?.dispose(); + this.sgb1?.dispose(); + this.sgb2?.dispose(); this._bindingEventService.unbindAll(); } initializeGrid() { - this.columnDefinitions = []; + this.columnDefinitions1 = []; + this.columnDefinitions2 = []; - this.gridOptions = { + this.gridOptions1 = { enableAutoResize: true, enableHeaderButton: true, enableHeaderMenu: false, @@ -61,40 +64,71 @@ export class Example13 { }, enableFiltering: false, enableCellNavigation: true, + gridHeight: 275, headerButton: { // you can use the "onCommand" (in Grid Options) and/or the "action" callback (in Column Definition) - onCommand: (_e, args) => { - const column = args.column; - const button = args.button; - const command = args.command; - - if (command === 'toggle-highlight') { - if (button.cssClass === 'mdi mdi-lightbulb-on color-danger') { - delete columnsWithHighlightingById[column.id]; - button.cssClass = 'mdi mdi-lightbulb-outline color-warning faded'; - button.tooltip = 'Highlight negative numbers.'; - } else { - columnsWithHighlightingById[column.id] = true; - button.cssClass = 'mdi mdi-lightbulb-on color-danger'; - button.tooltip = 'Remove highlight.'; - } - this.sgb.slickGrid.invalidate(); - } - } + onCommand: (_e, args) => this.handleOnCommand(_e, args, 1) + } + }; + + // grid 2 options, same as grid 1 + extras + this.gridOptions2 = { + ...this.gridOptions1, + enableHeaderMenu: true, + enableFiltering: true, + headerButton: { + // when floating to left, you might want to inverse the icon orders + inverseOrder: true, + onCommand: (_e, args) => this.handleOnCommand(_e, args, 2) } }; } - loadData() { + handleOnCommand(_e, args, gridNo: 1 | 2) { + const column = args.column; + const button = args.button; + const command = args.command; + + if (command === 'toggle-highlight') { + if (button.cssClass === 'mdi mdi-lightbulb-on color-danger') { + if (gridNo === 1) { + delete columns1WithHighlightingById[column.id]; + } else { + delete columns2WithHighlightingById[column.id]; + } + button.cssClass = 'mdi mdi-lightbulb-outline color-warning faded'; + button.tooltip = 'Highlight negative numbers.'; + } else { + if (gridNo === 1) { + columns1WithHighlightingById[column.id] = true; + } else { + columns2WithHighlightingById[column.id] = true; + } + button.cssClass = 'mdi mdi-lightbulb-on color-danger'; + button.tooltip = 'Remove highlight.'; + } + this[`sgb${gridNo}`].slickGrid.invalidate(); + } + } + + loadData(count: number, gridNo: 1 | 2) { // Set up some test columns. for (let i = 0; i < 10; i++) { - this.columnDefinitions.push({ + this[`columnDefinitions${gridNo}`].push({ id: i, name: 'Column ' + String.fromCharCode('A'.charCodeAt(0) + i), field: i + '', width: i === 0 ? 70 : 100, // have the 2 first columns wider + filterable: true, sortable: true, - formatter: highlightingFormatter, + formatter: (_row, _cell, value, columnDef) => { + if (gridNo === 1 && columns1WithHighlightingById[columnDef.id] && value < 0) { + return `
${value}
`; + } else if (gridNo === 2 && columns2WithHighlightingById[columnDef.id] && value < 0) { + return `
${value}
`; + } + return value; + }, header: { buttons: [ { @@ -121,8 +155,8 @@ export class Example13 { } // Set multiple buttons on the first column to demonstrate overflow. - this.columnDefinitions[0].name = 'Resize me!'; - this.columnDefinitions[0].header = { + this[`columnDefinitions${gridNo}`][0].name = 'Resize me!'; + this[`columnDefinitions${gridNo}`][0].header = { buttons: [ { cssClass: 'mdi mdi-message-text', @@ -152,8 +186,8 @@ export class Example13 { }; // Set a button on the second column to demonstrate hover. - this.columnDefinitions[1].name = 'Hover me!'; - this.columnDefinitions[1].header = { + this[`columnDefinitions${gridNo}`][1].name = 'Hover me!'; + this[`columnDefinitions${gridNo}`][1].header = { buttons: [ { cssClass: 'mdi mdi-help-circle-outline', @@ -168,10 +202,10 @@ export class Example13 { // mock a dataset const mockDataset = []; - for (let i = 0; i < 100; i++) { + for (let i = 0; i < count; i++) { const d = (mockDataset[i] = {}); d['id'] = i; - for (let j = 0; j < this.columnDefinitions.length; j++) { + for (let j = 0; j < this[`columnDefinitions${gridNo}`].length; j++) { d[j] = Math.round(Math.random() * 10) - 5; } } diff --git a/packages/common/src/interfaces/headerButton.interface.ts b/packages/common/src/interfaces/headerButton.interface.ts index 630ff1a39..07fee43a5 100644 --- a/packages/common/src/interfaces/headerButton.interface.ts +++ b/packages/common/src/interfaces/headerButton.interface.ts @@ -17,4 +17,10 @@ export interface HeaderButton extends HeaderButtonOption { export interface HeaderButtonOption { /** an extra CSS class to add to the menu button */ buttonCssClass?: string; + + /** + * defaults to false, since the default is right floating, we create the buttons in reverse order + * but if we align to left via CSS we might want to inverse the order + */ + inverseOrder?: boolean; } diff --git a/packages/common/src/plugins/__tests__/headerButton.plugin.spec.ts b/packages/common/src/plugins/__tests__/headerButton.plugin.spec.ts index 2d318e67c..d3ce47283 100644 --- a/packages/common/src/plugins/__tests__/headerButton.plugin.spec.ts +++ b/packages/common/src/plugins/__tests__/headerButton.plugin.spec.ts @@ -343,5 +343,23 @@ describe('HeaderButton Plugin', () => { `
`)); }); + + it('should populate 2x Header Buttons but in an inversed order "inverseOrder" flag is enabled and the "disabled" property is set on the 2nd button', () => { + const headerDiv = document.createElement('div'); + headerDiv.className = 'slick-header-column'; + + plugin.dispose(); + plugin.init({ inverseOrder: true }); + delete columnsMock[0].header.buttons[1].showOnHover; + columnsMock[0].header.buttons[1].disabled = true; + + const eventData = { ...new Slick.EventData(), preventDefault: jest.fn() }; + gridStub.onHeaderCellRendered.notify({ column: columnsMock[0], node: headerDiv, grid: gridStub }, eventData, gridStub); + + // add Header Buttons which are visible (2x buttons) + expect(removeExtraSpaces(headerDiv.innerHTML)).toBe(removeExtraSpaces( + `
+
`)); + }); }); }); diff --git a/packages/common/src/plugins/headerButton.plugin.ts b/packages/common/src/plugins/headerButton.plugin.ts index 501f4fab4..af66f5525 100644 --- a/packages/common/src/plugins/headerButton.plugin.ts +++ b/packages/common/src/plugins/headerButton.plugin.ts @@ -95,7 +95,13 @@ export class HeaderButtonPlugin { const column = args.column; if (column.header?.buttons && Array.isArray(column.header.buttons)) { - // Append buttons in reverse order since they are floated to the right. + // inverse the button (typically used when icons are floating left) + if (this._addonOptions?.inverseOrder) { + column.header.buttons.reverse(); + } + + // Append buttons in reverse order (unless they were inversed at previous line) + // since they are floated to the right (unless specified as inversed by the user) let i = column.header.buttons.length; while (i--) { const button = column.header.buttons[i]; diff --git a/packages/common/src/plugins/headerMenu.plugin.ts b/packages/common/src/plugins/headerMenu.plugin.ts index 3c65681d1..0cee520d0 100644 --- a/packages/common/src/plugins/headerMenu.plugin.ts +++ b/packages/common/src/plugins/headerMenu.plugin.ts @@ -276,12 +276,16 @@ export class HeaderMenuPlugin extends MenuBaseClass { if (Array.isArray(columnDefinitions) && gridOptions.enableHeaderMenu) { columnDefinitions.forEach((columnDef: Column) => { if (columnDef && !columnDef.excludeFromHeaderMenu) { - if (!columnDef.header || !columnDef.header.menu) { + if (!columnDef.header) { columnDef.header = { menu: { items: [] } }; + } else if (!columnDef.header.menu) { + // we might have header buttons without header menu, + // so only initialize the header menu without overwrite header buttons + columnDef.header.menu = { items: [] }; } const columnHeaderMenuItems: Array = columnDef?.header?.menu?.items ?? []; diff --git a/packages/common/src/styles/_variables-theme-material.scss b/packages/common/src/styles/_variables-theme-material.scss index a5aaf1721..6bb6fa03e 100644 --- a/packages/common/src/styles/_variables-theme-material.scss +++ b/packages/common/src/styles/_variables-theme-material.scss @@ -96,7 +96,7 @@ $grid-menu-title-font-size: 18px !default; $header-button-hidden-margin-right: -6px !default; $header-button-height: 18px !default; $header-button-width: 18px !default; -$header-button-margin: -7px 0 100px 0 !default; +$header-button-margin: -4px 0 100px 0 !default; $header-menu-button-height: 25px !default; $header-menu-button-icon-font-size: 24px !default; $header-menu-button-icon-width: 24px !default; diff --git a/packages/common/src/styles/_variables-theme-salesforce.scss b/packages/common/src/styles/_variables-theme-salesforce.scss index a404a3e76..ebb325331 100644 --- a/packages/common/src/styles/_variables-theme-salesforce.scss +++ b/packages/common/src/styles/_variables-theme-salesforce.scss @@ -116,7 +116,7 @@ $grid-menu-title-font-size: 18px !default; $header-button-hidden-margin-right: -6px !default; $header-button-height: 18px !default; $header-button-width: 18px !default; -$header-button-margin: -7px 0 100px 0 !default; +$header-button-margin: -4px 0 100px 0 !default; $header-menu-button-height: 25px !default; $header-menu-button-icon-font-size: 26px !default; $header-menu-button-icon-color: #706e6b !default; diff --git a/packages/common/src/styles/_variables.scss b/packages/common/src/styles/_variables.scss index ef8421be8..9b185678a 100644 --- a/packages/common/src/styles/_variables.scss +++ b/packages/common/src/styles/_variables.scss @@ -90,6 +90,7 @@ $header-row-filter-padding: 4px !default; $header-column-height: calc(17px * #{$header-row-count}) !default; // header is calculated by rows to show $header-column-background-active: darken($grid-header-background, 5%) !default; $header-column-background-hover: darken($grid-header-background, 2%) !default; +$header-column-name-margin-right: 5px !default; $header-border-top: 0 none !default; // header, column titles, that is without the Filters $header-border-right: 0 none !default; $header-border-bottom: 0 none !default; diff --git a/packages/common/src/styles/slick-bootstrap.scss b/packages/common/src/styles/slick-bootstrap.scss index d5ec63cde..017e20650 100644 --- a/packages/common/src/styles/slick-bootstrap.scss +++ b/packages/common/src/styles/slick-bootstrap.scss @@ -271,6 +271,7 @@ margin-left: 0; } } + .slick-header-column { height: var(--slick-header-column-height, $header-column-height); line-height: var(--slick-font-size-base, $font-size-base); @@ -283,6 +284,9 @@ &.ui-state-default { @include resetSlickCell(); } + .slick-column-name { + margin-right: var(--slick-header-column-name-margin-right, $header-column-name-margin-right); + } $slickgridHoverHeaderColor: var(--slick-text-color, $text-color); $slickgridSortingHeaderColor: var(--slick-text-color, $text-color); diff --git a/packages/common/src/styles/slick-plugins.scss b/packages/common/src/styles/slick-plugins.scss index b0690a17a..345af8168 100644 --- a/packages/common/src/styles/slick-plugins.scss +++ b/packages/common/src/styles/slick-plugins.scss @@ -284,6 +284,7 @@ * This makes all "float:right" elements after it that spill over to the next line * display way below the lower boundary of the column thus hiding them. */ + display: inline; float: var(--slick-header-button-float, $header-button-float); vertical-align: var(--slick-header-button-vertical-align, $header-button-vertical-align); margin: var(--slick-header-button-margin, $header-button-margin); diff --git a/test/cypress/integration/example13.spec.js b/test/cypress/integration/example13.spec.js index f36985ab6..5256d70e9 100644 --- a/test/cypress/integration/example13.spec.js +++ b/test/cypress/integration/example13.spec.js @@ -10,156 +10,412 @@ describe('Example 13 - Header Button Plugin', { retries: 1 }, () => { }); }); - it('should display Example title', () => { - cy.visit(`${Cypress.config('baseExampleUrl')}/example13`); - cy.get('h3').should('contain', 'Example 13 - Header Button Plugin'); - }); + describe('Grid 1', () => { + it('should display Example title', () => { + cy.visit(`${Cypress.config('baseExampleUrl')}/example13`); + cy.get('h3').should('contain', 'Example 13 - Header Button Plugin'); + }); - it('should have exact Column Titles in the grid', () => { - cy.get('.slick-header-columns') - .children() - .each(($child, index) => expect($child.text()).to.eq(titles[index])); - }); + it('should have exact Column Titles in the grid', () => { + cy.get('.grid13-1 .slick-header-columns') + .children() + .each(($child, index) => expect($child.text()).to.eq(titles[index])); + }); - it('should go over the 3rd column "Column C" and expect to see negative number in red after clicking on the red header button', () => { - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(2)') - .should('contain', 'Column C'); + it('should go over the 3rd column "Column C" and expect to see negative number in red after clicking on the red header button', () => { + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(2)') + .should('contain', 'Column C'); - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(2)') - .find('.slick-header-button.mdi-lightbulb-outline.color-warning.faded') - .click(); + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(2)') + .find('.slick-header-button.mdi-lightbulb-outline.color-warning.faded') + .click(); - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(2)') - .find('.slick-header-button.mdi-lightbulb-outline.color-warning.faded') - .should('not.exist'); // shouldn't be faded anymore + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(2)') + .find('.slick-header-button.mdi-lightbulb-outline.color-warning.faded') + .should('not.exist'); // shouldn't be faded anymore - cy.window().then((win) => { - expect(win.console.log).to.have.callCount(1); - expect(win.console.log).to.be.calledWith(`execute a callback action to "toggle-highlight" on Column C`); - }); - - cy.get('.slick-row') - .each(($row, index) => { - if (index > 10) { - return; // check only the first 10 rows is enough - } - cy.wrap($row).children('.slick-cell:nth(2)') - .each($cell => { - const numberValue = $cell.text(); - const htmlValue = $cell.html(); - if (+numberValue < 0) { - expect(htmlValue).to.eq(`
${numberValue}
`); - } else { - expect(htmlValue).to.eq(numberValue); - } - }); + cy.window().then((win) => { + expect(win.console.log).to.have.callCount(1); + expect(win.console.log).to.be.calledWith(`execute a callback action to "toggle-highlight" on Column C`); }); - }); - it('should go over the 5th column "Column E" and not find the red header button', () => { - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(4)') - .should('contain', 'Column E'); + cy.get('.grid13-1 .slick-row') + .each(($row, index) => { + if (index > 10) { + return; // check only the first 10 rows is enough + } + cy.wrap($row).children('.slick-cell:nth(2)') + .each($cell => { + const numberValue = $cell.text(); + const htmlValue = $cell.html(); + if (+numberValue < 0) { + expect(htmlValue).to.eq(`
${numberValue}
`); + } else { + expect(htmlValue).to.eq(numberValue); + } + }); + }); + }); - // column E should not have the icon - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(4)') - .find('.slick-header-button') - .should('not.exist'); - }); + it('should go over the 5th column "Column E" and not find the red header button', () => { + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(4)') + .should('contain', 'Column E'); + + // column E should not have the icon + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(4)') + .find('.slick-header-button') + .should('not.exist'); + }); + + 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('.grid13-1 .slick-viewport-top.slick-viewport-left') + .scrollTo('right') + .wait(50); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(9)') + .should('contain', 'Column J') + .find('.slick-header-button-disabled') + .should('exist'); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(9)') + .find('.slick-header-button.slick-header-button-disabled.mdi-lightbulb-outline.color-warning.faded') + .should('exist') + .click(); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(9)') + .find('.slick-header-button.slick-header-button-disabled.mdi-lightbulb-outline.color-warning.faded') + .should('exist'); // should still be faded after previous click - 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('.slick-viewport-top.slick-viewport-left') - .scrollTo('right') - .wait(50); - - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(9)') - .should('contain', 'Column J') - .find('.slick-header-button-disabled') - .should('exist'); - - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(9)') - .find('.slick-header-button.slick-header-button-disabled.mdi-lightbulb-outline.color-warning.faded') - .should('exist') - .click(); - - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(9)') - .find('.slick-header-button.slick-header-button-disabled.mdi-lightbulb-outline.color-warning.faded') - .should('exist'); // should still be faded after previous click - - cy.get('.slick-row') - .each(($row, index) => { - if (index > 10) { - return; - } - cy.wrap($row).children('.slick-cell:nth(9)') - .each($cell => expect($cell.html()).to.eq($cell.text())); + cy.get('.grid13-1 .slick-row') + .each(($row, index) => { + if (index > 10) { + return; + } + cy.wrap($row).children('.slick-cell:nth(9)') + .each($cell => expect($cell.html()).to.eq($cell.text())); + }); + + cy.window().then((win) => { + expect(win.console.log).to.have.callCount(0); }); + }); - cy.window().then((win) => { - expect(win.console.log).to.have.callCount(0); + it('should resize 1st column and make it wider', () => { + cy.get('.grid13-1 .slick-viewport-top.slick-viewport-left') + .scrollTo('left') + .wait(50); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .should('contain', 'Resize me!'); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button:nth(3)') + .should('be.hidden'); + + // Cypress does not yet support the .hover() method and because of that we need to manually resize the element + // this is not ideal since it only resizes the cell not the entire column but it's enough to test the functionality + cy.get('.grid13-1 .slick-header-column:nth(0)') + // resize the 1st column + .each($elm => $elm.width(140)) + .find('.slick-resizable-handle') + .should('be.visible') + .invoke('show'); + + cy.get('.grid13-1 .slick-header-column:nth(0)') + .should(($el) => { + const expectedWidth = 140; // calculate with a calculated width including a (+/-)1px precision + expect($el.width()).greaterThan(expectedWidth - 1); + expect($el.width()).lessThan(expectedWidth + 1); + }); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button') + .should('have.length', 4); + }); + + it('should resize column to its previous size and still expect some icons to be hidden', () => { + cy.get('.grid13-1 .slick-header-column:nth(0)') + // resize the 1st column + .each($elm => $elm.width(50)) + .find('.slick-resizable-handle') + .should('be.visible') + .invoke('show'); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button:nth(3)') + .should('be.hidden'); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button:nth(1)') + .should('be.hidden'); + }); + + it('should go on the 2nd column "Hover me!" and expect the header button to appear only when doing hover over it', () => { + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(1)') + .should('contain', 'Hover me!'); + + cy.get('.grid13-1 .slick-header-columns') + .children('.slick-header-column:nth(1)') + .find('.slick-header-button.slick-header-button-hidden') + .should('be.hidden') + .should('have.css', 'width', '0px'); }); }); - it('should resize 1st column and make it wider', () => { - cy.get('.slick-viewport-top.slick-viewport-left') - .scrollTo('left') - .wait(50); - - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(0)') - .should('contain', 'Resize me!'); - - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(0)') - .find('.slick-header-button:nth(3)') - .should('be.hidden'); - - // Cypress does not yet support the .hover() method and because of that we need to manually resize the element - // this is not ideal since it only resizes the cell not the entire column but it's enough to test the functionality - cy.get('.slick-header-column:nth(0)') - // resize the 1st column - .each($elm => $elm.width(140)) - .find('.slick-resizable-handle') - .should('be.visible') - .invoke('show'); - - cy.get('.slick-header-column:nth(0)') - .should(($el) => { - const expectedWidth = 140; // calculate with a calculated width including a (+/-)1px precision - expect($el.width()).greaterThan(expectedWidth - 1); - expect($el.width()).lessThan(expectedWidth + 1); + describe('Grid 2', () => { + it('should have exact Column Titles in the grid', () => { + cy.get('.grid13-2 .slick-header-columns') + .children() + .each(($child, index) => expect($child.text()).to.eq(titles[index])); + }); + + it('should go over the 3rd column "Column C" and expect to see negative number in red after clicking on the red header button', () => { + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(2)') + .should('contain', 'Column C'); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(2)') + .find('.slick-header-button.mdi-lightbulb-outline.color-warning.faded') + .click({ force: true }); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(2)') + .find('.slick-header-button.mdi-lightbulb-outline.color-warning.faded') + .should('not.exist'); // shouldn't be faded anymore + + cy.window().then((win) => { + expect(win.console.log).to.have.callCount(1); + expect(win.console.log).to.be.calledWith(`execute a callback action to "toggle-highlight" on Column C`); }); - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(0)') - .find('.slick-header-button') - .should('have.length', 4); - }); + cy.get('.grid13-2 .slick-row') + .each(($row, index) => { + if (index > 10) { + return; // check only the first 10 rows is enough + } + cy.wrap($row).children('.slick-cell:nth(2)') + .each($cell => { + const numberValue = $cell.text(); + const htmlValue = $cell.html(); + if (+numberValue < 0) { + expect(htmlValue).to.eq(`
${numberValue}
`); + } else { + expect(htmlValue).to.eq(numberValue); + } + }); + }); + }); + + it('should go over the 5th column "Column E" and not find the red header button', () => { + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(4)') + .should('contain', 'Column E'); + + // column E should not have the icon + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(4)') + .find('.slick-header-button') + .should('not.exist'); + }); + + 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('.grid13-2 .slick-viewport-top.slick-viewport-left') + .scrollTo('right') + .wait(50); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(9)') + .should('contain', 'Column J') + .find('.slick-header-button-disabled') + .should('exist'); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(9)') + .find('.slick-header-button.slick-header-button-disabled.mdi-lightbulb-outline.color-warning.faded') + .should('exist') + .click({ force: true }); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(9)') + .find('.slick-header-button.slick-header-button-disabled.mdi-lightbulb-outline.color-warning.faded') + .should('exist'); // should still be faded after previous click + + cy.get('.grid13-2 .slick-row') + .each(($row, index) => { + if (index > 10) { + return; + } + cy.wrap($row).children('.slick-cell:nth(9)') + .each($cell => expect($cell.html()).to.eq($cell.text())); + }); + + cy.window().then((win) => { + expect(win.console.log).to.have.callCount(0); + }); + }); + + it('should resize 1st column and make it wider', () => { + cy.get('.grid13-2 .slick-viewport-top.slick-viewport-left') + .scrollTo('left') + .wait(50); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .should('contain', 'Resize me!'); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button:nth(3)') + .should('be.hidden'); + + // Cypress does not yet support the .hover() method and because of that we need to manually resize the element + // this is not ideal since it only resizes the cell not the entire column but it's enough to test the functionality + cy.get('.grid13-2 .slick-header-column:nth(0)') + // resize the 1st column + .each($elm => $elm.width(140)) + .find('.slick-resizable-handle') + .should('be.visible') + .invoke('show'); + + cy.get('.grid13-2 .slick-header-column:nth(0)') + .should(($el) => { + const expectedWidth = 140; // calculate with a calculated width including a (+/-)1px precision + expect($el.width()).greaterThan(expectedWidth - 1); + expect($el.width()).lessThan(expectedWidth + 1); + }); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button') + .should('have.length', 4); + }); + + it('should resize column to its previous size and still expect some icons to be hidden', () => { + cy.get('.grid13-2 .slick-header-column:nth(0)') + // resize the 1st column + .each($elm => $elm.width(50)) + .find('.slick-resizable-handle') + .should('be.visible') + .invoke('show'); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button:nth(3)') + .should('be.hidden'); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(0)') + .find('.slick-header-button:nth(1)') + .should('be.hidden'); + }); - it('should go on the 2nd column "Hover me!" and expect the header button to appear only when doing hover over it', () => { - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(1)') - .should('contain', 'Hover me!'); - - cy.get('.slick-header-columns') - .children('.slick-header-column:nth(1)') - .find('.slick-header-button.slick-header-button-hidden') - .should('be.hidden') - .should('have.css', 'width', '0px'); - - // hover is not yet implemented in Cypress, so the following test won't work until then - // cy.get('.slick-header-columns') - // .children('.slick-header-column:nth(1)') - // .trigger('mouseover') - // .hover() - // .find('.slick-header-button') - // .should('have.css', 'width', '15px'); + it('should go on the 2nd column "Hover me!" and expect the header button to appear only when doing hover over it', () => { + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(1)') + .should('contain', 'Hover me!'); + + cy.get('.grid13-2 .slick-header-columns') + .children('.slick-header-column:nth(1)') + .find('.slick-header-button.slick-header-button-hidden') + .should('be.hidden') + .should('have.css', 'width', '0px'); + }); + + it('should filter "Column C" with positive number only and not expect any more red values', () => { + cy.get('.grid13-2 .search-filter.filter-2') + .type('>0'); + + cy.get('.grid13-2 .slick-row') + .each(($row, index) => { + if (index > 10) { + return; // check only the first 10 rows is enough + } + cy.wrap($row).children('.slick-cell:nth(2)') + .each($cell => { + const numberValue = $cell.text(); + const htmlValue = $cell.html(); + expect(+numberValue).to.be.greaterThan(0); + }); + }); + }); + + it('should hover over the "Column C" and click on "Clear Filter" and expect grid to have all rows shown', () => { + cy.get('.grid13-2 .slick-header-column:nth(2)') + .first() + .trigger('mouseover') + .children('.slick-header-menu-button') + .click(); + + cy.get('.grid13-2 .slick-header-menu') + .should('be.visible') + .children('.slick-header-menu-item:nth-child(6)') + .children('.slick-header-menu-content') + .should('contain', 'Remove Filter') + .click(); + + cy.get('.slick-row').should('have.length.greaterThan', 1); + }); + + it('should Clear all Sorting', () => { + cy.get('.grid13-2') + .find('button.slick-grid-menu-button') + .trigger('click') + .click({ force: true }); + + cy.get(`.slick-grid-menu:visible`) + .find('.slick-grid-menu-item:nth(1)') + .find('span') + .contains('Clear all Sorting') + .click(); + }); + + it('should hover over the "Column C" and click on "Sort Ascending"', () => { + cy.get('.grid13-2 .slick-header-column:nth(2)') + .first() + .trigger('mouseover') + .children('.slick-header-menu-button') + .click(); + + cy.get('.grid13-2 .slick-header-menu') + .should('be.visible') + .children('.slick-header-menu-item:nth-child(3)') + .children('.slick-header-menu-content') + .should('contain', 'Sort Ascending') + .click(); + }); + + it('should expect first few items of "Column C" to be negative numbers and be red', () => { + cy.get('.grid13-2 .slick-viewport-top.slick-viewport-left') + .scrollTo('top') + .wait(50); + + cy.get('.grid13-2 .slick-row') + .each(($row, index) => { + if (index > 10) { + return; // check only the first 10 rows is enough + } + cy.wrap($row).children('.slick-cell:nth(2)') + .each($cell => { + const numberValue = $cell.text(); + const htmlValue = $cell.html(); + expect(htmlValue).to.eq(`
${numberValue}
`); + }); + }); + }); }); });