import { Assert, context, describe, it } from '@ephox/bedrock-client'; import { Optional, OptionalInstances } from '@ephox/katamari'; import { Css, Insert, InsertAll, Remove, SelectorFind, SugarBody, SugarElement, Width } from '@ephox/sugar'; import { assert } from 'chai'; import * as fc from 'fast-check'; import { TableSize } from 'ephox/snooker/api/TableSize'; import { Warehouse } from 'ephox/snooker/api/Warehouse'; const tOptional = OptionalInstances.tOptional; describe('TableSizeTest', () => { const pixelTableHtml = '
'; const overflowingPixelTableHtml = '
'; const percentTableHtml = '
'; const overflowingPercentTableHtml = '
'; const noneTableHtml = '
'; context('getTableSize', () => { it('table with no widths should be detected as none', () => { const noneTable = SugarElement.fromHtml(noneTableHtml); const noneSizing = TableSize.getTableSize(noneTable); assert.equal(noneSizing.label, 'none', 'None sizing detected'); }); it('tables with widths should be detected as percent or pixel', () => { fc.assert(fc.property(fc.integer(100, 1000), fc.float(1, 100), (pixel, percent) => { const pixelTable = SugarElement.fromHtml(pixelTableHtml.replace('400px', pixel + 'px')); const percentageTable = SugarElement.fromHtml(percentTableHtml.replace('80%', percent + '%')); const pixelSizing = TableSize.getTableSize(pixelTable); const percentageSizing = TableSize.getTableSize(percentageTable); assert.equal(pixelSizing.label, 'pixel', 'Pixel sizing detected'); assert.equal(percentageSizing.label, 'percent', 'Percentage sizing detected'); })); }); }); context('pixelSize', () => { it('content box sizing should return pixel based widths that exclude borders in table sizes', () => { const style = SugarElement.fromHtml(''); const table = SugarElement.fromHtml(pixelTableHtml); InsertAll.append(SugarBody.body(), [ style, table ]); const sizing = TableSize.getTableSize(table); const warehouse = Warehouse.fromTable(table); assert.equal(sizing.width(), 400, 'Width should be 400px'); assert.equal(sizing.pixelWidth(), 400, 'Pixel width should be 400px'); assert.deepEqual(sizing.getWidths(warehouse, sizing), [ 198, 198 ], 'Cell widths should be 198px each'); assert.isAtLeast(sizing.minCellWidth(), 10, 'Cell min width should be at least 10px'); fc.assert(fc.property(fc.integer(-390, 390), fc.integer(400, 1000), (delta, colWidth) => { assert.equal(sizing.getCellDelta(delta), delta, 'Cell delta should be identity'); assert.deepEqual(sizing.singleColumnWidth(colWidth, delta), [ delta ], 'Single column delta width should be the delta'); })); sizing.adjustTableWidth(-200); Assert.eq('Table raw width after resizing is 200px', Optional.some('200px'), Css.getRaw(table, 'width'), tOptional()); assert.equal(sizing.width(), 200, 'Table width after resizing is 200px'); assert.equal(sizing.pixelWidth(), 200, 'Table pixel width after resizing is 200px'); const cell = SelectorFind.descendant(table, 'td').getOrDie(); sizing.setElementWidth(cell, 50); Assert.eq('Cell width after resizing is 50px', Optional.some('50px'), Css.getRaw(cell, 'width'), tOptional()); Remove.remove(table); Remove.remove(style); }); it('border box should return pixel based widths that include borders in table sizes', () => { const style = SugarElement.fromHtml(''); const table = SugarElement.fromHtml(pixelTableHtml); InsertAll.append(SugarBody.body(), [ style, table ]); const sizing = TableSize.getTableSize(table); const warehouse = Warehouse.fromTable(table); assert.equal(sizing.width(), 400, 'Width should be 400px'); assert.equal(sizing.pixelWidth(), 400, 'Pixel width should be 400px'); assert.deepEqual(sizing.getWidths(warehouse, sizing), [ 200, 200 ], 'Cell widths should be 200px each'); assert.isAtLeast(sizing.minCellWidth(), 10, 'Cell min width should be at least 10px'); fc.assert(fc.property(fc.integer(-390, 390), fc.integer(400, 1000), (delta, colWidth) => { assert.equal(sizing.getCellDelta(delta), delta, 'Cell delta should be identity'); assert.deepEqual(sizing.singleColumnWidth(colWidth, delta), [ delta ], 'Single column delta width should be the delta'); })); sizing.adjustTableWidth(-200); Assert.eq('Table raw width after resizing is 200px', Optional.some('200px'), Css.getRaw(table, 'width'), tOptional()); assert.equal(sizing.width(), 200, 'Table width after resizing is 200px'); assert.equal(sizing.pixelWidth(), 200, 'Table pixel width after resizing is 200px'); const cell = SelectorFind.descendant(table, 'td').getOrDie(); sizing.setElementWidth(cell, 50); Assert.eq('Cell width after resizing is 50px', Optional.some('50px'), Css.getRaw(cell, 'width'), tOptional()); Remove.remove(table); Remove.remove(style); }); it('TINY-7731: returned widths should use the actual width, not the specified widths', () => { const table = SugarElement.fromHtml(overflowingPixelTableHtml); Insert.append(SugarBody.body(), table); const sizing = TableSize.getTableSize(table); const warehouse = Warehouse.fromTable(table); assert.approximately(sizing.width(), 487, 1, 'Width should be ~487px'); assert.approximately(sizing.pixelWidth(), 487, 1, 'Pixel width should be ~487px'); const columnSizes = sizing.getWidths(warehouse, sizing); assert.approximately(columnSizes[0], 483, 1, 'First column should be the entire size of the table, minus borders'); assert.approximately(columnSizes[1], 0, 1, 'Second column should be 0 as there is no room for it to render'); Remove.remove(table); }); }); context('percentageSize', () => { it('should return percentage based widths in table sizes', () => { const container = SugarElement.fromHtml('
'); const table = SugarElement.fromHtml(percentTableHtml); Insert.append(container, table); Insert.append(SugarBody.body(), container); const sizing = TableSize.getTableSize(table); const warehouse = Warehouse.fromTable(table); assert.equal(sizing.width(), 80, 'Width should be 80'); assert.equal(sizing.pixelWidth(), 400, 'Pixel width should be 400px'); assert.deepEqual(sizing.getWidths(warehouse, sizing), [ 50, 50 ], 'Cell widths should be 50% each'); assert.equal(sizing.minCellWidth() >= 2.5, true, 'Cell min width should be at least 10px in percentage (2.5%)'); fc.assert(fc.property(fc.integer(-390, 390), fc.nat(100), (delta, colWidth) => { const deltaPercent = delta / 400 * 100; assert.equal(sizing.getCellDelta(delta), deltaPercent, 'Cell delta should be the same, but in percentage'); assert.deepEqual(sizing.singleColumnWidth(colWidth, delta), [ 100 - colWidth ], 'Single column delta width should be 100% - percentage width'); })); sizing.adjustTableWidth(-25); Assert.eq('Table raw width after resizing is 25% less of the original 80%', Optional.some('60%'), Css.getRaw(table, 'width'), tOptional()); assert.equal(sizing.width(), 60, 'Table width after resizing is 60%'); assert.equal(sizing.pixelWidth(), 300, 'Table pixel width after resizing is 300px'); const cell = SelectorFind.descendant(table, 'td').getOrDie(); sizing.setElementWidth(cell, 25); Assert.eq('Cell width after resizing is 25%', Optional.some('25%'), Css.getRaw(cell, 'width'), tOptional()); Remove.remove(container); }); it('TINY-7731: returned widths should use the actual width, not the specified widths', () => { const container = SugarElement.fromHtml('
'); const table = SugarElement.fromHtml(overflowingPercentTableHtml); Insert.append(container, table); Insert.append(SugarBody.body(), container); const sizing = TableSize.getTableSize(table); const warehouse = Warehouse.fromTable(table); assert.approximately(sizing.width(), 97.4, 0.5, 'Width should be ~97.4%'); assert.approximately(sizing.pixelWidth(), 487, 1, 'Pixel width should be ~487px'); const columnSizes = sizing.getWidths(warehouse, sizing); assert.approximately(columnSizes[0], 99.5, 0.5, 'First column should be the entire size of the table, minus borders'); assert.approximately(columnSizes[1], 0, 0.5, 'Second column should be 0 as there is no room for it to render'); Remove.remove(container); }); }); context('noneSize', () => { it('should return 0 or the actual widths for table sizes', () => { const table = SugarElement.fromHtml(noneTableHtml); Insert.append(SugarBody.body(), table); const sizing = TableSize.getTableSize(table); const warehouse = Warehouse.fromTable(table); const width = Width.get(table); const cellWidth = SelectorFind.descendant(table, 'td') .map((cell) => parseInt(Css.get(cell, 'width'), 10)) .getOrDie(); assert.equal(sizing.width(), width, 'Width should be the computed size of the table'); assert.equal(sizing.pixelWidth(), width, 'Pixel width should be the computed size of the table'); assert.deepEqual(sizing.getWidths(warehouse, sizing), [ cellWidth, cellWidth ], 'Cell widths should be the computed size of the cell'); assert.equal(sizing.minCellWidth(), 0, 'Cell min width should be 0px'); fc.assert(fc.property(fc.integer(-390, 390), fc.integer(400, 1000), (delta, colWidth) => { assert.equal(sizing.getCellDelta(delta), 0, 'Cell delta should be 0'); assert.deepEqual(sizing.singleColumnWidth(colWidth, delta), [ 0 ], 'Single column delta width should be 0'); })); sizing.adjustTableWidth(-20); Assert.eq('Table raw width after resizing is unchanged', Optional.none(), Css.getRaw(table, 'width'), tOptional()); assert.equal(sizing.width(), width, 'Table width after resizing is unchanged'); assert.equal(sizing.pixelWidth(), width, 'Table pixel width after resizing is unchanged'); const cell = SelectorFind.descendant(table, 'td').getOrDie(); sizing.setElementWidth(cell, 20); Assert.eq('Cell width after resizing is unchanged', Optional.none(), Css.getRaw(cell, 'width'), tOptional()); Remove.remove(table); }); }); });