diff --git a/ui/app/components/allocation-row.js b/ui/app/components/allocation-row.js index c6bf62788..415d5f3fe 100644 --- a/ui/app/components/allocation-row.js +++ b/ui/app/components/allocation-row.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import { lazyClick } from '../helpers/lazy-click'; const { Component } = Ember; @@ -15,6 +16,6 @@ export default Component.extend({ onClick() {}, click(event) { - this.get('onClick')(event); + lazyClick([this.get('onClick'), event]); }, }); diff --git a/ui/app/components/client-node-row.js b/ui/app/components/client-node-row.js index ed4c47dfc..e2f9dd19c 100644 --- a/ui/app/components/client-node-row.js +++ b/ui/app/components/client-node-row.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import { lazyClick } from '../helpers/lazy-click'; const { Component } = Ember; @@ -11,7 +12,7 @@ export default Component.extend({ onClick() {}, click(event) { - this.get('onClick')(event); + lazyClick([this.get('onClick'), event]); }, didReceiveAttrs() { diff --git a/ui/app/components/job-row.js b/ui/app/components/job-row.js index 1ac98b43d..024f8d6c1 100644 --- a/ui/app/components/job-row.js +++ b/ui/app/components/job-row.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import { lazyClick } from '../helpers/lazy-click'; const { Component } = Ember; @@ -11,7 +12,7 @@ export default Component.extend({ onClick() {}, click(event) { - this.get('onClick')(event); + lazyClick([this.get('onClick'), event]); }, didReceiveAttrs() { diff --git a/ui/app/components/server-agent-row.js b/ui/app/components/server-agent-row.js index 5fbb6832f..f853ada96 100644 --- a/ui/app/components/server-agent-row.js +++ b/ui/app/components/server-agent-row.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import { lazyClick } from '../helpers/lazy-click'; const { Component, inject, computed } = Ember; @@ -28,6 +29,7 @@ export default Component.extend({ }), click() { - this.get('router').transitionTo('servers.server', this.get('agent')); + const transition = () => this.get('router').transitionTo('servers.server', this.get('agent')); + lazyClick([transition, event]); }, }); diff --git a/ui/app/components/task-group-row.js b/ui/app/components/task-group-row.js index e23541e9c..4fb239637 100644 --- a/ui/app/components/task-group-row.js +++ b/ui/app/components/task-group-row.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import { lazyClick } from '../helpers/lazy-click'; const { Component } = Ember; @@ -12,6 +13,6 @@ export default Component.extend({ onClick() {}, click(event) { - this.get('onClick')(event); + lazyClick([this.get('onClick'), event]); }, }); diff --git a/ui/app/helpers/lazy-click.js b/ui/app/helpers/lazy-click.js new file mode 100644 index 000000000..f9d12dcd2 --- /dev/null +++ b/ui/app/helpers/lazy-click.js @@ -0,0 +1,19 @@ +import Ember from 'ember'; + +const { Helper, $ } = Ember; + +/** + * Lazy Click Event + * + * Usage: {{lazy-click action}} + * + * Calls the provided action only if the target isn't an anchor + * that should be handled instead. + */ +export function lazyClick([onClick, event]) { + if (!$(event.target).is('a')) { + onClick(event); + } +} + +export default Helper.helper(lazyClick); diff --git a/ui/app/templates/nodes/node.hbs b/ui/app/templates/nodes/node.hbs index d44a40eab..0fb81d11e 100644 --- a/ui/app/templates/nodes/node.hbs +++ b/ui/app/templates/nodes/node.hbs @@ -69,7 +69,7 @@ Attributes
- {{attributes-table attributes=model.attributes.attributesStructured}} + {{attributes-table attributes=model.attributes.attributesStructured class="attributes-table"}}
diff --git a/ui/package.json b/ui/package.json index c4f37ed75..66840e74f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -59,6 +59,7 @@ "ember-href-to": "^1.13.0", "ember-load-initializers": "^1.0.0", "ember-moment": "^7.3.1", + "ember-native-dom-helpers": "^0.5.4", "ember-resolver": "^4.0.0", "ember-sinon": "^0.7.0", "ember-source": "~2.14.0", diff --git a/ui/tests/acceptance/allocation-detail-test.js b/ui/tests/acceptance/allocation-detail-test.js index 70d567262..51997cef6 100644 --- a/ui/tests/acceptance/allocation-detail-test.js +++ b/ui/tests/acceptance/allocation-detail-test.js @@ -1,7 +1,11 @@ +import Ember from 'ember'; +import { click, findAll, currentURL, find, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; import moment from 'moment'; +const { $ } = Ember; + let job; let node; let allocation; @@ -23,32 +27,27 @@ moduleForAcceptance('Acceptance | allocation detail', { test('/allocation/:id should name the allocation and link to the corresponding job and node', function( assert ) { + assert.ok(find('h1').textContent.includes(allocation.name), 'Allocation name is in the heading'); + assert.ok(find('h3').textContent.includes(job.name), 'Job name is in the subheading'); assert.ok( - find('h1') - .text() - .includes(allocation.name), - 'Allocation name is in the heading' - ); - assert.ok( - find('h3') - .text() - .includes(job.name), - 'Job name is in the subheading' - ); - assert.ok( - find('h3') - .text() - .includes(node.id.split('-')[0]), + find('h3').textContent.includes(node.id.split('-')[0]), 'Node short id is in the subheading' ); - click('h3 a:eq(0)'); + andThen(() => { + click(findAll('h3 a')[0]); + }); + andThen(() => { assert.equal(currentURL(), `/jobs/${job.id}`, 'Job link navigates to the job'); }); visit(`/allocations/${allocation.id}`); - click('h3 a:eq(1)'); + + andThen(() => { + click(findAll('h3 a')[1]); + }); + andThen(() => { assert.equal(currentURL(), `/nodes/${node.id}`, 'Node link navigates to the node'); }); @@ -56,7 +55,7 @@ test('/allocation/:id should name the allocation and link to the corresponding j test('/allocation/:id should list all tasks for the allocation', function(assert) { assert.equal( - find('.tasks tbody tr').length, + findAll('.tasks tbody tr').length, server.db.taskStates.where({ allocationId: allocation.id }).length, 'Table lists all tasks' ); @@ -68,7 +67,7 @@ test('each task row should list high-level information for the task', function(a .map(id => server.db.taskResources.find(id)) .sortBy('name')[0]; const reservedPorts = taskResources.resources.Networks[0].ReservedPorts; - const taskRow = find('.tasks tbody tr:eq(0)'); + const taskRow = $(findAll('.tasks tbody tr')[0]); const events = server.db.taskEvents.where({ taskStateId: task.id }); const event = events[events.length - 1]; @@ -117,7 +116,7 @@ test('each task row should list high-level information for the task', function(a test('/allocation/:id should list recent events for each task', function(assert) { const tasks = server.db.taskStates.where({ allocationId: allocation.id }); assert.equal( - find('.task-state-events').length, + findAll('.task-state-events').length, tasks.length, 'A task state event block per task' ); @@ -127,7 +126,7 @@ test('each recent events list should include the name, state, and time info for assert ) { const task = server.db.taskStates.where({ allocationId: allocation.id })[0]; - const recentEventsSection = find('.task-state-events:eq(0)'); + const recentEventsSection = $(findAll('.task-state-events')[0]); const heading = recentEventsSection .find('.message-header') .text() @@ -146,7 +145,7 @@ test('each recent events list should list all recent events for the task', funct const events = server.db.taskEvents.where({ taskStateId: task.id }); assert.equal( - find('.task-state-events:eq(0) .task-events tbody tr').length, + findAll('.task-state-events')[0].querySelectorAll('.task-events tbody tr').length, events.length, `Lists ${events.length} events` ); @@ -157,7 +156,7 @@ test('each recent event should list the time, type, and description of the event ) { const task = server.db.taskStates.where({ allocationId: allocation.id })[0]; const event = server.db.taskEvents.where({ taskStateId: task.id })[0]; - const recentEvent = find('.task-state-events:eq(0) .task-events tbody tr:last'); + const recentEvent = $('.task-state-events:eq(0) .task-events tbody tr:last'); assert.equal( recentEvent diff --git a/ui/tests/acceptance/client-detail-test.js b/ui/tests/acceptance/client-detail-test.js index 521f6757c..78a8e66f4 100644 --- a/ui/tests/acceptance/client-detail-test.js +++ b/ui/tests/acceptance/client-detail-test.js @@ -1,6 +1,10 @@ +import Ember from 'ember'; +import { click, find, findAll, currentURL, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; +const { $ } = Ember; + let node; moduleForAcceptance('Acceptance | client detail', { @@ -18,52 +22,45 @@ moduleForAcceptance('Acceptance | client detail', { }); test('/nodes/:id should have a breadrcumb trail linking back to nodes', function(assert) { - assert.equal(find('.breadcrumb:eq(0)').text(), 'Nodes', 'First breadcrumb says nodes'); + assert.equal(findAll('.breadcrumb')[0].textContent, 'Nodes', 'First breadcrumb says nodes'); assert.equal( - find('.breadcrumb:eq(1)').text(), + findAll('.breadcrumb')[1].textContent, node.id.split('-')[0], 'Second breadcrumb says the node short id' ); - click('.breadcrumb:eq(0)'); + click(findAll('.breadcrumb')[0]); andThen(() => { assert.equal(currentURL(), '/nodes', 'First breadcrumb links back to nodes'); }); }); test('/nodes/:id should list immediate details for the node in the title', function(assert) { + assert.ok(find('.title').textContent.includes(node.name), 'Title includes name'); + assert.ok(find('.title').textContent.includes(node.id), 'Title includes id'); assert.ok( - find('.title') - .text() - .includes(node.name), - 'Title includes name' + findAll(`.title .node-status-light.${node.status}`).length, + 'Title includes status light' ); - assert.ok( - find('.title') - .text() - .includes(node.id), - 'Title includes id' - ); - assert.ok(find(`.title .node-status-light.${node.status}`).length, 'Title includes status light'); }); test('/nodes/:id should list additional detail for the node below the title', function(assert) { assert.equal( - find('.inline-definitions .pair:eq(0)').text(), + findAll('.inline-definitions .pair')[0].textContent, `Status ${node.status}`, 'Status is in additional details' ); assert.ok( - find('.inline-definitions .pair:eq(0) .status-text').hasClass(`node-${node.status}`), + $('.inline-definitions .pair:eq(0) .status-text').hasClass(`node-${node.status}`), 'Status is decorated with a status class' ); assert.equal( - find('.inline-definitions .pair:eq(1)').text(), + findAll('.inline-definitions .pair')[1].textContent, `Address ${node.httpAddr}`, 'Address is in additional detals' ); assert.equal( - find('.inline-definitions .pair:eq(2)').text(), + findAll('.inline-definitions .pair')[2].textContent, `Datacenter ${node.datacenter}`, 'Datacenter is in additional details' ); @@ -72,14 +69,14 @@ test('/nodes/:id should list additional detail for the node below the title', fu test('/nodes/:id should list all allocations on the node', function(assert) { const allocationsCount = server.db.allocations.where({ nodeId: node.id }).length; assert.equal( - find('.allocations tbody tr').length, + findAll('.allocations tbody tr').length, allocationsCount, `Allocations table lists all ${allocationsCount} associated allocations` ); }); test('each allocation should have high-level details for the allocation', function(assert) { - const allocationRow = find('.allocations tbody tr:eq(0)'); + const allocationRow = $(findAll('.allocations tbody tr')[0]); const allocation = server.db.allocations .where({ nodeId: node.id }) .sortBy('modifyIndex') @@ -156,7 +153,7 @@ test('each allocation should link to the allocation detail page', function(asser .sortBy('modifyIndex') .reverse()[0]; - click('.allocations tbody tr:eq(0) td:eq(0) a'); + click($('.allocations tbody tr:eq(0) td:eq(0) a').get(0)); andThen(() => { assert.equal( @@ -170,7 +167,7 @@ test('each allocation should link to the allocation detail page', function(asser test('each allocation should link to the job the allocation belongs to', function(assert) { const allocation = server.db.allocations.where({ nodeId: node.id })[0]; const job = server.db.jobs.find(allocation.jobId); - click('.allocations tbody tr:eq(0) td:eq(3) a'); + click($('.allocations tbody tr:eq(0) td:eq(3) a').get(0)); andThen(() => { assert.equal( diff --git a/ui/tests/acceptance/job-definition-test.js b/ui/tests/acceptance/job-definition-test.js index 77496f905..f097ba024 100644 --- a/ui/tests/acceptance/job-definition-test.js +++ b/ui/tests/acceptance/job-definition-test.js @@ -1,9 +1,10 @@ +import { findAll, currentURL, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; let job; -moduleForAcceptance('Acceptance | job detail', { +moduleForAcceptance('Acceptance | job definition', { beforeEach() { server.create('node'); server.create('job'); @@ -17,7 +18,7 @@ test('visiting /jobs/:job_id/definition', function(assert) { }); test('the job definition page contains a json viewer component', function(assert) { - assert.ok(find('.json-viewer').length, 'JSON viewer found'); + assert.ok(findAll('.json-viewer').length, 'JSON viewer found'); }); test('the job definition page requests the job to display in an unmutated form', function(assert) { diff --git a/ui/tests/acceptance/job-deployments-test.js b/ui/tests/acceptance/job-deployments-test.js index 8e46e889b..f69bebea0 100644 --- a/ui/tests/acceptance/job-deployments-test.js +++ b/ui/tests/acceptance/job-deployments-test.js @@ -1,9 +1,10 @@ +import { click, findAll, find, visit } from 'ember-native-dom-helpers'; import Ember from 'ember'; import { test } from 'qunit'; import moment from 'moment'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; -const { get } = Ember; +const { get, $ } = Ember; const sum = (list, key) => list.reduce((sum, item) => sum + get(item, key), 0); let job; @@ -32,7 +33,7 @@ test('/jobs/:id/deployments should list all job deployments', function(assert) { visit(`/jobs/${job.id}/deployments`); andThen(() => { assert.ok( - find('.timeline-object').length, + findAll('.timeline-object').length, deployments.length, 'Each deployment gets a row in the timeline' ); @@ -50,7 +51,7 @@ test('each deployment mentions the deployment shortId, status, version, and time jobId: deployment.jobId, version: deployment.versionNumber, }); - const deploymentRow = find('.timeline-object:eq(0)'); + const deploymentRow = $(findAll('.timeline-object')[0]); assert.ok(deploymentRow.text().includes(deployment.id.split('-')[0]), 'Short ID'); assert.equal(deploymentRow.find('.tag').text(), deployment.status, 'Status'); @@ -89,7 +90,7 @@ test('when the deployment is running and needs promotion, the deployment item sa visit(`/jobs/${job.id}/deployments`); andThen(() => { - const deploymentRow = find('.timeline-object:eq(0)'); + const deploymentRow = $(findAll('.timeline-object')[0]); assert.ok( deploymentRow.find('.badge:contains("Requires Promotion")').length, 'Requires Promotion badge found' @@ -103,11 +104,11 @@ test('each deployment item can be opened to show details', function(assert) { visit(`/jobs/${job.id}/deployments`); andThen(() => { - deploymentRow = find('.timeline-object:eq(0)'); + deploymentRow = $(findAll('.timeline-object')[0]); assert.ok(deploymentRow.find('.boxed-section-body').length === 0, 'No deployment body'); - click(deploymentRow.find('button')); + click(deploymentRow.find('button').get(0)); andThen(() => { assert.ok(deploymentRow.find('.boxed-section-body').length, 'Deployment body found'); @@ -120,18 +121,18 @@ test('when open, a deployment shows the deployment metrics', function(assert) { andThen(() => { const deployment = sortedDeployments.models[0]; - const deploymentRow = find('.timeline-object:eq(0)'); + const deploymentRow = $(findAll('.timeline-object')[0]); const taskGroupSummaries = deployment.deploymentTaskGroupSummaryIds.map(id => server.db.deploymentTaskGroupSummaries.find(id) ); - click(deploymentRow.find('button')); + click(deploymentRow.find('button').get(0)); andThen(() => { assert.equal( - find('.deployment-metrics .label:contains("Canaries") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Canaries") + .value') + .get(0) + .textContent.trim(), `${sum(taskGroupSummaries, 'placedCanaries')} / ${sum( taskGroupSummaries, 'desiredCanaries' @@ -140,41 +141,39 @@ test('when open, a deployment shows the deployment metrics', function(assert) { ); assert.equal( - find('.deployment-metrics .label:contains("Placed") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Placed") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'placedAllocs'), 'Placed allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .label:contains("Desired") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Desired") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'desiredTotal'), 'Desired allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .label:contains("Healthy") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Healthy") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'healthyAllocs'), 'Healthy allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .label:contains("Unhealthy") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Unhealthy") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'unhealthyAllocs'), 'Unhealthy allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .notification') - .text() - .trim(), + find('.deployment-metrics .notification').textContent.trim(), deployment.statusDescription, 'Status description is in the metrics block' ); @@ -189,12 +188,12 @@ test('when open, a deployment shows a list of all task groups and their respecti andThen(() => { const deployment = sortedDeployments.models[0]; - const deploymentRow = find('.timeline-object:eq(0)'); + const deploymentRow = $(findAll('.timeline-object')[0]); const taskGroupSummaries = deployment.deploymentTaskGroupSummaryIds.map(id => server.db.deploymentTaskGroupSummaries.find(id) ); - click(deploymentRow.find('button')); + click(deploymentRow.find('button').get(0)); andThen(() => { assert.ok( @@ -282,13 +281,13 @@ test('when open, a deployment shows a list of all allocations for the deployment andThen(() => { const deployment = sortedDeployments.models[0]; - const deploymentRow = find('.timeline-object:eq(0)'); + const deploymentRow = $(findAll('.timeline-object')[0]); // TODO: Make this less brittle. This logic is copied from the mirage config, // since there is no reference to allocations on the deployment model. const allocations = server.db.allocations.where({ jobId: deployment.jobId }).slice(0, 3); - click(deploymentRow.find('button')); + click(deploymentRow.find('button').get(0)); andThen(() => { assert.ok( diff --git a/ui/tests/acceptance/job-detail-test.js b/ui/tests/acceptance/job-detail-test.js index e9abf8340..ba73c7d10 100644 --- a/ui/tests/acceptance/job-detail-test.js +++ b/ui/tests/acceptance/job-detail-test.js @@ -1,9 +1,10 @@ +import { click, findAll, currentURL, find, visit } from 'ember-native-dom-helpers'; import Ember from 'ember'; import moment from 'moment'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; -const { get } = Ember; +const { get, $ } = Ember; const sum = (list, key) => list.reduce((sum, item) => sum + get(item, key), 0); let job; @@ -22,39 +23,28 @@ test('visiting /jobs/:job_id', function(assert) { }); test('breadcrumbs includes job name and link back to the jobs list', function(assert) { - assert.equal(find('.breadcrumb:eq(0)').text(), 'Jobs', 'First breadcrumb says jobs'); - assert.equal(find('.breadcrumb:eq(1)').text(), job.name, 'Second breadcrumb says the job name'); + assert.equal(findAll('.breadcrumb')[0].textContent, 'Jobs', 'First breadcrumb says jobs'); + assert.equal( + findAll('.breadcrumb')[1].textContent, + job.name, + 'Second breadcrumb says the job name' + ); - click('.breadcrumb:eq(0)'); + click(findAll('.breadcrumb')[0]); andThen(() => { assert.equal(currentURL(), '/jobs', 'First breadcrumb links back to jobs'); }); }); test('the job detail page should contain basic information about the job', function(assert) { - assert.ok( - find('.title .tag:eq(0)') - .text() - .includes(job.status), - 'Status' - ); - assert.ok( - find('.job-stats span:eq(0)') - .text() - .includes(job.type), - 'Type' - ); - assert.ok( - find('.job-stats span:eq(1)') - .text() - .includes(job.priority), - 'Priority' - ); + assert.ok(findAll('.title .tag')[0].textContent.includes(job.status), 'Status'); + assert.ok(findAll('.job-stats span')[0].textContent.includes(job.type), 'Type'); + assert.ok(findAll('.job-stats span')[1].textContent.includes(job.priority), 'Priority'); }); test('the job detail page should list all task groups', function(assert) { assert.equal( - find('.task-group-row').length, + findAll('.task-group-row').length, server.db.taskGroups.where({ jobId: job.id }).length ); }); @@ -63,7 +53,7 @@ test('each row in the task group table should show basic information about the t assert ) { const taskGroup = job.taskGroupIds.map(id => server.db.taskGroups.find(id)).sortBy('name')[0]; - const taskGroupRow = find('.task-group-row:eq(0)'); + const taskGroupRow = $(findAll('.task-group-row')[0]); const tasks = server.db.tasks.where({ taskGroupId: taskGroup.id }); const sum = (list, key) => list.reduce((sum, item) => sum + get(item, key), 0); @@ -104,37 +94,37 @@ test('the allocations diagram lists all allocation status figures', function(ass ); assert.equal( - legend.find('li.queued .value').text(), + legend.querySelector('li.queued .value').textContent, statusCounts.queued, `${statusCounts.queued} are queued` ); assert.equal( - legend.find('li.starting .value').text(), + legend.querySelector('li.starting .value').textContent, statusCounts.starting, `${statusCounts.starting} are starting` ); assert.equal( - legend.find('li.running .value').text(), + legend.querySelector('li.running .value').textContent, statusCounts.running, `${statusCounts.running} are running` ); assert.equal( - legend.find('li.complete .value').text(), + legend.querySelector('li.complete .value').textContent, statusCounts.complete, `${statusCounts.complete} are complete` ); assert.equal( - legend.find('li.failed .value').text(), + legend.querySelector('li.failed .value').textContent, statusCounts.failed, `${statusCounts.failed} are failed` ); assert.equal( - legend.find('li.lost .value').text(), + legend.querySelector('li.lost .value').textContent, statusCounts.lost, `${statusCounts.lost} are lost` ); @@ -149,7 +139,7 @@ test('there is no active deployment section when the job has no active deploymen visit(`/jobs/${job.id}`); andThen(() => { - assert.ok(find('.active-deployment').length === 0, 'No active deployment'); + assert.ok(findAll('.active-deployment').length === 0, 'No active deployment'); }); }); @@ -168,27 +158,27 @@ test('the active deployment section shows up for the currently running deploymen visit(`/jobs/${job.id}`); andThen(() => { - assert.ok(find('.active-deployment').length === 1, 'Active deployment'); + assert.ok(findAll('.active-deployment').length === 1, 'Active deployment'); assert.equal( - find('.active-deployment > .boxed-section-head .badge') - .text() - .trim(), + $('.active-deployment > .boxed-section-head .badge') + .get(0) + .textContent.trim(), deployment.id.split('-')[0], 'The active deployment is the most recent running deployment' ); assert.equal( - find('.active-deployment > .boxed-section-head .submit-time') - .text() - .trim(), + $('.active-deployment > .boxed-section-head .submit-time') + .get(0) + .textContent.trim(), moment(version.submitTime / 1000000).fromNow(), 'Time since the job was submitted is in the active deployment header' ); assert.equal( - find('.deployment-metrics .label:contains("Canaries") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Canaries") + .value') + .get(0) + .textContent.trim(), `${sum(taskGroupSummaries, 'placedCanaries')} / ${sum( taskGroupSummaries, 'desiredCanaries' @@ -197,41 +187,41 @@ test('the active deployment section shows up for the currently running deploymen ); assert.equal( - find('.deployment-metrics .label:contains("Placed") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Placed") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'placedAllocs'), 'Placed allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .label:contains("Desired") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Desired") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'desiredTotal'), 'Desired allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .label:contains("Healthy") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Healthy") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'healthyAllocs'), 'Healthy allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .label:contains("Unhealthy") + .value') - .text() - .trim(), + $('.deployment-metrics .label:contains("Unhealthy") + .value') + .get(0) + .textContent.trim(), sum(taskGroupSummaries, 'unhealthyAllocs'), 'Unhealthy allocs aggregates across task groups' ); assert.equal( - find('.deployment-metrics .notification') - .text() - .trim(), + $('.deployment-metrics .notification') + .get(0) + .textContent.trim(), deployment.statusDescription, 'Status description is in the metrics block' ); @@ -246,24 +236,26 @@ test('the active deployment section can be expanded to show task groups and allo andThen(() => { assert.ok( - find('.active-deployment .boxed-section-head:contains("Task Groups")').length === 0, + $('.active-deployment .boxed-section-head:contains("Task Groups")').length === 0, 'Task groups not found' ); assert.ok( - find('.active-deployment .boxed-section-head:contains("Allocations")').length === 0, + $('.active-deployment .boxed-section-head:contains("Allocations")').length === 0, 'Allocations not found' ); }); - click('.active-deployment-details-toggle'); + andThen(() => { + click('.active-deployment-details-toggle'); + }); andThen(() => { assert.ok( - find('.active-deployment .boxed-section-head:contains("Task Groups")').length === 1, + $('.active-deployment .boxed-section-head:contains("Task Groups")').length === 1, 'Task groups found' ); assert.ok( - find('.active-deployment .boxed-section-head:contains("Allocations")').length === 1, + $('.active-deployment .boxed-section-head:contains("Allocations")').length === 1, 'Allocations found' ); }); diff --git a/ui/tests/acceptance/job-versions-test.js b/ui/tests/acceptance/job-versions-test.js index 0843243ea..578eb28bf 100644 --- a/ui/tests/acceptance/job-versions-test.js +++ b/ui/tests/acceptance/job-versions-test.js @@ -1,7 +1,11 @@ +import Ember from 'ember'; +import { findAll, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; import moment from 'moment'; +const { $ } = Ember; + let job; let versions; @@ -16,7 +20,7 @@ moduleForAcceptance('Acceptance | job versions', { test('/jobs/:id/versions should list all job versions', function(assert) { assert.ok( - find('.timeline-object').length, + findAll('.timeline-object').length, versions.length, 'Each version gets a row in the timeline' ); @@ -26,7 +30,7 @@ test('each version mentions the version number, the stability, and the submitted assert ) { const version = versions.sortBy('submitTime').reverse()[0]; - const versionRow = find('.timeline-object:eq(0)'); + const versionRow = $(findAll('.timeline-object')[0]); assert.ok(versionRow.text().includes(`Version #${version.version}`), 'Version #'); assert.equal( diff --git a/ui/tests/acceptance/jobs-list-test.js b/ui/tests/acceptance/jobs-list-test.js index 61f9a070a..699739fe4 100644 --- a/ui/tests/acceptance/jobs-list-test.js +++ b/ui/tests/acceptance/jobs-list-test.js @@ -1,6 +1,10 @@ +import Ember from 'ember'; +import { click, findAll, currentURL, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; +const { $ } = Ember; + moduleForAcceptance('Acceptance | jobs list', { beforeEach() { // Required for placing allocations (a result of creating jobs) @@ -25,10 +29,10 @@ test('/jobs should list the first page of jobs sorted by modify index', function andThen(() => { const sortedJobs = server.db.jobs.sortBy('modifyIndex').reverse(); - assert.equal(find('.job-row').length, pageSize); + assert.equal(findAll('.job-row').length, pageSize); for (var jobNumber = 0; jobNumber < pageSize; jobNumber++) { assert.equal( - find(`.job-row:eq(${jobNumber}) td:eq(0)`).text(), + $(`.job-row:eq(${jobNumber}) td:eq(0)`).text(), sortedJobs[jobNumber].name, 'Jobs are ordered' ); @@ -44,11 +48,18 @@ test('each job row should contain information about the job', function(assert) { visit('/jobs'); andThen(() => { - const jobRow = find('.job-row:eq(0)'); + const jobRow = $(findAll('.job-row')[0]); assert.equal(jobRow.find('td:eq(0)').text(), job.name, 'Name'); assert.equal(jobRow.find('td:eq(0) a').attr('href'), `/ui/jobs/${job.id}`, 'Detail Link'); - assert.equal(jobRow.find('td:eq(1)').text().trim(), job.status, 'Status'); + assert.equal( + jobRow + .find('td:eq(1)') + .text() + .trim(), + job.status, + 'Status' + ); assert.equal(jobRow.find('td:eq(2)').text(), job.type, 'Type'); assert.equal(jobRow.find('td:eq(3)').text(), job.priority, 'Priority'); assert.equal(jobRow.find('td:eq(4)').text(), taskGroups.length, '# Groups'); @@ -60,7 +71,10 @@ test('each job row should link to the corresponding job', function(assert) { const job = server.db.jobs[0]; visit('/jobs'); - click('.job-row:eq(0) td:eq(0) a'); + + andThen(() => { + click($('.job-row:eq(0) td:eq(0) a').get(0)); + }); andThen(() => { assert.equal(currentURL(), `/jobs/${job.id}`); diff --git a/ui/tests/acceptance/nodes-list-test.js b/ui/tests/acceptance/nodes-list-test.js index 2b506aab6..4a6ee0301 100644 --- a/ui/tests/acceptance/nodes-list-test.js +++ b/ui/tests/acceptance/nodes-list-test.js @@ -1,8 +1,12 @@ +import Ember from 'ember'; +import { click, findAll, currentURL, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; import { findLeader } from '../../mirage/config'; import ipParts from 'nomad-ui/utils/ip-parts'; +const { $ } = Ember; + function minimumSetup() { server.createList('node', 1); server.createList('agent', 1); @@ -21,14 +25,14 @@ test('/nodes should list one page of clients', function(assert) { visit('/nodes'); andThen(() => { - assert.equal(find('.client-node-row').length, pageSize); - assert.ok(find('.pagination').length, 'Pagination found on the page'); + assert.equal(findAll('.client-node-row').length, pageSize); + assert.ok(findAll('.pagination').length, 'Pagination found on the page'); const sortedNodes = server.db.nodes.sortBy('modifyIndex').reverse(); for (var nodeNumber = 0; nodeNumber < pageSize; nodeNumber++) { assert.equal( - find(`.client-node-row:eq(${nodeNumber}) td:eq(0)`).text(), + $(`.client-node-row:eq(${nodeNumber}) td:eq(0)`).text(), sortedNodes[nodeNumber].id.split('-')[0], 'Nodes are ordered' ); @@ -43,7 +47,7 @@ test('each client record should show high-level info of the client', function(as visit('/nodes'); andThen(() => { - const nodeRow = find('.client-node-row:eq(0)'); + const nodeRow = $(findAll('.client-node-row')[0]); const allocations = server.db.allocations.where({ nodeId: node.id }); const { address, port } = ipParts(node.httpAddr); @@ -62,7 +66,9 @@ test('each client should link to the client detail page', function(assert) { const node = server.db.nodes[0]; visit('/nodes'); - click('.client-node-row:eq(0)'); + andThen(() => { + click(findAll('.client-node-row')[0]); + }); andThen(() => { assert.equal(currentURL(), `/nodes/${node.id}`); @@ -81,7 +87,7 @@ test('/servers should list all servers', function(assert) { visit('/servers'); andThen(() => { - assert.equal(find('.server-agent-row').length, pageSize); + assert.equal(findAll('.server-agent-row').length, pageSize); const sortedAgents = server.db.agents .sort((a, b) => { @@ -96,7 +102,7 @@ test('/servers should list all servers', function(assert) { for (var agentNumber = 0; agentNumber < 8; agentNumber++) { assert.equal( - find(`.server-agent-row:eq(${agentNumber}) td:eq(0)`).text(), + $(`.server-agent-row:eq(${agentNumber}) td:eq(0)`).text(), sortedAgents[agentNumber].name, 'Clients are ordered' ); @@ -111,7 +117,7 @@ test('each server should show high-level info of the server', function(assert) { visit('/servers'); andThen(() => { - const agentRow = find('.server-agent-row:eq(0)'); + const agentRow = $(findAll('.server-agent-row')[0]); assert.equal(agentRow.find('td:eq(0)').text(), agent.name, 'Name'); assert.equal(agentRow.find('td:eq(1)').text(), agent.status, 'Status'); @@ -127,7 +133,9 @@ test('each server should link to the server detail page', function(assert) { const agent = server.db.agents[0]; visit('/servers'); - click('.server-agent-row:eq(0)'); + andThen(() => { + click(findAll('.server-agent-row')[0]); + }); andThen(() => { assert.equal(currentURL(), `/servers/${agent.name}`); diff --git a/ui/tests/acceptance/server-detail-test.js b/ui/tests/acceptance/server-detail-test.js index 164a0449a..4b4af6673 100644 --- a/ui/tests/acceptance/server-detail-test.js +++ b/ui/tests/acceptance/server-detail-test.js @@ -1,6 +1,10 @@ +import Ember from 'ember'; +import { findAll, currentURL, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; +const { $ } = Ember; + let agent; moduleForAcceptance('Acceptance | server detail', { @@ -18,22 +22,22 @@ test('visiting /servers/:server_name', function(assert) { test('the server detail page should list all tags for the server', function(assert) { const tags = agent.tags; - assert.equal(find('.server-tags tbody tr').length, Object.keys(tags).length, '# of tags'); + assert.equal(findAll('.server-tags tbody tr').length, Object.keys(tags).length, '# of tags'); Object.keys(tags).forEach((key, index) => { - const row = find(`.server-tags tbody tr:eq(${index})`); + const row = $(`.server-tags tbody tr:eq(${index})`); assert.equal(row.find('td:eq(0)').text(), key, `Label: ${key}`); assert.equal(row.find('td:eq(1)').text(), tags[key], `Value: ${tags[key]}`); }); }); test('the list of servers from /servers should still be present', function(assert) { - assert.equal(find('.server-agent-row').length, server.db.agents.length, '# of servers'); + assert.equal(findAll('.server-agent-row').length, server.db.agents.length, '# of servers'); }); test('the active server should be denoted in the table', function(assert) { - assert.equal(find('.server-agent-row.is-active').length, 1, 'Only one active server'); + assert.equal(findAll('.server-agent-row.is-active').length, 1, 'Only one active server'); assert.equal( - find('.server-agent-row.is-active td:eq(0)').text(), + findAll('.server-agent-row.is-active td')[0].textContent, agent.name, 'Active server matches current route' ); diff --git a/ui/tests/acceptance/task-group-detail-test.js b/ui/tests/acceptance/task-group-detail-test.js index 41b03aa1d..800e57544 100644 --- a/ui/tests/acceptance/task-group-detail-test.js +++ b/ui/tests/acceptance/task-group-detail-test.js @@ -1,6 +1,10 @@ +import Ember from 'ember'; +import { click, findAll, currentURL, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; +const { $ } = Ember; + let job; let taskGroup; let tasks; @@ -10,6 +14,7 @@ const sum = (total, n) => total + n; moduleForAcceptance('Acceptance | task group detail', { beforeEach() { + server.create('agent'); server.create('node', 'forceIPv4'); job = server.create('job', { @@ -46,39 +51,43 @@ test('/jobs/:id/:task-group should list high-level metrics for the allocation', const totalDisk = taskGroup.ephemeralDisk.SizeMB; assert.equal( - find('.inline-definitions .pair:eq(0)').text(), + findAll('.inline-definitions .pair')[0].textContent, `# Tasks ${tasks.length}`, '# Tasks' ); assert.equal( - find('.inline-definitions .pair:eq(1)').text(), + findAll('.inline-definitions .pair')[1].textContent, `Reserved CPU ${totalCPU} MHz`, 'Aggregated CPU reservation for all tasks' ); assert.equal( - find('.inline-definitions .pair:eq(2)').text(), + findAll('.inline-definitions .pair')[2].textContent, `Reserved Memory ${totalMemory} MiB`, 'Aggregated Memory reservation for all tasks' ); assert.equal( - find('.inline-definitions .pair:eq(3)').text(), + findAll('.inline-definitions .pair')[3].textContent, `Reserved Disk ${totalDisk} MiB`, 'Aggregated Disk reservation for all tasks' ); }); test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', function(assert) { - assert.equal(find('.breadcrumb:eq(0)').text(), 'Jobs', 'First breadcrumb says jobs'); - assert.equal(find('.breadcrumb:eq(1)').text(), job.name, 'Second breadcrumb says the job name'); + assert.equal(findAll('.breadcrumb')[0].textContent, 'Jobs', 'First breadcrumb says jobs'); assert.equal( - find('.breadcrumb:eq(2)').text(), + findAll('.breadcrumb')[1].textContent, + job.name, + 'Second breadcrumb says the job name' + ); + assert.equal( + findAll('.breadcrumb')[2].textContent, taskGroup.name, 'Third breadcrumb says the job name' ); }); test('/jobs/:id/:task-group first breadcrumb should link to jobs', function(assert) { - click('.breadcrumb:eq(0)'); + click(findAll('.breadcrumb')[0]); andThen(() => { assert.equal(currentURL(), '/jobs', 'First breadcrumb links back to jobs'); }); @@ -87,7 +96,7 @@ test('/jobs/:id/:task-group first breadcrumb should link to jobs', function(asse test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', function( assert ) { - click('.breadcrumb:eq(1)'); + click(findAll('.breadcrumb')[1]); andThen(() => { assert.equal( currentURL(), @@ -117,7 +126,7 @@ test('/jobs/:id/:task-group should list one page of allocations for the task gro ); assert.equal( - find('.allocations tbody tr').length, + findAll('.allocations tbody tr').length, pageSize, 'All allocations for the task group' ); @@ -126,7 +135,7 @@ test('/jobs/:id/:task-group should list one page of allocations for the task gro test('each allocation should show basic information about the allocation', function(assert) { const allocation = allocations.sortBy('name')[0]; - const allocationRow = find('.allocations tbody tr:eq(0)'); + const allocationRow = $(findAll('.allocations tbody tr')[0]); assert.equal( allocationRow @@ -158,15 +167,21 @@ test('each allocation should show basic information about the allocation', funct .text() .trim(), server.db.nodes.find(allocation.nodeId).id.split('-')[0], - 'Node name' + 'Node ID' ); + + click(allocationRow.find('td:eq(3) a').get(0)); + + andThen(() => { + assert.equal(currentURL(), `/nodes/${allocation.nodeId}`, 'Node links to node page'); + }); }); test('each allocation should show stats about the allocation, retrieved directly from the node', function( assert ) { const allocation = allocations.sortBy('name')[0]; - const allocationRow = find('.allocations tbody tr:eq(0)'); + const allocationRow = $(findAll('.allocations tbody tr')[0]); const allocStats = server.db.clientAllocationStats.find(allocation.id); const tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id)); diff --git a/ui/tests/acceptance/token-test.js b/ui/tests/acceptance/token-test.js index 9c176a4e3..e4c6f2a5d 100644 --- a/ui/tests/acceptance/token-test.js +++ b/ui/tests/acceptance/token-test.js @@ -1,3 +1,4 @@ +import { fillIn, visit } from 'ember-native-dom-helpers'; import { test } from 'qunit'; import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; @@ -22,14 +23,18 @@ test('the token form sets the token in session storage', function(assert) { assert.ok(window.sessionStorage.nomadTokenSecret == null, 'No token secret set'); assert.ok(window.sessionStorage.nomadTokenAccessor == null, 'No token accessor set'); - fillIn('.token-secret', secret); + andThen(() => { + fillIn('.token-secret', secret); + }); andThen(() => { assert.equal(window.sessionStorage.nomadTokenSecret, secret, 'Token secret was set'); assert.ok(window.sessionStorage.nomadTokenAccessor == null, 'Token accessor was not set'); }); - fillIn('.token-accessor', accessor); + andThen(() => { + fillIn('.token-accessor', accessor); + }); andThen(() => { assert.equal(window.sessionStorage.nomadTokenAccessor, accessor, 'Token accessor was set'); @@ -55,7 +60,9 @@ test('the X-Nomad-Token header gets sent with requests once it is set', function }); visit('/settings/tokens'); - fillIn('.token-secret', secret); + andThen(() => { + fillIn('.token-secret', secret); + }); visit(`/jobs/${job.id}`); visit(`/nodes/${node.id}`); diff --git a/ui/tests/integration/attributes-table-test.js b/ui/tests/integration/attributes-table-test.js index 384f7dc92..3147ff638 100644 --- a/ui/tests/integration/attributes-table-test.js +++ b/ui/tests/integration/attributes-table-test.js @@ -1,3 +1,4 @@ +import { findAll } from 'ember-native-dom-helpers'; import { test, moduleForComponent } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; import flat from 'npm:flat'; @@ -42,23 +43,39 @@ test('should render the full path of key/value pair from the root of the object' this.render(hbs`{{attributes-table attributes=attributes}}`); assert.equal( - this.$('tbody tr:eq(0) td:eq(0)').text().trim(), + this.$('tbody tr:eq(0) td') + .get(0) + .textContent.trim(), 'key', 'Simple row renders only the key' ); - assert.equal(this.$('tbody tr:eq(0) td:eq(1)').text().trim(), 'value'); + assert.equal( + this.$('tbody tr:eq(0) td') + .get(1) + .textContent.trim(), + 'value' + ); assert.equal( - this.$('tbody tr:eq(8) td:eq(0)').text().trim(), + this.$('tbody tr:eq(8) td') + .get(0) + .textContent.trim(), 'so.are.deeply.nested', 'Complex row renders the full path to the key' ); assert.equal( - this.$('tbody tr:eq(8) td:eq(0) .is-faded').text().trim(), + this.$('tbody tr:eq(8) td:eq(0) .is-faded') + .get(0) + .textContent.trim(), 'so.are.deeply.', 'The prefix is faded to put emphasis on the attribute' ); - assert.equal(this.$('tbody tr:eq(8) td:eq(1)').text().trim(), 'properties'); + assert.equal( + this.$('tbody tr:eq(8) td') + .get(1) + .textContent.trim(), + 'properties' + ); }); test('should render a row for key/value pairs even when the value is another object', function( @@ -69,7 +86,7 @@ test('should render a row for key/value pairs even when the value is another obj const countOfParentRows = countOfParentKeys(commonAttributes); assert.equal( - this.$('tbody tr td[colspan="2"]').length, + findAll('tbody tr td[colspan="2"]').length, countOfParentRows, 'Each key for a nested object gets a row with no value' ); diff --git a/ui/tests/integration/job-diff-test.js b/ui/tests/integration/job-diff-test.js index 77d88e6d9..087cbbd9f 100644 --- a/ui/tests/integration/job-diff-test.js +++ b/ui/tests/integration/job-diff-test.js @@ -1,3 +1,4 @@ +import { findAll, find } from 'ember-native-dom-helpers'; import { test, moduleForComponent } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; @@ -28,22 +29,22 @@ test('job field diffs', function(assert) { this.render(commonTemplate); assert.equal( - this.$('.diff-section-label').length, + findAll('.diff-section-label').length, 5, 'A section label for each line, plus one for the group' ); assert.equal( - cleanWhitespace(this.$('.diff-section-label .diff-section-label.is-added').text()), + cleanWhitespace(find('.diff-section-label .diff-section-label.is-added').textContent), '+ Added Field: "Foobar"', 'Added field is rendered correctly' ); assert.equal( - cleanWhitespace(this.$('.diff-section-label .diff-section-label.is-edited').text()), + cleanWhitespace(find('.diff-section-label .diff-section-label.is-edited').textContent), '+/- Edited Field: "256" => "512"', 'Edited field is rendered correctly' ); assert.equal( - cleanWhitespace(this.$('.diff-section-label .diff-section-label.is-deleted').text()), + cleanWhitespace(find('.diff-section-label .diff-section-label.is-deleted').textContent), '- Removed Field: "12"', 'Removed field is rendered correctly' ); @@ -96,51 +97,51 @@ test('job object diffs', function(assert) { this.render(commonTemplate); assert.ok( - cleanWhitespace(this.$('.diff-section-label > .diff-section-label.is-added').text()).startsWith( - '+ DeepConfiguration {' - ), + cleanWhitespace( + find('.diff-section-label > .diff-section-label.is-added').textContent + ).startsWith('+ DeepConfiguration {'), 'Added object starts with a JSON block' ); assert.ok( cleanWhitespace( - this.$('.diff-section-label > .diff-section-label.is-edited').text() + find('.diff-section-label > .diff-section-label.is-edited').textContent ).startsWith('+/- ComplexProperty {'), 'Edited object starts with a JSON block' ); assert.ok( cleanWhitespace( - this.$('.diff-section-label > .diff-section-label.is-deleted').text() + find('.diff-section-label > .diff-section-label.is-deleted').textContent ).startsWith('- DatedStuff {'), 'Removed object starts with a JSON block' ); assert.ok( - cleanWhitespace(this.$('.diff-section-label > .diff-section-label.is-added').text()).endsWith( - '}' - ), + cleanWhitespace( + find('.diff-section-label > .diff-section-label.is-added').textContent + ).endsWith('}'), 'Added object ends the JSON block' ); assert.ok( - cleanWhitespace(this.$('.diff-section-label > .diff-section-label.is-edited').text()).endsWith( - '}' - ), + cleanWhitespace( + find('.diff-section-label > .diff-section-label.is-edited').textContent + ).endsWith('}'), 'Edited object starts with a JSON block' ); assert.ok( - cleanWhitespace(this.$('.diff-section-label > .diff-section-label.is-deleted').text()).endsWith( - '}' - ), + cleanWhitespace( + find('.diff-section-label > .diff-section-label.is-deleted').textContent + ).endsWith('}'), 'Removed object ends the JSON block' ); assert.equal( - this.$('.diff-section-label > .diff-section-label.is-added > .diff-section-label').length, + findAll('.diff-section-label > .diff-section-label.is-added > .diff-section-label').length, this.get('diff').Objects[1].Objects.length + this.get('diff').Objects[1].Fields.length, 'Edited block contains each nested field and object' ); assert.equal( - this.$( + findAll( '.diff-section-label > .diff-section-label.is-added > .diff-section-label > .diff-section-label .diff-section-table-row' ).length, this.get('diff').Objects[1].Objects[0].Fields.length, diff --git a/ui/tests/integration/list-pagination-test.js b/ui/tests/integration/list-pagination-test.js index 6e1c40529..a3091d62a 100644 --- a/ui/tests/integration/list-pagination-test.js +++ b/ui/tests/integration/list-pagination-test.js @@ -1,3 +1,4 @@ +import { findAll, find } from 'ember-native-dom-helpers'; import { test, skip, moduleForComponent } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; @@ -12,7 +13,9 @@ const defaults = { spread: 2, }; -const list100 = Array(100).fill(null).map((_, i) => i); +const list100 = Array(100) + .fill(null) + .map((_, i) => i); test('the source property', function(assert) { this.set('source', list100); @@ -33,31 +36,31 @@ test('the source property', function(assert) { {{/list-pagination}} `); - assert.ok(!this.$('.first').length, 'On the first page, there is no first link'); - assert.ok(!this.$('.prev').length, 'On the first page, there is no prev link'); + assert.ok(!findAll('.first').length, 'On the first page, there is no first link'); + assert.ok(!findAll('.prev').length, 'On the first page, there is no prev link'); assert.equal( - this.$('.link').length, + findAll('.link').length, defaults.spread + 1, 'Pages links spread to the right by the spread amount' ); for (var pageNumber = 1; pageNumber <= defaults.spread + 1; pageNumber++) { - assert.ok(this.$(`.link.page-${pageNumber}`).length, `Page link includes ${pageNumber}`); + assert.ok(findAll(`.link.page-${pageNumber}`).length, `Page link includes ${pageNumber}`); } - assert.ok(this.$('.next').length, 'While not on the last page, there is a next link'); - assert.ok(this.$('.last').length, 'While not on the last page, there is a last link'); + assert.ok(findAll('.next').length, 'While not on the last page, there is a next link'); + assert.ok(findAll('.last').length, 'While not on the last page, there is a last link'); assert.ok( - this.$('.item').length, + findAll('.item').length, defaults.size, `Only ${defaults.size} (the default) number of items are rendered` ); for (var item = 0; item < defaults.size; item++) { assert.equal( - this.$(`.item:eq(${item})`).text(), + findAll('.item')[item].textContent, item, 'Rendered items are in the current page' ); @@ -76,7 +79,7 @@ test('the size property', function(assert) { `); const totalPages = Math.ceil(this.get('source').length / this.get('size')); - assert.equal(this.$('.page-info').text(), `1 of ${totalPages}`, `${totalPages} total pages`); + assert.equal(find('.page-info').textContent, `1 of ${totalPages}`, `${totalPages} total pages`); }); test('the spread property', function(assert) { @@ -144,14 +147,14 @@ test('there are no pagination links when source is less than page size', functio {{/list-pagination}} `); - assert.ok(!this.$('.first').length, 'No first link'); - assert.ok(!this.$('.prev').length, 'No prev link'); - assert.ok(!this.$('.next').length, 'No next link'); - assert.ok(!this.$('.last').length, 'No last link'); + assert.ok(!findAll('.first').length, 'No first link'); + assert.ok(!findAll('.prev').length, 'No prev link'); + assert.ok(!findAll('.next').length, 'No next link'); + assert.ok(!findAll('.last').length, 'No last link'); - assert.equal(this.$('.page-info').text(), '1 of 1', 'Only one page'); + assert.equal(find('.page-info').textContent, '1 of 1', 'Only one page'); assert.equal( - this.$('.item').length, + findAll('.item').length, this.get('source.length'), 'Number of items equals length of source' ); @@ -180,10 +183,10 @@ test('when there are no items in source', function(assert) { `); assert.ok( - !this.$('.page-info, .first, .prev, .link, .next, .last, .item').length, + !findAll('.page-info, .first, .prev, .link, .next, .last, .item').length, 'Nothing in the yield renders' ); - assert.ok(this.$('.empty-state').length, 'Empty state is rendered'); + assert.ok(findAll('.empty-state').length, 'Empty state is rendered'); }); // when there is less pages than the total spread amount @@ -210,13 +213,13 @@ test('when there is less pages than the total spread amount', function(assert) { {{/list-pagination}} `); - assert.ok(this.$('.first').length, 'First page still exists'); - assert.ok(this.$('.prev').length, 'Prev page still exists'); - assert.ok(this.$('.next').length, 'Next page still exists'); - assert.ok(this.$('.last').length, 'Last page still exists'); - assert.equal(this.$('.link').length, totalPages, 'Every page gets a page link'); + assert.ok(findAll('.first').length, 'First page still exists'); + assert.ok(findAll('.prev').length, 'Prev page still exists'); + assert.ok(findAll('.next').length, 'Next page still exists'); + assert.ok(findAll('.last').length, 'Last page still exists'); + assert.equal(findAll('.link').length, totalPages, 'Every page gets a page link'); for (var pageNumber = 1; pageNumber < totalPages; pageNumber++) { - assert.ok(this.$(`.link.page-${pageNumber}`).length, `Page link for ${pageNumber} exists`); + assert.ok(findAll(`.link.page-${pageNumber}`).length, `Page link for ${pageNumber} exists`); } }); @@ -224,7 +227,7 @@ function testSpread(assert) { const { spread, currentPage } = this.getProperties('spread', 'currentPage'); for (var pageNumber = currentPage - spread; pageNumber <= currentPage + spread; pageNumber++) { assert.ok( - this.$(`.link.page-${pageNumber}`).length, + findAll(`.link.page-${pageNumber}`).length, `Page links for currentPage (${currentPage}) +/- spread of ${spread} (${pageNumber})` ); } @@ -234,7 +237,7 @@ function testItems(assert) { const { currentPage, size } = this.getProperties('currentPage', 'size'); for (var item = 0; item < size; item++) { assert.equal( - this.$(`.item:eq(${item})`).text(), + findAll('.item')[item].textContent, item + (currentPage - 1) * size, `Rendered items are in the current page, ${currentPage} (${item + (currentPage - 1) * size})` ); diff --git a/ui/tests/integration/list-table-test.js b/ui/tests/integration/list-table-test.js index a9c688035..d399f87f8 100644 --- a/ui/tests/integration/list-table-test.js +++ b/ui/tests/integration/list-table-test.js @@ -1,3 +1,4 @@ +import { findAll, find } from 'ember-native-dom-helpers'; import { test, skip, moduleForComponent } from 'ember-qunit'; import { faker } from 'ember-cli-mirage'; import hbs from 'htmlbars-inline-precompile'; @@ -6,11 +7,13 @@ moduleForComponent('list-table', 'Integration | Component | list table', { integration: true, }); -const commonTable = Array(10).fill(null).map(() => ({ - firstName: faker.name.firstName(), - lastName: faker.name.lastName(), - age: faker.random.number({ min: 18, max: 60 }), -})); +const commonTable = Array(10) + .fill(null) + .map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + age: faker.random.number({ min: 18, max: 60 }), + })); // thead test('component exposes a thead contextual component', function(assert) { @@ -25,12 +28,8 @@ test('component exposes a thead contextual component', function(assert) { {{/list-table}} `); - assert.ok(this.$('.head').length, 'Table head is rendered'); - assert.equal( - this.$('.head').prop('tagName').toLowerCase(), - 'thead', - 'Table head is a thead element' - ); + assert.ok(findAll('.head').length, 'Table head is rendered'); + assert.equal(find('.head').tagName.toLowerCase(), 'thead', 'Table head is a thead element'); }); // tbody @@ -52,22 +51,39 @@ test('component exposes a tbody contextual component', function(assert) { {{/list-table}} `); - assert.ok(this.$('.body').length, 'Table body is rendered'); - assert.equal( - this.$('.body').prop('tagName').toLowerCase(), - 'tbody', - 'Table body is a tbody element' - ); + assert.ok(findAll('.body').length, 'Table body is rendered'); + assert.equal(find('.body').tagName.toLowerCase(), 'tbody', 'Table body is a tbody element'); - assert.equal(this.$('.item').length, this.get('source.length'), 'Each item gets its own row'); + assert.equal(findAll('.item').length, this.get('source.length'), 'Each item gets its own row'); // list-table is not responsible for sorting, only dispatching sort events. The table is still // rendered in index-order. this.get('source').forEach((item, index) => { const $item = this.$(`.item:eq(${index})`); - assert.equal($item.find('td:eq(0)').text().trim(), item.firstName, 'First name'); - assert.equal($item.find('td:eq(1)').text().trim(), item.lastName, 'Last name'); - assert.equal($item.find('td:eq(2)').text().trim(), item.age, 'Age'); + assert.equal( + $item + .find('td:eq(0)') + .text() + .trim(), + item.firstName, + 'First name' + ); + assert.equal( + $item + .find('td:eq(1)') + .text() + .trim(), + item.lastName, + 'Last name' + ); + assert.equal( + $item + .find('td:eq(2)') + .text() + .trim(), + item.age, + 'Age' + ); }); }); diff --git a/ui/yarn.lock b/ui/yarn.lock index 84ee0a99e..cb724121b 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -3103,6 +3103,13 @@ ember-moment@^7.3.1: ember-getowner-polyfill "^2.0.1" ember-macro-helpers "^0.15.1" +ember-native-dom-helpers@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/ember-native-dom-helpers/-/ember-native-dom-helpers-0.5.4.tgz#0bc1506a643fb7adc0abf1d09c44a7914459296b" + dependencies: + broccoli-funnel "^1.1.0" + ember-cli-babel "^6.6.0" + ember-qunit@^2.1.3: version "2.2.0" resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-2.2.0.tgz#3cdf400031c93a38de781a7304819738753b7f99"