diff --git a/.template-lintrc.js b/.template-lintrc.js index ecf4da154..327107d62 100644 --- a/.template-lintrc.js +++ b/.template-lintrc.js @@ -12,6 +12,7 @@ module.exports = { files: ['tests/integration/**'], rules: { 'require-input-label': 'off', + 'no-curly-component-invocation': 'off', // Disabled until we refactor the table tests }, }, ], diff --git a/addon/components/au-data-table/default-data-table-content-body.js b/addon/components/au-data-table/default-data-table-content-body.js index 57d7fc262..5e4e35a89 100644 --- a/addon/components/au-data-table/default-data-table-content-body.js +++ b/addon/components/au-data-table/default-data-table-content-body.js @@ -5,7 +5,6 @@ import { oneWay } from '@ember/object/computed'; import Component from '@ember/component'; // Source: https://github.com/mu-semtech/ember-data-table/blob/c690a3948b2d9d5f91d69f0a935c6b5cdb4862ca/addon/components/default-data-table-content-body.js - export default Component.extend({ tagName: '', allFields: oneWay('data-table.parsedFields'), diff --git a/tests/integration/components/au-data-table-test.gjs b/tests/integration/components/au-data-table-test.gjs new file mode 100644 index 000000000..9075487ec --- /dev/null +++ b/tests/integration/components/au-data-table-test.gjs @@ -0,0 +1,29 @@ +import AuDataTable from '@appuniversum/ember-appuniversum/components/au-data-table'; +import { render } from '@ember/test-helpers'; +import { setupRenderingTest } from 'ember-qunit'; +import { module, test } from 'qunit'; + +module('Integration | Component | au-data-table', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + const content = []; + content.meta = { + pagination: { + first: { number: 1 }, + last: { number: 10 }, + }, + }; + + await render( + , + ); + + assert.dom('.au-c-data-table').exists({ count: 1 }); + }); +}); diff --git a/tests/integration/components/au-data-table-test.js b/tests/integration/components/au-data-table-test.js deleted file mode 100644 index 9efcb86ad..000000000 --- a/tests/integration/components/au-data-table-test.js +++ /dev/null @@ -1,17 +0,0 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module('Integration | Component | au-data-table', function (hooks) { - setupRenderingTest(hooks); - - test('it renders', async function (assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); - - await render(hbs``); - - assert.dom(this.element).hasText('No data'); - }); -}); diff --git a/tests/integration/components/au-data-table/au-data-table-content-body-test.js b/tests/integration/components/au-data-table/au-data-table-content-body-test.js new file mode 100644 index 000000000..fed7e5698 --- /dev/null +++ b/tests/integration/components/au-data-table/au-data-table-content-body-test.js @@ -0,0 +1,181 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { click, render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module( + 'Integration | Component | au-data-table-content-body', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + await render(hbs``); + assert.dom('tbody').exists({ count: 1 }); + }); + + test('display rows', async function (assert) { + this.set('content', [ + { firstName: 'John', lastName: 'Doe', age: 20 }, + { firstName: 'Jane', lastName: 'Doe', age: 21 }, + ]); + this.set('dataTable', {}); + this.set('dataTable.parsedFields', ['firstName', 'lastName', 'age']); + this.set('dataTable.selection', []); + + await render( + hbs`{{au-data-table-content-body content=this.content data-table=this.dataTable}}`, + ); + + assert.dom('tr').exists({ count: 2 }, 'displays 2 rows'); + assert + .dom('tr:first-child td') + .exists({ count: 3 }, 'displays 3 columns'); + assert + .dom('tr:first-child td:first-child') + .hasText('John', 'displays firstName in first column'); + assert + .dom('tr:first-child td:nth-child(2)') + .hasText('Doe', 'displays lastName in second column'); + assert + .dom('tr:first-child td:nth-child(3)') + .hasText('20', 'displays age in third column'); + }); + + test('add checkboxes for selection if enabled', async function (assert) { + const john = { firstName: 'John', lastName: 'Doe', age: 20 }; + const jane = { firstName: 'Jane', lastName: 'Doe', age: 21 }; + const jeff = { firstName: 'Jeff', lastName: 'Doe', age: 22 }; + this.set('content', [john, jane, jeff]); + this.set('data-table', {}); + this.set('data-table.parsedFields', ['firstName', 'lastName', 'age']); + this.set('data-table.selection', [jane]); + + await render( + hbs`{{au-data-table-content-body content=this.content data-table=this.data-table enableSelection=true}}`, + ); + + assert + .dom('tr:first-child td') + .exists({ count: 4 }, 'displays 4 columns'); + assert.dom('tr.selected').exists({ count: 1 }, 'displays 1 selected row'); + assert + .dom('tr input[type="checkbox"]') + .exists({ count: 3 }, 'displays a checkbox on each row'); + assert + .dom('tr input[type="checkbox"]:checked') + .isChecked('displays 1 checked checkbox'); + }); + + test('toggles selection if checkbox is clicked', async function (assert) { + const john = { firstName: 'John', lastName: 'Doe', age: 20 }; + const jane = { firstName: 'Jane', lastName: 'Doe', age: 21 }; + const jeff = { firstName: 'Jeff', lastName: 'Doe', age: 22 }; + this.set('content', [john, jane, jeff]); + this.set('data-table', {}); + this.set('data-table.parsedFields', ['firstName', 'lastName', 'age']); + this.set('data-table.selection', [jane]); + this.set('data-table.addItemToSelection', () => + this.set('data-table.selection', [john, jane]), + ); // mock function + this.set('data-table.removeItemFromSelection', function () {}); // mock function + + await render( + hbs`{{au-data-table-content-body content=this.content data-table=this.data-table enableSelection=true}}`, + ); + + assert + .dom('tr input[type="checkbox"]:checked') + .isChecked('displays 1 checked checkbox before selecting a row'); + + await click('tr:first-child input[type="checkbox"]'); + + assert + .dom('tr input[type="checkbox"]:checked') + .isChecked('displays 2 checked checkboxes after selecting a row'); + }); + + test('add line numbers if enabled', async function (assert) { + const john = { firstName: 'John', lastName: 'Doe', age: 20 }; + const jane = { firstName: 'Jane', lastName: 'Doe', age: 21 }; + const jeff = { firstName: 'Jeff', lastName: 'Doe', age: 22 }; + this.set('content', [john, jane, jeff]); + this.set('data-table', {}); + this.set('data-table.parsedFields', ['firstName', 'lastName', 'age']); + this.set('data-table.selection', []); + + await render( + hbs`{{au-data-table-content-body content=this.content data-table=this.data-table enableLineNumbers=true}}`, + ); + + assert + .dom('tr:first-child td') + .exists({ count: 4 }, 'displays 4 columns'); + assert + .dom('tr:first-child td:first-child') + .hasText('1', 'displays offset 1 on the first row'); + assert + .dom('tr:nth-child(2) td:first-child') + .hasText('2', 'displays offset 2 on the second row'); + assert + .dom('tr:nth-child(3) td:first-child') + .hasText('3', 'displays offset 3 on the third row'); + + this.set('data-table.page', 2); + this.set('data-table.size', 5); + await render( + hbs`{{au-data-table-content-body content=this.content data-table=this.data-table enableLineNumbers=true}}`, + ); + + assert + .dom('tr:first-child td') + .exists({ count: 4 }, 'displays 4 columns on page 3'); + assert + .dom('tr:first-child td:first-child') + .hasText('11', 'displays offset 11 on the first row on page 3'); + assert + .dom('tr:nth-child(2) td:first-child') + .hasText('12', 'displays offset 12 on the second row on page 3'); + assert + .dom('tr:nth-child(3) td:first-child') + .hasText('13', 'displays offset 13 on the third row of page 3'); + }); + + test('displays no data message if there is no data', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + this.set('noDataMessage', 'No data'); + this.set('data-table', {}); + this.set('data-table.parsedFields', ['firstName', 'lastName', 'age']); + this.set('data-table.selection', []); + + await render( + hbs`{{au-data-table-content-body noDataMessage=this.noDataMessage data-table=this.data-table}}`, + ); + assert + .dom('td.au-c-data-table__message') + .exists({ count: 1 }, 'displays a no data message if no content') + .hasText('No data', 'displays message "No data" if no content'); + + this.set('content', []); + await render( + hbs`{{au-data-table-content-body content=this.content noDataMessage=this.noDataMessage data-table=this.data-table}}`, + ); + assert + .dom('td.au-c-data-table__message') + .exists({ count: 1 }, 'displays a no data message if empty content'); + assert + .dom('td.au-c-data-table__message') + .hasText('No data', 'displays message "No data" if empty content'); + + this.set('content', ['foo', 'bar']); + await render( + hbs`{{au-data-table-content-body content=this.content noDataMessage=this.noDataMessage data-table=this.data-table}}`, + ); + assert + .dom('td.au-c-data-table__message') + .doesNotExist('displays no message when there is content'); + }); + }, +); diff --git a/tests/integration/components/au-data-table/au-data-table-content-header-test.js b/tests/integration/components/au-data-table/au-data-table-content-header-test.js new file mode 100644 index 000000000..63195aac3 --- /dev/null +++ b/tests/integration/components/au-data-table/au-data-table-content-header-test.js @@ -0,0 +1,86 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module( + 'Integration | Component | au-data-table-content-header', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs`{{au-data-table-content-header}}`); + assert.dom('thead').exists({ count: 1 }); + + assert.dom('*').hasText(''); + + // Template block usage: + await render(hbs` + {{#au-data-table-content-header}} + template block text + {{/au-data-table-content-header}} + `); + + assert.dom('*').hasText('template block text'); + }); + + test('display column headers', async function (assert) { + this.set('data-table', {}); + this.set('data-table.parsedFields', ['firstName', 'lastName', 'age']); + + await render( + hbs`{{au-data-table-content-header data-table=this.data-table}}`, + ); + assert.dom('tr').exists({ count: 1 }, 'displays 1 header row'); + assert + .dom('tr:first-child th') + .exists({ count: 3 }, 'displays 3 column headers'); + assert + .dom('tr:first-child th:first-child') + .hasText('firstName Sorteren', 'displays firstName as first header'); + assert + .dom('tr:first-child th:nth-child(2)') + .hasText( + 'lastName Sorteren', + 'displays lastName as second column header', + ); + assert + .dom('tr:first-child th:nth-child(3)') + .hasText('age Sorteren', 'displays age as third column header'); + }); + + test('add selection column header if enabled', async function (assert) { + this.set('data-table', {}); + this.set('data-table.parsedFields', ['firstName', 'lastName', 'age']); + + await render( + hbs`{{au-data-table-content-header data-table=this.data-table enableSelection=true}}`, + ); + + assert.dom('tr').exists({ count: 1 }, 'displays 1 header row'); + assert + .dom('tr:first-child th') + .exists({ count: 4 }, 'displays 4 column headers'); + assert + .dom('tr:first-child th:first-child') + .hasText('', 'displays selection as first header'); + }); + + test('add line number column header if enabled', async function (assert) { + this.set('data-table', {}); + this.set('data-table.parsedFields', ['firstName', 'lastName', 'age']); + + await render( + hbs`{{au-data-table-content-header data-table=this.data-table enableLineNumbers=true}}`, + ); + + assert.dom('tr').exists({ count: 1 }, 'displays 1 header row'); + assert + .dom('tr:first-child th') + .exists({ count: 4 }, 'displays 4 column headers'); + assert + .dom('tr:first-child th:first-child') + .hasText('', 'displays line number as first header'); + }); + }, +); diff --git a/tests/integration/components/au-data-table/au-data-table-menu-general-test.js b/tests/integration/components/au-data-table/au-data-table-menu-general-test.js new file mode 100644 index 000000000..122784d73 --- /dev/null +++ b/tests/integration/components/au-data-table/au-data-table-menu-general-test.js @@ -0,0 +1,44 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module( + 'Integration | Component | au-data-table-menu-general', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + await render(hbs`{{au-data-table-menu-general}}`); + + assert.dom('*').hasText(''); + }); + + test('it renders block only if data table selection is empty', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.set('data-table', { selectionIsEmpty: true }); + // Template block usage: + await render(hbs` + {{#au-data-table-menu-general data-table=this.data-table}} + template block text + {{/au-data-table-menu-general}} + `); + assert.dom('*').hasText('template block text'); + + this.set('data-table', { selectionIsEmpty: false }); + // Template block usage: + await render(hbs` + {{#au-data-table-menu-general data-table=this.data-table}} + template block text + {{/au-data-table-menu-general}} + `); + + assert.dom('*').hasText(''); + }); + }, +); diff --git a/tests/integration/components/au-data-table/au-data-table-menu-selected-test.js b/tests/integration/components/au-data-table/au-data-table-menu-selected-test.js new file mode 100644 index 000000000..df0d73a25 --- /dev/null +++ b/tests/integration/components/au-data-table/au-data-table-menu-selected-test.js @@ -0,0 +1,22 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module( + 'Integration | Component | au-data-table-menu-selected', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders block only if data table selection is not empty', async function (assert) { + this.set('data-table', { selectionIsEmpty: true }); + // Template block usage: + await render(hbs` + {{#au-data-table-menu-selected data-table=this.data-table}} + template block text + {{/au-data-table-menu-selected}} + `); + assert.dom('*').hasText(''); + }); + }, +);