import { Page } from "tns-core-modules/ui/page"; import { GridLayout, ItemSpec } from "tns-core-modules/ui/layouts/grid-layout"; import { Button } from "tns-core-modules/ui/button"; import * as TKUnit from "../../TKUnit"; import * as view from "tns-core-modules/ui/core/view"; import { unsetValue } from "tns-core-modules/ui/core/view"; import * as builder from "tns-core-modules/ui/builder"; import * as testModule from "../../ui-test"; import * as layoutHelper from "./layout-helper"; import * as platform from "tns-core-modules/platform"; import { ios as iosUtils } from "tns-core-modules/utils/utils"; import * as commonTests from "./common-layout-tests"; import * as helper from "../helper"; import { parse } from "tns-core-modules/ui/builder"; import { dipToDp, left, top, right, bottom, height, width, paddingLeft, paddingTop, paddingRight, paddingBottom, equal, closeEnough, notEqual, check, heightEqual, widthEqual, isLeftAlignedWith, isRightAlignedWith, isTopAlignedWith, isBottomAlignedWith, isLeftOf, isRightOf, isBelow, isAbove, isLeftWith, isAboveWith, isRightWith, isBelowWith } from "./layout-tests-helper"; var DELTA = 1; class RemovalTrackingGridLayout extends GridLayout { public removedRows = 0; public removedCols = 0; public _onRowRemoved(itemSpec: ItemSpec, index: number) { this.removedRows++; super._onRowRemoved(itemSpec, index); } public _onColumnRemoved(itemSpec: ItemSpec, index: number) { this.removedCols++; super._onColumnRemoved(itemSpec, index); } } export class GridLayoutTest extends testModule.UITest { public create(): RemovalTrackingGridLayout { return new RemovalTrackingGridLayout(); } public test_recycling() { helper.nativeView_recycling_test(() => new GridLayout()); } public test_item_recycling() { helper.nativeView_recycling_test(() => new Button(), () => new GridLayout()); } private row(view: view.View): number { return GridLayout.getRow(view); } private rowSpan(view: view.View): number { return GridLayout.getRowSpan(view); } private col(view: view.View): number { return GridLayout.getColumn(view); } private colSpan(view: view.View): number { return GridLayout.getColumnSpan(view); } // TODO: Start Refactor private getViews (template: string) { let root = parse(template); return { root, grid: root.getViewById("grid") as GridLayout, cells: [ [ root.getViewById("cell00") as view.View, root.getViewById("cell01") as view.View, root.getViewById("cell02") as view.View ], [ root.getViewById("cell10") as view.View, root.getViewById("cell11") as view.View, root.getViewById("cell12") as view.View ], [ root.getViewById("cell20") as view.View, root.getViewById("cell21") as view.View, root.getViewById("cell22") as view.View ] ] }; }; private executeSnippet(ui: U, setup: (ui: U) => void, test: (ui: U) => void): void { function waitUntilTestElementLayoutIsValid(view: view.View, timeoutSec?: number): void { TKUnit.waitUntilReady(() => { return view.isLayoutValid; }, timeoutSec || 1); } setup(ui); helper.buildUIAndRunTest(ui.root, () => { waitUntilTestElementLayoutIsValid(ui.root); test(ui); }); }; private noop() { // no operation }; // TODO: End Refactor private prepareGridLayout(wait?: boolean) { this.testView.addRow(new ItemSpec(1, "star")); this.testView.addRow(new ItemSpec(2, "star")); this.testView.addRow(new ItemSpec(layoutHelper.dp(50), "pixel")); this.testView.addRow(new ItemSpec(50, "auto")); this.testView.addColumn(new ItemSpec(1, "star")); this.testView.addColumn(new ItemSpec(2, "star")); this.testView.addColumn(new ItemSpec(layoutHelper.dp(50), "pixel")); this.testView.addColumn(new ItemSpec(50, "auto")); for (var r = 0; r < 4; r++) { for (var c = 0; c < 4; c++) { var btn = new layoutHelper.MyButton(); btn.text = "R" + r + "C" + c; GridLayout.setColumn(btn, c); GridLayout.setRow(btn, r); if (c === 3) { btn.width = { value: 100, unit: "px" }; // Auto column should take 100px for this test. } if (r === 3) { btn.height = { value: 100, unit: "px" }; // Auto row should take 100px for this test. } this.testView.addChild(btn); } } this.testView.width = { value: 300, unit: "px" }; this.testView.height = { value: 300, unit: "px" }; if (wait) { this.waitUntilTestElementLayoutIsValid(); } } public test_layout_in_fullscreen() { const snippet = ` `; this.executeSnippet( this.getViews(snippet), this.noop, ({ root, grid, cells }) => { const fullscreenOrigin = { x: 0, y: 0}; if (platform.isIOS && iosUtils.MajorVersion < 11) { const safeAreaOrigin = grid.parent.nativeViewProtected.safeAreaLayoutGuide.layoutFrame.origin; fullscreenOrigin.y += dipToDp(safeAreaOrigin.y); fullscreenOrigin.x += dipToDp(safeAreaOrigin.x); } equal(left(grid), fullscreenOrigin.x, `actual:${grid}.left:${left(grid)} expected:${fullscreenOrigin.x}`); equal(top(grid), fullscreenOrigin.y, `actual:${grid}.top:${top(grid)} expected:${fullscreenOrigin.y}`); equal(right(grid), platform.screen.mainScreen.widthPixels, `actual:${grid}.right:${right(grid)} expected:${platform.screen.mainScreen.widthPixels}`); equal(bottom(grid), platform.screen.mainScreen.heightPixels, `actual:${grid}.bottom:${bottom(grid)} expected:${platform.screen.mainScreen.heightPixels}`); } ); } public test_component_cells_layout_in_safe_area() { const snippet = ` `; this.executeSnippet( this.getViews(snippet), this.noop, ({ root, grid, cells }) => { const insets = grid.getSafeAreaInsets(); equal(left(cells[0][0]), insets.left, `cell00 left actual:<${left(cells[0][0])}> expected:<${insets.left}>`); equal(left(cells[1][0]), insets.left, `cell10 left actual:<${left(cells[1][0])}> expected:<${insets.left}>`); equal(left(cells[2][0]), insets.left, `cell20 left actual:<${left(cells[2][0])}> expected:<${insets.left}>`); isBelowWith(grid, cells[0][0], insets.top); isBelowWith(grid, cells[0][1], insets.top); isBelowWith(grid, cells[0][2], insets.top); equal(right(cells[0][2]), width(grid) - insets.right, `cell02 left actual:<${left(cells[0][2])}> expected:<${width(grid) - insets.right}>`); equal(right(cells[1][2]), width(grid) - insets.right, `cell12 left actual:<${left(cells[1][2])}> expected:<${width(grid) - insets.right}>`); equal(right(cells[2][2]), width(grid) - insets.right, `cell22 left actual:<${left(cells[2][2])}> expected:<${width(grid) - insets.right}>`); isAboveWith(cells[2][0], grid, insets.bottom); isAboveWith(cells[2][1], grid, insets.bottom); isAboveWith(cells[2][2], grid, insets.bottom); equal(height(cells[0][1]), height(cells[1][1]), `cell height should be equal - cell01<${height(cells[0][1])}> - cell11<${height(cells[1][1])}>`); equal(height(cells[1][1]), height(cells[2][1]), `cell height should be equal - cell11<${height(cells[1][1])}> - cell21<${height(cells[2][1])}>`); const sumOfLabelHeightAndInsets = insets.top + height(cells[0][1]) + height(cells[1][1]) + height(cells[2][1]) + insets.bottom; equal(height(grid), sumOfLabelHeightAndInsets, `grid height<${height(grid)}> sum of labels height and insets<${sumOfLabelHeightAndInsets}>`); equal(width(cells[1][0]), width(cells[1][1]), `cell width should be equal - cell10<${width(cells[1][0])}> - cell11<${width(cells[1][1])}>`); equal(width(cells[1][1]), width(cells[1][2]), `cell width should be equal - cell11<${width(cells[1][1])}> - cell12<${width(cells[1][2])}>`); const sumOfLabelWidthsAndInsets = insets.left + width(cells[1][0]) + width(cells[1][1]) + width(cells[1][2]) + insets.right; equal(width(grid), sumOfLabelWidthsAndInsets, `grid width<${width(grid)}> sum of nested grids width and insets<${sumOfLabelWidthsAndInsets}>`); } ); } public test_nested_grid_cells_layout_beyond_safe_area() { const snippet = ` `; this.executeSnippet( this.getViews(snippet), this.noop, ({ root, grid, cells }) => { isLeftAlignedWith(grid, cells[0][0]); isLeftAlignedWith(grid, cells[1][0]); isLeftAlignedWith(grid, cells[2][0]); isTopAlignedWith(grid, cells[0][0]); isTopAlignedWith(grid, cells[0][1]); isTopAlignedWith(grid, cells[0][2]); isRightAlignedWith(grid, cells[0][2]); isRightAlignedWith(grid, cells[1][2]); isRightAlignedWith(grid, cells[2][2]); isBottomAlignedWith(grid, cells[2][0]); isBottomAlignedWith(grid, cells[2][1]); isBottomAlignedWith(grid, cells[2][2]); check(height(cells[0][1]) >= height(cells[1][1]), `cell01 height<${height(cells[0][1])}> not greater or equal cell11 height<${height(cells[1][1])}>`); check(height(cells[1][1]) <= height(cells[2][1]), `cell11 height<${height(cells[1][1])}> not less or equal cell21 height<${height(cells[2][1])}>`); const sumOfNestedGridHeights = height(cells[0][1]) + height(cells[1][1]) + height(cells[2][1]); equal(height(grid), sumOfNestedGridHeights, `grid height<${height(grid)}> sum of nested grids height <${sumOfNestedGridHeights}>`); check(width(cells[1][0]) >= width(cells[1][1]), `cell10 width<${width(cells[1][0])}> not greater or equal cell11 width<${width(cells[1][1])}>`); check(width(cells[1][1]) <= width(cells[1][2]), `cell11 width<${width(cells[1][1])}> not less or equal cell12 width<${width(cells[1][2])}>`); const sumOfNestedGridWidths = width(cells[1][0]) + width(cells[1][1]) + width(cells[1][2]) equal(width(grid), sumOfNestedGridWidths, `grid width<${width(grid)}> sum of nested grids width <${sumOfNestedGridWidths}>`); } ); } public test_row_defaultValue() { var test = new Button(); TKUnit.assert(test !== null); TKUnit.assertEqual(this.row(test), 0, "'row' property default value should be 0."); } public test_rowSpan_defaultValue() { var test = new Button(); TKUnit.assert(test !== null); TKUnit.assertEqual(this.rowSpan(test), 1, "'rowSpan' property default value should be 1."); } public test_column_defaultValue() { var test = new Button(); TKUnit.assert(test !== null); TKUnit.assertEqual(this.col(test), 0, "'column' property default value should be 0."); } public test_columnSpan_defaultValue() { var test = new Button(); TKUnit.assert(test !== null); TKUnit.assertEqual(this.colSpan(test), 1, "'columnSpan' property default value should be 1."); } public test_getRow_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.getRow(null); }, "getRow called with null should throw exception"); } public test_getRowSpan_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.getRowSpan(null); }, "getRowSpan called with null should throw exception"); } public test_getColumn_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.getColumn(null); }, "getColumn called with null should throw exception"); } public test_getColumnSpan_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.getColumnSpan(null); }, "getColumnSpan called with null should throw exception"); } public test_setRow_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.setRow(null, 1); }, "setRow called with null should throw exception"); } public test_setRowSpan_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.setRowSpan(null, 1); }, "setRowSpan called with null should throw exception"); } public test_setColumn_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.setColumn(null, 1); }, "setColumn called with null should throw exception") } public test_setColumnSpan_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { GridLayout.setColumnSpan(null, 1); }, "setColumnSpan called with null should throw exception"); } public test_setRow_shouldNotThrow_onNegativeValues() { GridLayout.setRow(new Button(), -1); } public test_setRowSpan_shouldNotThrow_onNotPositiveValues() { GridLayout.setRowSpan(new Button(), 0); } public test_setColumn_shouldNotThrow_onNegativeValues() { GridLayout.setColumn(new Button(), -1); } public test_setColumnSpan_shouldNotThrow_onNotPositiveValues() { GridLayout.setColumnSpan(new Button(), 0); } public test_addRow_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { this.testView.addRow(null); }, "addRow called with null should throw exception"); } public test_addColumn_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { this.testView.addColumn(null); }, "addColumn called with null should throw exception"); } public test_removeRow_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { this.testView.removeRow(null); }, "removeRow called with null should throw exception"); } public test_removeColumn_shouldThrow_onNullValues() { TKUnit.assertThrows(() => { this.testView.removeColumn(null); }, "removeColumn called with null should throw exception"); } public test_removeColumns() { this.prepareGridLayout(false); const colsBefore = this.testView.getColumns().length; TKUnit.assertTrue(colsBefore > 0, "There should be columns."); this.testView.removeColumns(); TKUnit.assertTrue(this.testView.getColumns().length === 0, "Columns should be empty."); TKUnit.assertTrue(this.testView.removedCols === colsBefore, "_onColumnRemoved called for each column."); } public test_removeRows() { this.prepareGridLayout(false); const rowsBefore = this.testView.getRows().length; TKUnit.assertTrue(rowsBefore > 0, "There should be rows."); this.testView.removeRows(); TKUnit.assertTrue(this.testView.getRows().length === 0, "Rows should be empty."); TKUnit.assertTrue(this.testView.removedRows === rowsBefore, "_onRowRemoved called for each row."); } public test_removeChildren() { this.prepareGridLayout(false); TKUnit.assertTrue(this.testView.getChildrenCount() > 0, "There should be children."); this.testView.removeChildren(); TKUnit.assertTrue(this.testView.getChildrenCount() === 0, "Childrens should be empty."); } public test_measuredWidth_when_not_stretched_single_column() { this.testView.horizontalAlignment = "center"; let btn = new Button(); btn.text = "A"; this.testView.addChild(btn); this.waitUntilTestElementLayoutIsValid(); TKUnit.assertTrue(btn.getMeasuredWidth() === this.testView.getMeasuredWidth()); TKUnit.assertTrue(this.testView.getMeasuredWidth() < platform.screen.mainScreen.widthPixels); } public test_measuredWidth_when_not_stretched_two_columns() { this.testView.horizontalAlignment = "center"; this.testView.addColumn(new ItemSpec(layoutHelper.dp(80), "pixel")); this.testView.addColumn(new ItemSpec(1, "star")); let btn = new Button(); btn.text = "A"; btn.width = { value: 100, unit: "px" }; GridLayout.setColumnSpan(btn, 2); this.testView.addChild(btn); this.waitUntilTestElementLayoutIsValid(); var cols = this.testView.getColumns(); TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, "column 0"); TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(20)), DELTA, "column 1"); TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 100, DELTA, "measured width"); } public test_measuredWidth_when_not_stretched_three_columns() { this.testView.horizontalAlignment = "center"; this.testView.addColumn(new ItemSpec(layoutHelper.dp(80), "pixel")); this.testView.addColumn(new ItemSpec(1, "star")); this.testView.addColumn(new ItemSpec(1, "auto")); for (let i = 1; i < 4; i++) { let btn = new Button(); btn.text = "A"; btn.width = { value: i * 20, unit: "px" }; GridLayout.setColumn(btn, i - 1); this.testView.addChild(btn); } let btn = new Button(); btn.text = "B"; btn.width = { value: 100, unit: "px" }; GridLayout.setColumnSpan(btn, 3); this.testView.addChild(btn); this.waitUntilTestElementLayoutIsValid(); var cols = this.testView.getColumns(); TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, "column 0"); TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(40)), DELTA, "column 1"); TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(60)), DELTA, "column 2"); TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 180, DELTA, "measured width"); } public test_getRows_shouldNotReturnNULL() { var rows = this.testView.getRows(); TKUnit.assert(rows, "getRows should not return null/undefinied"); } public test_getColumns_shouldNotReturnNULL() { var cols = this.testView.getColumns(); TKUnit.assert(cols, "getColumns should not return null/undefinied"); } public test_ItemSpec_actualLength_defaultValue() { var def = new ItemSpec(1, "auto"); TKUnit.assertEqual(def.actualLength, 0, "'actualLength' property default value should be 0."); } public test_ItemSpec_constructor_throws_onNegativeValue() { TKUnit.assertThrows(() => { return new ItemSpec(-1, "auto"); }, "'value' should be positive number."); } public test_ItemSpec_constructor_doesnt_throw_onCorrectType() { try { var dummy = new ItemSpec(1, "auto"); dummy = new ItemSpec(1, "star"); dummy = new ItemSpec(1, "pixel"); } catch (ex) { TKUnit.assert(false, "ItemSpec type should support auto, star and pixel."); } } public test_ItemSpec_constructor_throws_onWrongType() { TKUnit.assertThrows(() => { return new ItemSpec(1, "unsupported"); }, "Invalid value: unsupported"); } public test_ItemSpec_auto() { var w = new ItemSpec(1, "auto"); TKUnit.assertEqual(w.gridUnitType, "auto", "'gridUnitType' property default value should be 'auto'"); TKUnit.assertEqual(w.isAbsolute, false, "'isAbsolute' property default value should be 'false'"); TKUnit.assertEqual(w.isAuto, true, "'isAuto' property default value should be 'false'"); TKUnit.assertEqual(w.isStar, false, "'isAuto' property default value should be 'true'"); TKUnit.assertEqual(w.value, 1, "'value' property default value should be '1'"); } public test_ItemSpec_unitType_pixel() { var w = new ItemSpec(6, "pixel"); TKUnit.assertEqual(w.gridUnitType, "pixel", "'gridUnitType' property default value should be 'pixel'"); TKUnit.assertEqual(w.isAbsolute, true, "'isAbsolute' property default value should be 'false'"); TKUnit.assertEqual(w.isAuto, false, "'isAuto' property default value should be 'false'"); TKUnit.assertEqual(w.isStar, false, "'isAuto' property default value should be 'true'"); TKUnit.assertEqual(w.value, 6, "'value' property default value should be '1'"); } public test_ItemSpec_unitType() { var w = new ItemSpec(2, "star"); TKUnit.assertEqual(w.gridUnitType, "star", "'gridUnitType' property default value should be 'star'"); TKUnit.assertEqual(w.isAbsolute, false, "'isAbsolute' property default value should be 'false'"); TKUnit.assertEqual(w.isAuto, false, "'isAuto' property default value should be 'false'"); TKUnit.assertEqual(w.isStar, true, "'isAuto' property default value should be 'true'"); TKUnit.assertEqual(w.value, 2, "'value' property default value should be '1'"); } public test_desiredSize_isCorrect() { this.prepareGridLayout(false); this.testView.width = unsetValue; this.testView.height = unsetValue; this.waitUntilTestElementLayoutIsValid(); var maxWidth = 0; var maxHeight = 0; var width = 0; var height = 0; var i = 0; var cols = this.testView.getColumns(); var rows = this.testView.getRows(); for (var r = 0; r < 4; r++) { width = 0; height = 0; for (var c = 0; c < 4; c++) { var btn = this.testView.getChildAt(i++); if (cols[c].isAbsolute) { width += layoutHelper.dip(cols[c].actualLength); } else { width += btn.getMeasuredWidth(); } height = Math.max(height, btn.getMeasuredHeight()); } maxWidth = Math.max(maxWidth, width); if (rows[r].isAbsolute) { maxHeight += layoutHelper.dip(rows[r].actualLength); } else { maxHeight += height; } } let measuredWidth = this.testView.getMeasuredWidth(); let measuredHeight = this.testView.getMeasuredHeight(); TKUnit.assertAreClose(measuredWidth, maxWidth, DELTA, "GridLayout incorrect measured width"); TKUnit.assertAreClose(measuredHeight, maxHeight, DELTA, "GridLayout incorrect measured height"); } public test_columnsActualWidth_isCorrect() { this.prepareGridLayout(true); var cols = this.testView.getColumns(); TKUnit.assertEqual(cols[0].actualLength, Math.round(layoutHelper.dp(50)), "Star column should be 50px width"); TKUnit.assertEqual(cols[1].actualLength, Math.round(layoutHelper.dp(100)), "2*Star column should be 100px width"); TKUnit.assertEqual(cols[2].actualLength, Math.round(layoutHelper.dp(50)), "Absolute column should be 50px width"); TKUnit.assertEqual(cols[3].actualLength, Math.round(layoutHelper.dp(100)), "Auto column should be 100px width"); } public test_rowsActualHeight_isCorrect() { this.prepareGridLayout(true); var rows = this.testView.getRows(); TKUnit.assertEqual(rows[0].actualLength, Math.round(layoutHelper.dp(50)), "Star row should be 50px width"); TKUnit.assertEqual(rows[1].actualLength, Math.round(layoutHelper.dp(100)), "2*Star row should be 100px width"); TKUnit.assertEqual(rows[2].actualLength, Math.round(layoutHelper.dp(50)), "Absolute row should be 50px width"); TKUnit.assertEqual(rows[3].actualLength, Math.round(layoutHelper.dp(100)), "Auto row should be 100px width"); } public test_Measure_and_Layout_Children_withCorrect_size() { this.prepareGridLayout(true); var rows = this.testView.getRows(); var cols = this.testView.getColumns(); var i = 0; for (var r = 0; r < 4; r++) { for (var c = 0; c < 4; c++) { var btn = this.testView.getChildAt(i++); var col = cols[c]; var row = rows[r]; var h = r % 2 === 0 ? 50 : 100; var w = c % 2 === 0 ? 50 : 100; if (row.isAuto) { TKUnit.assertAreClose(btn.layoutHeight, btn.getMeasuredHeight(), DELTA, "Auto rows should layout with measured height"); } else if (row.isAbsolute) { TKUnit.assertAreClose(btn.measureHeight, h, DELTA, "Absolute rows should measure with specific height"); TKUnit.assertAreClose(btn.layoutHeight, h, DELTA, "Absolute rows should layout with specific height"); } else { TKUnit.assertAreClose(btn.measureHeight, h, DELTA, "Star rows should measure with specific height"); TKUnit.assertAreClose(btn.layoutHeight, h, DELTA, "Star rows should layout with exact length"); } if (col.isAuto) { TKUnit.assertAreClose(btn.layoutWidth, btn.getMeasuredWidth(), DELTA, "Auto columns should layout with measured width"); } else if (col.isAbsolute) { TKUnit.assertAreClose(btn.measureWidth, w, DELTA, "Absolute columns should measure with specific width"); TKUnit.assertAreClose(btn.layoutWidth, w, DELTA, "Absolute columns should layout with specific width"); } else { TKUnit.assertAreClose(btn.measureWidth, w, DELTA, "Star columns should measure with specific width"); TKUnit.assertAreClose(btn.layoutWidth, w, DELTA, "Star columns should layout with exact length"); } } } } public test_ColumnWidth_when_4stars_and_width_110() { this.testView.width = { value: 110, unit: "px" }; this.testView.addColumn(new ItemSpec(1, "star")); this.testView.addColumn(new ItemSpec(1, "star")); this.testView.addColumn(new ItemSpec(1, "star")); this.testView.addColumn(new ItemSpec(1, "star")); this.waitUntilTestElementLayoutIsValid(); var cols = this.testView.getColumns(); TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(28)), DELTA, "Column[0] actual length should be 28"); TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(27)), DELTA, "Column[1] actual length should be 27"); TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(28)), DELTA, "Column[2] actual length should be 28"); TKUnit.assertAreClose(cols[3].actualLength, Math.round(layoutHelper.dp(27)), DELTA, "Column[3] actual length should be 27"); } public test_margins_and_verticalAlignment_center() { this.testView.height = { value: 200, unit: "px" }; this.testView.width = { value: 200, unit: "px" }; var btn = new layoutHelper.MyButton(); btn.text = "btn"; btn.height = { value: 100, unit: "px" }; btn.width = { value: 100, unit: "px" }; btn.marginBottom = { value: 50, unit: "px" }; btn.marginRight = { value: 50, unit: "px" }; this.testView.addChild(btn); this.waitUntilTestElementLayoutIsValid(); TKUnit.assertAreClose(btn.layoutTop, 25, DELTA, "vertical margins"); TKUnit.assertAreClose(btn.layoutLeft, 25, DELTA, "horizontal margins"); } public test_set_columns_in_XML_comma_separator() { var p = builder.parse("