UI: Remove ember-native-dom-helpers (#5959)

This also includes migration of some tests to async.
This commit is contained in:
Buck Doyle 2019-07-23 14:40:32 -05:00 committed by GitHub
parent cc20b3169c
commit 354b4c830f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 969 additions and 1478 deletions

View file

@ -75,7 +75,6 @@
"ember-load-initializers": "^1.1.0",
"ember-maybe-import-regenerator": "^0.1.6",
"ember-moment": "^7.8.1",
"ember-native-dom-helpers": "^0.5.4",
"ember-page-title": "^5.0.2",
"ember-power-select": "^2.2.3",
"ember-qunit-nice-errors": "^1.2.0",

View file

@ -1,4 +1,4 @@
import { find } from 'ember-native-dom-helpers';
import { find } from '@ember/test-helpers';
import { module, skip, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';

View file

@ -1,13 +1,11 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import generateResources from '../../mirage/data/generate-resources';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import { find } from 'ember-native-dom-helpers';
import { find, render } from '@ember/test-helpers';
import Response from 'ember-cli-mirage/response';
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
import { Promise, resolve } from 'rsvp';
module('Integration | Component | allocation row', function(hooks) {
setupRenderingTest(hooks);
@ -25,7 +23,7 @@ module('Integration | Component | allocation row', function(hooks) {
this.server.shutdown();
});
test('Allocation row polls for stats, even when it errors or has an invalid response', function(assert) {
test('Allocation row polls for stats, even when it errors or has an invalid response', async function(assert) {
const component = this;
let currentFrame = 0;
@ -52,13 +50,9 @@ module('Integration | Component | allocation row', function(hooks) {
});
this.server.create('allocation', { clientStatus: 'running' });
this.store.findAll('allocation');
await this.store.findAll('allocation');
let allocation;
return settled()
.then(async () => {
allocation = this.store.peekAll('allocation').get('firstObject');
const allocation = this.store.peekAll('allocation').get('firstObject');
this.setProperties({
allocation,
@ -72,9 +66,7 @@ module('Integration | Component | allocation row', function(hooks) {
context=context
enablePolling=enablePolling}}
`);
return settled();
})
.then(() => {
assert.equal(
this.server.pretender.handledRequests.filterBy(
'url',
@ -84,9 +76,8 @@ module('Integration | Component | allocation row', function(hooks) {
'Requests continue to be made after malformed responses and server errors'
);
});
});
test('Allocation row shows warning when it requires drivers that are unhealthy on the node it is running on', function(assert) {
test('Allocation row shows warning when it requires drivers that are unhealthy on the node it is running on', async function(assert) {
const node = this.server.schema.nodes.first();
const drivers = node.drivers;
Object.values(drivers).forEach(driver => {
@ -96,15 +87,11 @@ module('Integration | Component | allocation row', function(hooks) {
node.update({ drivers });
this.server.create('allocation', { clientStatus: 'running' });
this.store.findAll('job');
this.store.findAll('node');
this.store.findAll('allocation');
await this.store.findAll('job');
await this.store.findAll('node');
await this.store.findAll('allocation');
let allocation;
return settled()
.then(async () => {
allocation = this.store.peekAll('allocation').get('firstObject');
const allocation = this.store.peekAll('allocation').get('firstObject');
this.setProperties({
allocation,
@ -116,18 +103,13 @@ module('Integration | Component | allocation row', function(hooks) {
allocation=allocation
context=context}}
`);
return settled();
})
.then(() => {
assert.ok(find('[data-test-icon="unhealthy-driver"]'), 'Unhealthy driver icon is shown');
});
});
test('Allocation row shows an icon indicator when it was preempted', async function(assert) {
const allocId = this.server.create('allocation', 'preempted').id;
const allocation = await this.store.findRecord('allocation', allocId);
await settled();
this.setProperties({ allocation, context: 'job' });
await render(hbs`
@ -135,12 +117,11 @@ module('Integration | Component | allocation row', function(hooks) {
allocation=allocation
context=context}}
`);
await settled();
assert.ok(find('[data-test-icon="preemption"]'), 'Preempted icon is shown');
});
test('when an allocation is not running, the utilization graphs are omitted', function(assert) {
test('when an allocation is not running, the utilization graphs are omitted', async function(assert) {
this.setProperties({
context: 'job',
enablePolling: false,
@ -151,56 +132,22 @@ module('Integration | Component | allocation row', function(hooks) {
this.server.create('allocation', { clientStatus })
);
this.store.findAll('allocation');
await this.store.findAll('allocation');
return settled().then(() => {
const allocations = this.store.peekAll('allocation');
return waitForEach(
allocations.map(allocation => async () => {
for (const allocation of allocations.toArray()) {
this.set('allocation', allocation);
await render(hbs`
await this.render(hbs`
{{allocation-row
allocation=allocation
context=context
enablePolling=enablePolling}}
`);
return settled().then(() => {
const status = allocation.get('clientStatus');
assert.notOk(find('[data-test-cpu] .inline-chart'), `No CPU chart for ${status}`);
assert.notOk(find('[data-test-mem] .inline-chart'), `No Mem chart for ${status}`);
});
})
);
});
});
// A way to loop over asynchronous code. Can be replaced by async/await in the future.
const waitForEach = fns => {
let i = 0;
let done = () => {};
// This function is asynchronous and needs to return a promise
const pending = new Promise(resolve => {
done = resolve;
});
const step = () => {
// The waitForEach promise and this recursive loop are done once
// all functions have been called.
if (i >= fns.length) {
done();
return;
}
// Call the current function
const promise = fns[i]() || resolve(true);
// Increment the function position
i++;
// Wait for async behaviors to settle and repeat
promise.then(() => settled()).then(step);
};
step();
return pending;
};
});
});

View file

@ -2,8 +2,7 @@ import Service from '@ember/service';
import RSVP from 'rsvp';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { findAll } from 'ember-native-dom-helpers';
import { findAll, render, settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import PromiseObject from 'nomad-ui/utils/classes/promise-object';

View file

@ -1,7 +1,6 @@
import { find, findAll } from 'ember-native-dom-helpers';
import { find, findAll, render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import flat from 'flat';

View file

@ -1,7 +1,6 @@
import { findAll, find } from 'ember-native-dom-helpers';
import { findAll, find, render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import cleanWhitespace from '../utils/clean-whitespace';

View file

@ -1,8 +1,6 @@
import { assign } from '@ember/polyfills';
import { run } from '@ember/runloop';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { create } from 'ember-cli-page-object';
import sinon from 'sinon';
@ -95,8 +93,7 @@ module('Integration | Component | job-editor', function(hooks) {
const renderNewJob = async (component, job) => {
component.setProperties({ job, onSubmit: sinon.spy(), context: 'new' });
component.render(commonTemplate);
await settled();
await component.render(commonTemplate);
};
const renderEditJob = async (component, job) => {
@ -106,33 +103,22 @@ module('Integration | Component | job-editor', function(hooks) {
const planJob = async spec => {
await Editor.editor.fillIn(spec);
await settled();
await Editor.plan();
await settled();
};
test('the default state is an editor with an explanation popup', async function(assert) {
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
assert.ok(Editor.editorHelp.isPresent, 'Editor explanation popup is present');
assert.ok(Editor.editor.isPresent, 'Editor is present');
});
test('the explanation popup can be dismissed', async function(assert) {
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await Editor.editorHelp.dismiss();
await settled();
assert.notOk(Editor.editorHelp.isPresent, 'Editor explanation popup is gone');
assert.equal(
window.localStorage.nomadMessageJobEditor,
@ -144,24 +130,16 @@ module('Integration | Component | job-editor', function(hooks) {
test('the explanation popup is not shown once the dismissal state is set in localStorage', async function(assert) {
window.localStorage.nomadMessageJobEditor = 'false';
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
assert.notOk(Editor.editorHelp.isPresent, 'Editor explanation popup is gone');
});
test('submitting a json job skips the parse endpoint', async function(assert) {
const spec = jsonJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
const requests = this.server.pretender.handledRequests.mapBy('url');
@ -171,12 +149,8 @@ module('Integration | Component | job-editor', function(hooks) {
test('submitting an hcl job requires the parse endpoint', async function(assert) {
const spec = hclJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
const requests = this.server.pretender.handledRequests.mapBy('url');
@ -190,12 +164,8 @@ module('Integration | Component | job-editor', function(hooks) {
test('when a job is successfully parsed and planned, the plan is shown to the user', async function(assert) {
const spec = hclJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
assert.ok(Editor.planOutput, 'The plan is outputted');
@ -205,16 +175,11 @@ module('Integration | Component | job-editor', function(hooks) {
test('from the plan screen, the cancel button goes back to the editor with the job still in tact', async function(assert) {
const spec = hclJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
await Editor.cancel();
await settled();
assert.ok(Editor.editor.isPresent, 'The editor is shown again');
assert.equal(Editor.editor.contents, spec, 'The spec that was planned is still in the editor');
});
@ -222,15 +187,10 @@ module('Integration | Component | job-editor', function(hooks) {
test('when parse fails, the parse error message is shown', async function(assert) {
const spec = hclJob();
const errorMessage = 'Parse Failed!! :o';
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
this.server.pretender.post('/v1/jobs/parse', () => [400, {}, errorMessage]);
await settled();
await renderNewJob(this, job);
await planJob(spec);
assert.notOk(Editor.planError.isPresent, 'Plan error is not shown');
@ -247,15 +207,10 @@ module('Integration | Component | job-editor', function(hooks) {
test('when plan fails, the plan error message is shown', async function(assert) {
const spec = hclJob();
const errorMessage = 'Plan Failed!! :o';
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
this.server.pretender.post(`/v1/job/${newJobName}/plan`, () => [400, {}, errorMessage]);
await settled();
await renderNewJob(this, job);
await planJob(spec);
assert.notOk(Editor.parseError.isPresent, 'Parse error is not shown');
@ -272,19 +227,13 @@ module('Integration | Component | job-editor', function(hooks) {
test('when run fails, the run error message is shown', async function(assert) {
const spec = hclJob();
const errorMessage = 'Run Failed!! :o';
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
this.server.pretender.post('/v1/jobs', () => [400, {}, errorMessage]);
await settled();
await renderNewJob(this, job);
await planJob(spec);
await Editor.run();
await settled();
assert.notOk(Editor.planError.isPresent, 'Plan error is not shown');
assert.notOk(Editor.parseError.isPresent, 'Parse error is not shown');
@ -298,12 +247,8 @@ module('Integration | Component | job-editor', function(hooks) {
test('when the scheduler dry-run has warnings, the warnings are shown to the user', async function(assert) {
const spec = jsonJob({ Unschedulable: true });
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
assert.ok(
@ -322,12 +267,8 @@ module('Integration | Component | job-editor', function(hooks) {
test('when the scheduler dry-run has no warnings, a success message is shown to the user', async function(assert) {
const spec = hclJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
assert.ok(
@ -342,12 +283,8 @@ module('Integration | Component | job-editor', function(hooks) {
test('when a job is submitted in the edit context, a POST request is made to the update job endpoint', async function(assert) {
const spec = hclJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderEditJob(this, job);
await planJob(spec);
await Editor.run();
@ -358,12 +295,8 @@ module('Integration | Component | job-editor', function(hooks) {
test('when a job is submitted in the new context, a POST request is made to the create job endpoint', async function(assert) {
const spec = hclJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
await Editor.run();
@ -377,16 +310,11 @@ module('Integration | Component | job-editor', function(hooks) {
test('when a job is successfully submitted, the onSubmit hook is called', async function(assert) {
const spec = hclJob();
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
await planJob(spec);
await Editor.run();
await settled();
assert.ok(
this.get('onSubmit').calledWith(newJobName, 'default'),
'The onSubmit hook was called with the correct arguments'
@ -394,34 +322,22 @@ module('Integration | Component | job-editor', function(hooks) {
});
test('when the job-editor cancelable flag is false, there is no cancel button in the header', async function(assert) {
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderNewJob(this, job);
assert.notOk(Editor.cancelEditingIsAvailable, 'No way to cancel editing');
});
test('when the job-editor cancelable flag is true, there is a cancel button in the header', async function(assert) {
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderEditJob(this, job);
assert.ok(Editor.cancelEditingIsAvailable, 'Cancel editing button exists');
});
test('when the job-editor cancel button is clicked, the onCancel hook is called', async function(assert) {
let job;
run(() => {
job = this.store.createRecord('job');
});
const job = await this.store.createRecord('job');
await settled();
await renderEditJob(this, job);
await Editor.cancelEditing();
assert.ok(this.get('onCancel').calledOnce, 'The onCancel hook was called');

View file

@ -1,5 +1,4 @@
import { click, find } from 'ember-native-dom-helpers';
import { settled } from '@ember/test-helpers';
import { click, find } from '@ember/test-helpers';
export function jobURL(job, path = '') {
const id = job.get('plainId');
@ -11,20 +10,14 @@ export function jobURL(job, path = '') {
return expectedURL;
}
export function stopJob() {
click('[data-test-stop] [data-test-idle-button]');
return settled().then(() => {
click('[data-test-stop] [data-test-confirm-button]');
return settled();
});
export async function stopJob() {
await click('[data-test-stop] [data-test-idle-button]');
await click('[data-test-stop] [data-test-confirm-button]');
}
export function startJob() {
click('[data-test-start] [data-test-idle-button]');
return settled().then(() => {
click('[data-test-start] [data-test-confirm-button]');
return settled();
});
export async function startJob() {
await click('[data-test-start] [data-test-idle-button]');
await click('[data-test-start] [data-test-confirm-button]');
}
export function expectStartRequest(assert, server, job) {
@ -39,8 +32,7 @@ export function expectStartRequest(assert, server, job) {
assert.ok(requestPayload.Stop == null, 'The Stop signal is not sent in the POST request');
}
export function expectError(assert, title) {
return () => {
export async function expectError(assert, title) {
assert.equal(
find('[data-test-job-error-title]').textContent,
title,
@ -51,10 +43,8 @@ export function expectError(assert, title) {
'The error message mentions ACLs'
);
click('[data-test-job-error-close]');
await click('[data-test-job-error-close]');
assert.notOk(find('[data-test-job-error-title]'), 'Error message is dismissable');
return settled();
};
}
export function expectDeleteRequest(assert, server, job) {
@ -66,6 +56,4 @@ export function expectDeleteRequest(assert, server, job) {
.find(req => req.url === expectedURL),
'DELETE URL was made correctly'
);
return settled();
}

View file

@ -1,8 +1,6 @@
import { run } from '@ember/runloop';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { find, findAll } from 'ember-native-dom-helpers';
import { find, findAll, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
@ -29,20 +27,15 @@ module('Integration | Component | job-page/parts/body', function(hooks) {
{{/job-page/parts/body}}
`);
await settled();
assert.ok(find('[data-test-subnav="job"]'), 'Job subnav is rendered');
});
test('the subnav includes the deployments link when the job is a service', async function(assert) {
const store = this.owner.lookup('service:store');
let job;
run(() => {
job = store.createRecord('job', {
const job = await store.createRecord('job', {
id: 'service-job',
type: 'service',
});
});
this.set('job', job);
@ -52,7 +45,6 @@ module('Integration | Component | job-page/parts/body', function(hooks) {
{{/job-page/parts/body}}
`);
await settled();
const subnavLabels = findAll('[data-test-tab]').map(anchor => anchor.textContent);
assert.ok(subnavLabels.some(label => label === 'Definition'), 'Definition link');
assert.ok(subnavLabels.some(label => label === 'Versions'), 'Versions link');
@ -61,14 +53,10 @@ module('Integration | Component | job-page/parts/body', function(hooks) {
test('the subnav does not include the deployments link when the job is not a service', async function(assert) {
const store = this.owner.lookup('service:store');
let job;
run(() => {
job = store.createRecord('job', {
const job = await store.createRecord('job', {
id: 'batch-job',
type: 'batch',
});
});
this.set('job', job);
@ -78,7 +66,6 @@ module('Integration | Component | job-page/parts/body', function(hooks) {
{{/job-page/parts/body}}
`);
await settled();
const subnavLabels = findAll('[data-test-tab]').map(anchor => anchor.textContent);
assert.ok(subnavLabels.some(label => label === 'Definition'), 'Definition link');
assert.ok(subnavLabels.some(label => label === 'Versions'), 'Versions link');
@ -94,7 +81,6 @@ module('Integration | Component | job-page/parts/body', function(hooks) {
{{/job-page/parts/body}}
`);
await settled();
assert.ok(
find('[data-test-subnav="job"] + .section > .inner-content'),
'Content is rendered immediately after the subnav'

View file

@ -1,11 +1,9 @@
import { assign } from '@ember/polyfills';
import { run } from '@ember/runloop';
import hbs from 'htmlbars-inline-precompile';
import { findAll, find, click } from 'ember-native-dom-helpers';
import { findAll, find, click, render } from '@ember/test-helpers';
import sinon from 'sinon';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
module('Integration | Component | job-page/parts/children', function(hooks) {
@ -35,21 +33,16 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
options
);
test('lists each child', function(assert) {
let parent;
test('lists each child', async function(assert) {
this.server.create('job', 'periodic', {
id: 'parent',
childrenCount: 3,
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
run(() => {
parent = this.store.peekAll('job').findBy('plainId', 'parent');
});
const parent = this.store.peekAll('job').findBy('plainId', 'parent');
this.setProperties(props(parent));
@ -62,31 +55,23 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
gotoJob=gotoJob}}
`);
return settled().then(() => {
assert.equal(
findAll('[data-test-job-name]').length,
parent.get('children.length'),
'A row for each child'
);
});
});
});
test('eventually paginates', function(assert) {
let parent;
test('eventually paginates', async function(assert) {
this.server.create('job', 'periodic', {
id: 'parent',
childrenCount: 11,
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
run(() => {
parent = this.store.peekAll('job').findBy('plainId', 'parent');
});
const parent = this.store.peekAll('job').findBy('plainId', 'parent');
this.setProperties(props(parent));
@ -99,7 +84,6 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
gotoJob=gotoJob}}
`);
return settled().then(() => {
const childrenCount = parent.get('children.length');
assert.ok(childrenCount > 10, 'Parent has more children than one page size');
assert.equal(findAll('[data-test-job-name]').length, 10, 'Table length maxes out at 10');
@ -109,24 +93,17 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
new RegExp(`1.10.+?${childrenCount}`).test(find('.pagination-numbers').textContent.trim())
);
});
});
});
test('is sorted based on the sortProperty and sortDescending properties', function(assert) {
let parent;
test('is sorted based on the sortProperty and sortDescending properties', async function(assert) {
this.server.create('job', 'periodic', {
id: 'parent',
childrenCount: 3,
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
run(() => {
parent = this.store.peekAll('job').findBy('plainId', 'parent');
});
const parent = this.store.peekAll('job').findBy('plainId', 'parent');
this.setProperties(props(parent));
@ -139,7 +116,6 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
gotoJob=gotoJob}}
`);
return settled().then(() => {
const sortedChildren = parent.get('children').sortBy('name');
const childRows = findAll('[data-test-job-name]');
@ -151,7 +127,7 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
);
});
this.set('sortDescending', false);
await this.set('sortDescending', false);
sortedChildren.forEach((child, index) => {
assert.equal(
@ -160,14 +136,9 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
`Child ${index} is ${child.get('name')}`
);
});
return settled();
});
});
});
test('gotoJob is called when a job row is clicked', function(assert) {
let parent;
test('gotoJob is called when a job row is clicked', async function(assert) {
const gotoJobSpy = sinon.spy();
this.server.create('job', 'periodic', {
@ -176,12 +147,9 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
run(() => {
parent = this.store.peekAll('job').findBy('plainId', 'parent');
});
const parent = this.store.peekAll('job').findBy('plainId', 'parent');
this.setProperties(
props(parent, {
@ -198,13 +166,11 @@ module('Integration | Component | job-page/parts/children', function(hooks) {
gotoJob=gotoJob}}
`);
return settled().then(() => {
click('tr.job-row');
await click('tr.job-row');
assert.ok(
gotoJobSpy.withArgs(parent.get('children.firstObject')).calledOnce,
'Clicking the job row calls the gotoJob action'
);
});
});
});
});

View file

@ -1,7 +1,6 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { click, find } from 'ember-native-dom-helpers';
import { click, find, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import moment from 'moment';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
@ -23,45 +22,39 @@ module('Integration | Component | job-page/parts/latest-deployment', function(ho
window.localStorage.clear();
});
test('there is no latest deployment section when the job has no deployments', function(assert) {
test('there is no latest deployment section when the job has no deployments', async function(assert) {
this.server.create('job', {
type: 'service',
noDeployments: true,
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/latest-deployment job=job}})
`);
return settled().then(() => {
assert.notOk(find('[data-test-active-deployment]'), 'No active deployment');
});
});
});
test('the latest deployment section shows up for the currently running deployment', function(assert) {
test('the latest deployment section shows up for the currently running deployment', async function(assert) {
this.server.create('job', {
type: 'service',
createAllocations: false,
activeDeployment: true,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/latest-deployment job=job}}
`);
return settled().then(() => {
const deployment = this.get('job.latestDeployment');
const version = deployment.get('version');
const deployment = await this.get('job.latestDeployment');
const version = await deployment.get('version');
assert.ok(find('[data-test-active-deployment]'), 'Active deployment');
assert.ok(
@ -116,67 +109,54 @@ module('Integration | Component | job-page/parts/latest-deployment', function(ho
'Status description is in the metrics block'
);
});
});
});
test('when there is no running deployment, the latest deployment section shows up for the last deployment', function(assert) {
test('when there is no running deployment, the latest deployment section shows up for the last deployment', async function(assert) {
this.server.create('job', {
type: 'service',
createAllocations: false,
noActiveDeployment: true,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/latest-deployment job=job}}
`);
return settled().then(() => {
assert.ok(find('[data-test-active-deployment]'), 'Active deployment');
assert.notOk(
find('[data-test-active-deployment]').classList.contains('is-info'),
'Non-running deployment does not get the is-info class'
);
});
});
});
test('the latest deployment section can be expanded to show task groups and allocations', function(assert) {
test('the latest deployment section can be expanded to show task groups and allocations', async function(assert) {
this.server.create('node');
this.server.create('job', { type: 'service', activeDeployment: true });
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/latest-deployment job=job}}
`);
return settled().then(() => {
assert.notOk(find('[data-test-deployment-task-groups]'), 'Task groups not found');
assert.notOk(find('[data-test-deployment-allocations]'), 'Allocations not found');
click('[data-test-deployment-toggle-details]');
await click('[data-test-deployment-toggle-details]');
return settled().then(() => {
assert.ok(find('[data-test-deployment-task-groups]'), 'Task groups found');
assert.ok(find('[data-test-deployment-allocations]'), 'Allocations found');
});
});
});
});
test('each task group in the expanded task group section shows task group details', function(assert) {
test('each task group in the expanded task group section shows task group details', async function(assert) {
this.server.create('node');
this.server.create('job', { type: 'service', activeDeployment: true });
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
const job = this.store.peekAll('job').get('firstObject');
this.set('job', job);
@ -184,15 +164,10 @@ module('Integration | Component | job-page/parts/latest-deployment', function(ho
{{job-page/parts/latest-deployment job=job}}
`);
return settled()
.then(() => {
click('[data-test-deployment-toggle-details]');
return settled();
})
.then(() => {
await click('[data-test-deployment-toggle-details]');
const task = job.get('runningDeployment.taskGroupSummaries.firstObject');
const findForTaskGroup = selector =>
find(`[data-test-deployment-task-group-${selector}]`);
const findForTaskGroup = selector => find(`[data-test-deployment-task-group-${selector}]`);
assert.equal(findForTaskGroup('name').textContent.trim(), task.get('name'));
assert.equal(
findForTaskGroup('progress-deadline').textContent.trim(),
@ -200,5 +175,3 @@ module('Integration | Component | job-page/parts/latest-deployment', function(ho
);
});
});
});
});

View file

@ -1,9 +1,7 @@
import { run } from '@ember/runloop';
import hbs from 'htmlbars-inline-precompile';
import { findAll, find } from 'ember-native-dom-helpers';
import { findAll, find, render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
@ -23,22 +21,19 @@ module('Integration | Component | job-page/parts/placement-failures', function(h
window.localStorage.clear();
});
test('when the job has placement failures, they are called out', function(assert) {
test('when the job has placement failures, they are called out', async function(assert) {
this.server.create('job', { failedPlacements: true, createAllocations: false });
this.store.findAll('job').then(jobs => {
jobs.forEach(job => job.reload());
});
await this.store.findAll('job');
return settled().then(async () => {
run(() => {
this.set('job', this.store.peekAll('job').get('firstObject'));
});
const job = this.store.peekAll('job').get('firstObject');
await job.reload();
this.set('job', job);
await render(hbs`
{{job-page/parts/placement-failures job=job}})
`);
return settled().then(() => {
const failedEvaluation = this.get('job.evaluations')
.filterBy('hasPlacementFailures')
.sortBy('modifyIndex')
@ -64,28 +59,20 @@ module('Integration | Component | job-page/parts/placement-failures', function(h
);
});
});
});
});
test('when the job has no placement failures, the placement failures section is gone', function(assert) {
test('when the job has no placement failures, the placement failures section is gone', async function(assert) {
this.server.create('job', { noFailedPlacements: true, createAllocations: false });
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
run(() => {
this.set('job', this.store.peekAll('job').get('firstObject'));
});
const job = this.store.peekAll('job').get('firstObject');
await job.reload();
this.set('job', job);
await render(hbs`
{{job-page/parts/placement-failures job=job}})
`);
return settled().then(() => {
assert.notOk(
find('[data-test-placement-failures]'),
'Placement failures section not found'
);
});
});
assert.notOk(find('[data-test-placement-failures]'), 'Placement failures section not found');
});
});

View file

@ -1,8 +1,7 @@
import hbs from 'htmlbars-inline-precompile';
import { find, click } from 'ember-native-dom-helpers';
import { find, click, render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
@ -22,63 +21,53 @@ module('Integration | Component | job-page/parts/summary', function(hooks) {
window.localStorage.clear();
});
test('jobs with children use the children diagram', function(assert) {
test('jobs with children use the children diagram', async function(assert) {
this.server.create('job', 'periodic', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled().then(() => {
assert.ok(find('[data-test-children-status-bar]'), 'Children status bar found');
assert.notOk(find('[data-test-allocation-status-bar]'), 'Allocation status bar not found');
});
});
});
test('jobs without children use the allocations diagram', function(assert) {
test('jobs without children use the allocations diagram', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled().then(() => {
assert.ok(find('[data-test-allocation-status-bar]'), 'Allocation status bar found');
assert.notOk(find('[data-test-children-status-bar]'), 'Children status bar not found');
});
});
});
test('the allocations diagram lists all allocation status figures', function(assert) {
test('the allocations diagram lists all allocation status figures', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled().then(() => {
assert.equal(
find('[data-test-legend-value="queued"]').textContent,
this.get('job.queuedAllocs'),
@ -115,24 +104,20 @@ module('Integration | Component | job-page/parts/summary', function(hooks) {
`${this.get('job.lostAllocs')} are lost`
);
});
});
});
test('the children diagram lists all children status figures', function(assert) {
test('the children diagram lists all children status figures', async function(assert) {
this.server.create('job', 'periodic', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled().then(() => {
assert.equal(
find('[data-test-legend-value="queued"]').textContent,
this.get('job.pendingChildren'),
@ -151,127 +136,94 @@ module('Integration | Component | job-page/parts/summary', function(hooks) {
`${this.get('job.deadChildren')} are dead`
);
});
});
});
test('the summary block can be collapsed', function(assert) {
test('the summary block can be collapsed', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled();
})
.then(() => {
click('[data-test-accordion-toggle]');
return settled();
})
.then(() => {
await click('[data-test-accordion-toggle]');
assert.notOk(find('[data-test-accordion-body]'), 'No accordion body');
assert.notOk(find('[data-test-legend]'), 'No legend');
});
});
test('when collapsed, the summary block includes an inline version of the chart', function(assert) {
test('when collapsed, the summary block includes an inline version of the chart', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled();
})
.then(() => {
click('[data-test-accordion-toggle]');
return settled();
})
.then(() => {
await click('[data-test-accordion-toggle]');
assert.ok(find('[data-test-allocation-status-bar]'), 'Allocation bar still existed');
assert.ok(
find('.inline-chart [data-test-allocation-status-bar]'),
'Allocation bar is rendered in an inline-chart container'
);
});
});
test('the collapsed/expanded state is persisted to localStorage', function(assert) {
test('the collapsed/expanded state is persisted to localStorage', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled();
})
.then(() => {
assert.notOk(window.localStorage.nomadExpandJobSummary, 'No value in localStorage yet');
click('[data-test-accordion-toggle]');
return settled();
})
.then(() => {
await click('[data-test-accordion-toggle]');
assert.equal(
window.localStorage.nomadExpandJobSummary,
'false',
'Value is stored for the collapsed state'
);
});
});
test('the collapsed/expanded state from localStorage is used for the initial state when available', function(assert) {
test('the collapsed/expanded state from localStorage is used for the initial state when available', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
window.localStorage.nomadExpandJobSummary = 'false';
return settled()
.then(async () => {
this.set('job', this.store.peekAll('job').get('firstObject'));
await render(hbs`
{{job-page/parts/summary job=job}}
`);
return settled();
})
.then(() => {
assert.ok(find('[data-test-allocation-status-bar]'), 'Allocation bar still existed');
assert.ok(
find('.inline-chart [data-test-allocation-status-bar]'),
'Allocation bar is rendered in an inline-chart container'
);
click('[data-test-accordion-toggle]');
return settled();
})
.then(() => {
await click('[data-test-accordion-toggle]');
assert.equal(
window.localStorage.nomadExpandJobSummary,
'true',
@ -280,4 +232,3 @@ module('Integration | Component | job-page/parts/summary', function(hooks) {
assert.ok(find('[data-test-accordion-body]'), 'Summary still expands');
});
});
});

View file

@ -1,18 +1,15 @@
import { assign } from '@ember/polyfills';
import hbs from 'htmlbars-inline-precompile';
import { click, findAll, find } from 'ember-native-dom-helpers';
import { click, findAll, find } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import sinon from 'sinon';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
import { setupRenderingTest } from 'ember-qunit';
module('Integration | Component | job-page/parts/task-groups', function(hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function() {
fragmentSerializerInitializer(this.owner);
window.localStorage.clear();
this.store = this.owner.lookup('service:store');
this.server = startMirage();
@ -34,20 +31,19 @@ module('Integration | Component | job-page/parts/task-groups', function(hooks) {
options
);
test('the job detail page should list all task groups', function(assert) {
test('the job detail page should list all task groups', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job').then(jobs => {
await this.store.findAll('job').then(jobs => {
jobs.forEach(job => job.reload());
});
return settled().then(async () => {
const job = this.store.peekAll('job').get('firstObject');
this.setProperties(props(job));
await render(hbs`
await this.render(hbs`
{{job-page/parts/task-groups
job=job
sortProperty=sortProperty
@ -55,36 +51,31 @@ module('Integration | Component | job-page/parts/task-groups', function(hooks) {
gotoTaskGroup=gotoTaskGroup}}
`);
return settled().then(() => {
assert.equal(
findAll('[data-test-task-group]').length,
job.get('taskGroups.length'),
'One row per task group'
);
});
});
});
test('each row in the task group table should show basic information about the task group', function(assert) {
test('each row in the task group table should show basic information about the task group', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job').then(jobs => {
jobs.forEach(job => job.reload());
const job = await this.store.findAll('job').then(async jobs => {
return await jobs.get('firstObject').reload();
});
return settled().then(async () => {
const job = this.store.peekAll('job').get('firstObject');
const taskGroup = job
.get('taskGroups')
const taskGroups = await job.get('taskGroups');
const taskGroup = taskGroups
.sortBy('name')
.reverse()
.get('firstObject');
this.setProperties(props(job));
await render(hbs`
await this.render(hbs`
{{job-page/parts/task-groups
job=job
sortProperty=sortProperty
@ -92,7 +83,6 @@ module('Integration | Component | job-page/parts/task-groups', function(hooks) {
gotoTaskGroup=gotoTaskGroup}}
`);
return settled().then(() => {
const taskGroupRow = find('[data-test-task-group]');
assert.equal(
@ -121,23 +111,20 @@ module('Integration | Component | job-page/parts/task-groups', function(hooks) {
'Reserved Disk'
);
});
});
});
test('gotoTaskGroup is called when task group rows are clicked', function(assert) {
test('gotoTaskGroup is called when task group rows are clicked', async function(assert) {
this.server.create('job', {
createAllocations: false,
});
this.store.findAll('job').then(jobs => {
jobs.forEach(job => job.reload());
const job = await this.store.findAll('job').then(async jobs => {
return await jobs.get('firstObject').reload();
});
return settled().then(async () => {
const taskGroupSpy = sinon.spy();
const job = this.store.peekAll('job').get('firstObject');
const taskGroup = job
.get('taskGroups')
const taskGroups = await job.get('taskGroups');
const taskGroup = taskGroups
.sortBy('name')
.reverse()
.get('firstObject');
@ -148,7 +135,7 @@ module('Integration | Component | job-page/parts/task-groups', function(hooks) {
})
);
await render(hbs`
await this.render(hbs`
{{job-page/parts/task-groups
job=job
sortProperty=sortProperty
@ -156,13 +143,11 @@ module('Integration | Component | job-page/parts/task-groups', function(hooks) {
gotoTaskGroup=gotoTaskGroup}}
`);
return settled().then(() => {
click('[data-test-task-group]');
await click('[data-test-task-group]');
assert.ok(
taskGroupSpy.withArgs(taskGroup).calledOnce,
'Clicking the task group row calls the gotoTaskGroup action'
);
});
});
});
});

View file

@ -1,7 +1,6 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { click, find, findAll } from 'ember-native-dom-helpers';
import { click, find, findAll, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import {
@ -45,7 +44,7 @@ module('Integration | Component | job-page/periodic', function(hooks) {
gotoJob: () => {},
});
test('Clicking Force Launch launches a new periodic child job', function(assert) {
test('Clicking Force Launch launches a new periodic child job', async function(assert) {
const childrenCount = 3;
this.server.create('job', 'periodic', {
@ -54,15 +53,13 @@ module('Integration | Component | job-page/periodic', function(hooks) {
createAllocations: false,
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
const job = this.store.peekAll('job').findBy('plainId', 'parent');
this.setProperties(commonProperties(job));
await render(commonTemplate);
await this.render(commonTemplate);
return settled().then(() => {
const currentJobCount = server.db.jobs.length;
assert.equal(
@ -71,9 +68,8 @@ module('Integration | Component | job-page/periodic', function(hooks) {
'The new periodic job launch is in the children list'
);
click('[data-test-force-launch]');
await click('[data-test-force-launch]');
return settled().then(() => {
const expectedURL = jobURL(job, '/periodic/force');
assert.ok(
@ -85,11 +81,8 @@ module('Integration | Component | job-page/periodic', function(hooks) {
assert.equal(server.db.jobs.length, currentJobCount + 1, 'POST request was made');
});
});
});
});
test('Clicking force launch without proper permissions shows an error message', function(assert) {
test('Clicking force launch without proper permissions shows an error message', async function(assert) {
this.server.pretender.post('/v1/job/:id/periodic/force', () => [403, {}, null]);
this.server.create('job', 'periodic', {
@ -99,20 +92,17 @@ module('Integration | Component | job-page/periodic', function(hooks) {
status: 'running',
});
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
const job = this.store.peekAll('job').findBy('plainId', 'parent');
this.setProperties(commonProperties(job));
await render(commonTemplate);
await this.render(commonTemplate);
return settled().then(() => {
assert.notOk(find('[data-test-job-error-title]'), 'No error message yet');
click('[data-test-force-launch]');
await click('[data-test-force-launch]');
return settled().then(() => {
assert.equal(
find('[data-test-job-error-title]').textContent,
'Could Not Force Launch',
@ -123,15 +113,12 @@ module('Integration | Component | job-page/periodic', function(hooks) {
'The error message mentions ACLs'
);
click('[data-test-job-error-close]');
await click('[data-test-job-error-close]');
assert.notOk(find('[data-test-job-error-title]'), 'Error message is dismissable');
});
});
});
});
test('Stopping a job sends a delete request for the job', function(assert) {
test('Stopping a job sends a delete request for the job', async function(assert) {
const mirageJob = this.server.create('job', 'periodic', {
childrenCount: 0,
createAllocations: false,
@ -139,22 +126,18 @@ module('Integration | Component | job-page/periodic', function(hooks) {
});
let job;
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
await stopJob();
return settled();
})
.then(stopJob)
.then(() => expectDeleteRequest(assert, this.server, job));
expectDeleteRequest(assert, this.server, job);
});
test('Stopping a job without proper permissions shows an error message', function(assert) {
test('Stopping a job without proper permissions shows an error message', async function(assert) {
this.server.pretender.delete('/v1/job/:id', () => [403, {}, null]);
const mirageJob = this.server.create('job', 'periodic', {
@ -163,45 +146,35 @@ module('Integration | Component | job-page/periodic', function(hooks) {
status: 'running',
});
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(stopJob)
.then(expectError(assert, 'Could Not Stop Job'));
await stopJob();
expectError(assert, 'Could Not Stop Job');
});
test('Starting a job sends a post request for the job using the current definition', function(assert) {
let job;
test('Starting a job sends a post request for the job using the current definition', async function(assert) {
const mirageJob = this.server.create('job', 'periodic', {
childrenCount: 0,
createAllocations: false,
status: 'dead',
});
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(startJob)
.then(() => expectStartRequest(assert, this.server, job));
await startJob();
expectStartRequest(assert, this.server, job);
});
test('Starting a job without proper permissions shows an error message', function(assert) {
test('Starting a job without proper permissions shows an error message', async function(assert) {
this.server.pretender.post('/v1/job/:id', () => [403, {}, null]);
const mirageJob = this.server.create('job', 'periodic', {
@ -209,18 +182,14 @@ module('Integration | Component | job-page/periodic', function(hooks) {
createAllocations: false,
status: 'dead',
});
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(startJob)
.then(expectError(assert, 'Could Not Start Job'));
await startJob();
expectError(assert, 'Could Not Start Job');
});
});

View file

@ -1,8 +1,7 @@
import { assign } from '@ember/polyfills';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { click, find } from 'ember-native-dom-helpers';
import { click, find, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import { startJob, stopJob, expectError, expectDeleteRequest, expectStartRequest } from './helpers';
@ -57,182 +56,131 @@ module('Integration | Component | job-page/service', function(hooks) {
)
);
test('Stopping a job sends a delete request for the job', function(assert) {
let job;
test('Stopping a job sends a delete request for the job', async function(assert) {
const mirageJob = makeMirageJob(this.server);
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(stopJob)
.then(() => expectDeleteRequest(assert, this.server, job));
await stopJob();
expectDeleteRequest(assert, this.server, job);
});
test('Stopping a job without proper permissions shows an error message', function(assert) {
test('Stopping a job without proper permissions shows an error message', async function(assert) {
this.server.pretender.delete('/v1/job/:id', () => [403, {}, null]);
const mirageJob = makeMirageJob(this.server);
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(stopJob)
.then(expectError(assert, 'Could Not Stop Job'));
await stopJob();
expectError(assert, 'Could Not Stop Job');
});
test('Starting a job sends a post request for the job using the current definition', function(assert) {
let job;
test('Starting a job sends a post request for the job using the current definition', async function(assert) {
const mirageJob = makeMirageJob(this.server, { status: 'dead' });
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(startJob)
.then(() => expectStartRequest(assert, this.server, job));
await startJob();
expectStartRequest(assert, this.server, job);
});
test('Starting a job without proper permissions shows an error message', function(assert) {
test('Starting a job without proper permissions shows an error message', async function(assert) {
this.server.pretender.post('/v1/job/:id', () => [403, {}, null]);
const mirageJob = makeMirageJob(this.server, { status: 'dead' });
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(startJob)
.then(expectError(assert, 'Could Not Start Job'));
await startJob();
expectError(assert, 'Could Not Start Job');
});
test('Recent allocations shows allocations in the job context', function(assert) {
let job;
test('Recent allocations shows allocations in the job context', async function(assert) {
this.server.create('node');
const mirageJob = makeMirageJob(this.server, { createAllocations: true });
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(() => {
const allocation = this.server.db.allocations.sortBy('modifyIndex').reverse()[0];
const allocationRow = Job.allocations.objectAt(0);
assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'ID');
assert.equal(allocationRow.taskGroup, allocation.taskGroup, 'Task Group name');
});
});
test('Recent allocations caps out at five', function(assert) {
let job;
test('Recent allocations caps out at five', async function(assert) {
this.server.create('node');
const mirageJob = makeMirageJob(this.server);
this.server.createList('allocation', 10);
this.store.findAll('job');
await this.store.findAll('job');
return settled().then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled().then(() => {
assert.equal(Job.allocations.length, 5, 'Capped at 5 allocations');
assert.ok(
Job.viewAllAllocations.includes(job.get('allocations.length') + ''),
`View link mentions ${job.get('allocations.length')} allocations`
);
});
});
});
test('Recent allocations shows an empty message when the job has no allocations', function(assert) {
let job;
test('Recent allocations shows an empty message when the job has no allocations', async function(assert) {
this.server.create('node');
const mirageJob = makeMirageJob(this.server);
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(
Job.recentAllocationsEmptyState.headline.includes('No Allocations'),
'No allocations empty message'
);
});
});
test('Active deployment can be promoted', function(assert) {
let job;
let deployment;
test('Active deployment can be promoted', async function(assert) {
this.server.create('node');
const mirageJob = makeMirageJob(this.server, { activeDeployment: true });
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
deployment = job.get('latestDeployment');
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const deployment = await job.get('latestDeployment');
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(() => {
click('[data-test-promote-canary]');
return settled();
})
.then(() => {
await click('[data-test-promote-canary]');
const requests = this.server.pretender.handledRequests;
assert.ok(
requests
.filterBy('method', 'POST')
@ -240,32 +188,22 @@ module('Integration | Component | job-page/service', function(hooks) {
'A promote POST request was made'
);
});
});
test('When promoting the active deployment fails, an error is shown', function(assert) {
test('When promoting the active deployment fails, an error is shown', async function(assert) {
this.server.pretender.post('/v1/deployment/promote/:id', () => [403, {}, null]);
let job;
this.server.create('node');
const mirageJob = makeMirageJob(this.server, { activeDeployment: true });
this.store.findAll('job');
await this.store.findAll('job');
return settled()
.then(async () => {
job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
return settled();
})
.then(() => {
click('[data-test-promote-canary]');
return settled();
})
.then(() => {
await click('[data-test-promote-canary]');
assert.equal(
find('[data-test-job-error-title]').textContent,
'Could Not Promote Deployment',
@ -276,9 +214,8 @@ module('Integration | Component | job-page/service', function(hooks) {
'The error message mentions ACLs'
);
click('[data-test-job-error-close]');
await click('[data-test-job-error-close]');
assert.notOk(find('[data-test-job-error-title]'), 'Error message is dismissable');
return settled();
});
});
});

View file

@ -1,7 +1,6 @@
import { findAll, find } from 'ember-native-dom-helpers';
import { findAll, find, render } from '@ember/test-helpers';
import { module, skip, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | list pagination', function(hooks) {
@ -240,7 +239,8 @@ module('Integration | Component | list pagination', function(hooks) {
assert.equal(
findAll('.item')[item].textContent,
item + (currentPage - 1) * size,
`Rendered items are in the current page, ${currentPage} (${item + (currentPage - 1) * size})`
`Rendered items are in the current page, ${currentPage} (${item +
(currentPage - 1) * size})`
);
}
}

View file

@ -1,7 +1,6 @@
import { findAll, find } from 'ember-native-dom-helpers';
import { findAll, find, render } from '@ember/test-helpers';
import { module, skip, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { faker } from 'ember-cli-mirage';
import hbs from 'htmlbars-inline-precompile';

View file

@ -1,7 +1,6 @@
import { findAll, find, click, focus, keyEvent } from 'ember-native-dom-helpers';
import { findAll, find, click, focus, render, triggerKeyEvent } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import sinon from 'sinon';
import hbs from 'htmlbars-inline-precompile';
@ -55,27 +54,21 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
await assert.ok(find('[data-test-dropdown-options]'), 'Options are shown now');
await click('[data-test-dropdown-trigger]');
return settled()
.then(() => {
assert.ok(find('[data-test-dropdown-options]'), 'Options are shown now');
click('[data-test-dropdown-trigger]');
return settled();
})
.then(() => {
assert.notOk(find('[data-test-dropdown-options]'), 'Options are hidden after clicking again');
});
});
test('all options are shown in the options dropdown, each with a checkbox input', async function(assert) {
const props = commonProperties();
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
return settled().then(() => {
assert.equal(
findAll('[data-test-dropdown-option]').length,
props.options.length,
@ -87,21 +80,15 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
assert.ok(optionEl.querySelector('input[type="checkbox"]'), 'Option contains a checkbox');
});
});
});
test('onSelect gets called when an option is clicked', async function(assert) {
const props = commonProperties();
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-option] label');
return settled()
.then(() => {
click('[data-test-dropdown-option] label');
return settled();
})
.then(() => {
assert.ok(props.onSelect.called, 'onSelect was called');
const newSelection = props.onSelect.getCall(0).args[0];
assert.deepEqual(
@ -110,7 +97,6 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
'onSelect was called with the first option key'
);
});
});
test('the component trigger shows the selection count when there is a selection', async function(assert) {
const props = commonProperties();
@ -118,31 +104,32 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
assert.ok(find('[data-test-dropdown-trigger] [data-test-dropdown-count]'), 'The count is shown');
assert.ok(
find('[data-test-dropdown-trigger] [data-test-dropdown-count]'),
'The count is shown'
);
assert.equal(
find('[data-test-dropdown-trigger] [data-test-dropdown-count]').textContent,
props.selection.length,
'The count is accurate'
);
this.set('selection', []);
await this.set('selection', []);
return settled().then(() => {
assert.notOk(
find('[data-test-dropdown-trigger] [data-test-dropdown-count]'),
'The count is no longer shown when the selection is empty'
);
});
});
test('pressing DOWN when the trigger has focus opens the options list', async function(assert) {
const props = commonProperties();
this.setProperties(props);
await render(commonTemplate);
focus('[data-test-dropdown-trigger]');
await focus('[data-test-dropdown-trigger]');
assert.notOk(find('[data-test-dropdown-options]'), 'Options are not shown on focus');
keyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
assert.ok(find('[data-test-dropdown-options]'), 'Options are now shown');
assert.equal(
document.activeElement,
@ -156,9 +143,9 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
focus('[data-test-dropdown-trigger]');
keyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
keyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
await focus('[data-test-dropdown-trigger]');
await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
assert.equal(
document.activeElement,
find('[data-test-dropdown-option]'),
@ -171,9 +158,9 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
focus('[data-test-dropdown-trigger]');
keyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
keyEvent('[data-test-dropdown-trigger]', 'keydown', TAB);
await focus('[data-test-dropdown-trigger]');
await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', TAB);
assert.equal(
document.activeElement,
find('[data-test-dropdown-option]'),
@ -186,10 +173,10 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
focus('[data-test-dropdown-option]');
keyEvent('[data-test-dropdown-option]', 'keydown', ARROW_UP);
await focus('[data-test-dropdown-option]');
await triggerKeyEvent('[data-test-dropdown-option]', 'keydown', ARROW_UP);
assert.equal(
document.activeElement,
find('[data-test-dropdown-option]'),
@ -202,10 +189,10 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
focus('[data-test-dropdown-option]');
keyEvent('[data-test-dropdown-option]', 'keydown', ARROW_DOWN);
await focus('[data-test-dropdown-option]');
await triggerKeyEvent('[data-test-dropdown-option]', 'keydown', ARROW_DOWN);
assert.equal(
document.activeElement,
findAll('[data-test-dropdown-option]')[1],
@ -218,20 +205,26 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
focus('[data-test-dropdown-option]');
await focus('[data-test-dropdown-option]');
const optionEls = findAll('[data-test-dropdown-option]');
const lastIndex = optionEls.length - 1;
optionEls.forEach((option, index) => {
keyEvent(option, 'keydown', ARROW_DOWN);
for (const [index, option] of optionEls.entries()) {
await triggerKeyEvent(option, 'keydown', ARROW_DOWN);
if (index < lastIndex) {
assert.equal(document.activeElement, optionEls[index + 1], `Option ${index + 1} has focus`);
}
});
}
keyEvent(optionEls[lastIndex], 'keydown', ARROW_DOWN);
assert.equal(document.activeElement, optionEls[lastIndex], `Option ${lastIndex} still has focus`);
await triggerKeyEvent(optionEls[lastIndex], 'keydown', ARROW_DOWN);
assert.equal(
document.activeElement,
optionEls[lastIndex],
`Option ${lastIndex} still has focus`
);
});
test('onSelect gets called when pressing SPACE when a list option is focused', async function(assert) {
@ -239,10 +232,10 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
focus('[data-test-dropdown-option]');
keyEvent('[data-test-dropdown-option]', 'keydown', SPACE);
await focus('[data-test-dropdown-option]');
await triggerKeyEvent('[data-test-dropdown-option]', 'keydown', SPACE);
assert.ok(props.onSelect.called, 'onSelect was called');
const newSelection = props.onSelect.getCall(0).args[0];
@ -258,7 +251,7 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
findAll('[data-test-dropdown-option]').forEach(option => {
assert.ok(parseInt(option.getAttribute('tabindex'), 10) > 0, 'tabindex is a positive value');
@ -270,7 +263,7 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
findAll('[data-test-dropdown-option]').forEach(option => {
assert.ok(
@ -285,10 +278,10 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
focus('[data-test-dropdown-trigger]');
keyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
keyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
keyEvent('[data-test-dropdown-option]', 'keydown', ESC);
await focus('[data-test-dropdown-trigger]');
await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN);
await triggerKeyEvent('[data-test-dropdown-option]', 'keydown', ESC);
assert.notOk(find('[data-test-dropdown-options]'), 'The options list is hidden once more');
assert.equal(
@ -304,7 +297,7 @@ module('Integration | Component | multi-select dropdown', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
click('[data-test-dropdown-trigger]');
await click('[data-test-dropdown-trigger]');
assert.ok(find('[data-test-dropdown-options]'), 'The dropdown is still shown');
assert.ok(find('[data-test-dropdown-empty]'), 'The empty state is shown');
assert.notOk(find('[data-test-dropdown-option]'), 'No options are shown');

View file

@ -1,7 +1,6 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { find, click } from 'ember-native-dom-helpers';
import { find, click, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
@ -23,54 +22,36 @@ module('Integration | Component | page layout', function(hooks) {
find('[data-test-gutter-menu]').classList.contains('is-open'),
'Gutter menu is not open'
);
click('[data-test-header-gutter-toggle]');
await click('[data-test-header-gutter-toggle]');
return settled().then(() => {
assert.ok(find('[data-test-gutter-menu]').classList.contains('is-open'), 'Gutter menu is open');
});
});
test('the gutter-menu hamburger menu closes the gutter menu', async function(assert) {
await render(hbs`{{page-layout}}`);
click('[data-test-header-gutter-toggle]');
await click('[data-test-header-gutter-toggle]');
assert.ok(find('[data-test-gutter-menu]').classList.contains('is-open'), 'Gutter menu is open');
await click('[data-test-gutter-gutter-toggle]');
return settled()
.then(() => {
assert.ok(
find('[data-test-gutter-menu]').classList.contains('is-open'),
'Gutter menu is open'
);
click('[data-test-gutter-gutter-toggle]');
return settled();
})
.then(() => {
assert.notOk(
find('[data-test-gutter-menu]').classList.contains('is-open'),
'Gutter menu is not open'
);
});
});
test('the gutter-menu backdrop closes the gutter menu', async function(assert) {
await render(hbs`{{page-layout}}`);
click('[data-test-header-gutter-toggle]');
await click('[data-test-header-gutter-toggle]');
assert.ok(find('[data-test-gutter-menu]').classList.contains('is-open'), 'Gutter menu is open');
await click('[data-test-gutter-backdrop]');
return settled()
.then(() => {
assert.ok(
find('[data-test-gutter-menu]').classList.contains('is-open'),
'Gutter menu is open'
);
click('[data-test-gutter-backdrop]');
return settled();
})
.then(() => {
assert.notOk(
find('[data-test-gutter-menu]').classList.contains('is-open'),
'Gutter menu is not open'
);
});
});
});

View file

@ -1,7 +1,6 @@
import { find, findAll } from 'ember-native-dom-helpers';
import { find, findAll, render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { assign } from '@ember/polyfills';
import hbs from 'htmlbars-inline-precompile';
import cleanWhitespace from '../utils/clean-whitespace';

View file

@ -2,9 +2,8 @@ import EmberObject, { computed } from '@ember/object';
import Service from '@ember/service';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { find } from 'ember-native-dom-helpers';
import { find, render } from '@ember/test-helpers';
import { task } from 'ember-concurrency';
import sinon from 'sinon';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
@ -57,125 +56,93 @@ module('Integration | Component | primary metric', function(hooks) {
metric=metric}}
`;
test('Contains a line chart, a percentage bar, a percentage figure, and an absolute usage figure', function(assert) {
test('Contains a line chart, a percentage bar, a percentage figure, and an absolute usage figure', async function(assert) {
let resource;
const metric = 'cpu';
this.store.findAll('node');
await this.store.findAll('node');
return settled()
.then(async () => {
resource = this.store.peekAll('node').get('firstObject');
this.setProperties({ resource, metric });
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(find('[data-test-line-chart]'), 'Line chart');
assert.ok(find('[data-test-percentage-bar]'), 'Percentage bar');
assert.ok(find('[data-test-percentage]'), 'Percentage figure');
assert.ok(find('[data-test-absolute-value]'), 'Absolute usage figure');
});
});
test('The CPU metric maps to is-info', function(assert) {
let resource;
test('The CPU metric maps to is-info', async function(assert) {
const metric = 'cpu';
this.store.findAll('node');
await this.store.findAll('node');
return settled()
.then(async () => {
resource = this.store.peekAll('node').get('firstObject');
const resource = this.store.peekAll('node').get('firstObject');
this.setProperties({ resource, metric });
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(
find('[data-test-line-chart] .canvas').classList.contains('is-info'),
'Info class for CPU metric'
);
});
});
test('The Memory metric maps to is-danger', function(assert) {
let resource;
test('The Memory metric maps to is-danger', async function(assert) {
const metric = 'memory';
this.store.findAll('node');
await this.store.findAll('node');
return settled()
.then(async () => {
resource = this.store.peekAll('node').get('firstObject');
const resource = this.store.peekAll('node').get('firstObject');
this.setProperties({ resource, metric });
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(
find('[data-test-line-chart] .canvas').classList.contains('is-danger'),
'Danger class for Memory metric'
);
});
});
test('Gets the tracker from the tracker registry', function(assert) {
let resource;
test('Gets the tracker from the tracker registry', async function(assert) {
const metric = 'cpu';
this.store.findAll('node');
await this.store.findAll('node');
return settled()
.then(async () => {
resource = this.store.peekAll('node').get('firstObject');
const resource = this.store.peekAll('node').get('firstObject');
this.setProperties({ resource, metric });
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(
this.getTrackerSpy.calledWith(resource),
'Uses the tracker registry to get the tracker for the provided resource'
);
});
});
test('Immediately polls the tracker', function(assert) {
let resource;
test('Immediately polls the tracker', async function(assert) {
const metric = 'cpu';
this.store.findAll('node');
await this.store.findAll('node');
return settled()
.then(async () => {
resource = this.store.peekAll('node').get('firstObject');
const resource = this.store.peekAll('node').get('firstObject');
this.setProperties({ resource, metric });
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(this.trackerPollSpy.calledOnce, 'The tracker is polled immediately');
});
});
test('A pause signal is sent to the tracker when the component is destroyed', function(assert) {
let resource;
test('A pause signal is sent to the tracker when the component is destroyed', async function(assert) {
const metric = 'cpu';
// Capture a reference to the spy before the component is destroyed
const trackerSignalPauseSpy = this.trackerSignalPauseSpy;
this.store.findAll('node');
await this.store.findAll('node');
return settled()
.then(async () => {
resource = this.store.peekAll('node').get('firstObject');
const resource = this.store.peekAll('node').get('firstObject');
this.setProperties({ resource, metric, showComponent: true });
await render(hbs`
{{#if showComponent}}
@ -185,16 +152,11 @@ module('Integration | Component | primary metric', function(hooks) {
}}
{{/if}}
`);
return settled();
})
.then(() => {
assert.notOk(trackerSignalPauseSpy.called, 'No pause signal has been sent yet');
// This will toggle the if statement, resulting the primary-metric component being destroyed.
this.set('showComponent', false);
return settled();
})
.then(() => {
assert.ok(trackerSignalPauseSpy.calledOnce, 'A pause signal is sent to the tracker');
});
});
});

View file

@ -1,7 +1,6 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { find, findAll } from 'ember-native-dom-helpers';
import { find, findAll, render } from '@ember/test-helpers';
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import hbs from 'htmlbars-inline-precompile';
import moment from 'moment';
@ -25,7 +24,7 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
{{reschedule-event-timeline allocation=allocation}}
`;
test('when the allocation is running, the timeline shows past allocations', function(assert) {
test('when the allocation is running, the timeline shows past allocations', async function(assert) {
const attempts = 2;
this.server.create('allocation', 'rescheduled', {
@ -33,21 +32,15 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
rescheduleSuccess: true,
});
this.store.findAll('allocation');
let allocation;
await this.store.findAll('allocation');
return settled()
.then(async () => {
allocation = this.store
const allocation = this.store
.peekAll('allocation')
.find(alloc => !alloc.get('nextAllocation.content'));
this.set('allocation', allocation);
await render(commonTemplate);
return settled();
})
.then(() => {
assert.equal(
findAll('[data-test-allocation]').length,
attempts + 1,
@ -77,9 +70,8 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
'Allocation shows the status'
);
});
});
test('when the allocation has failed and there is a follow up evaluation, a note with a time is shown', function(assert) {
test('when the allocation has failed and there is a follow up evaluation, a note with a time is shown', async function(assert) {
const attempts = 2;
this.server.create('allocation', 'rescheduled', {
@ -87,28 +79,21 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
rescheduleSuccess: false,
});
this.store.findAll('allocation');
let allocation;
await this.store.findAll('allocation');
return settled()
.then(async () => {
allocation = this.store
const allocation = this.store
.peekAll('allocation')
.find(alloc => !alloc.get('nextAllocation.content'));
this.set('allocation', allocation);
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(
find('[data-test-stop-warning]'),
'Stop warning is shown since the last allocation failed'
);
assert.notOk(find('[data-test-attempt-notice]'), 'Reschdule attempt notice is not shown');
});
});
test('when the allocation has failed and there is no follow up evaluation, a warning is shown', async function(assert) {
const attempts = 2;
@ -128,7 +113,6 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
});
await this.store.findAll('allocation');
await settled();
let allocation = this.store
.peekAll('allocation')
@ -136,7 +120,6 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
this.set('allocation', allocation);
await render(commonTemplate);
await settled();
assert.ok(
find('[data-test-attempt-notice]'),
@ -145,7 +128,7 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
assert.notOk(find('[data-test-stop-warning]'), 'Stop warning is not shown');
});
test('when the allocation has a next allocation already, it is shown in the timeline', function(assert) {
test('when the allocation has a next allocation already, it is shown in the timeline', async function(assert) {
const attempts = 2;
const originalAllocation = this.server.create('allocation', 'rescheduled', {
@ -153,19 +136,13 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
rescheduleSuccess: true,
});
this.store.findAll('allocation');
let allocation;
await this.store.findAll('allocation');
return settled()
.then(async () => {
allocation = this.store.peekAll('allocation').findBy('id', originalAllocation.id);
const allocation = this.store.peekAll('allocation').findBy('id', originalAllocation.id);
this.set('allocation', allocation);
await render(commonTemplate);
return settled();
})
.then(() => {
assert.ok(
find('[data-test-reschedule-label]').textContent.trim(),
'Next Allocation',
@ -188,4 +165,3 @@ module('Integration | Component | reschedule event timeline', function(hooks) {
assert.notOk(find('[data-test-attempt-notice]'), 'No attempt notice');
});
});
});

View file

@ -1,8 +1,7 @@
import { run } from '@ember/runloop';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import { find, click } from 'ember-native-dom-helpers';
import { find, click, render, settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import Pretender from 'pretender';
import { logEncode } from '../../mirage/data/logs';

View file

@ -1,7 +1,6 @@
import { find, click } from 'ember-native-dom-helpers';
import { find, click, render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import sinon from 'sinon';
import { create } from 'ember-cli-page-object';
@ -53,9 +52,8 @@ module('Integration | Component | two step button', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
TwoStepButton.idle();
await TwoStepButton.idle();
return settled().then(() => {
assert.ok(find('[data-test-cancel-button]'), 'Cancel button is rendered');
assert.equal(TwoStepButton.cancelText, props.cancelText, 'Button is labeled correctly');
@ -70,41 +68,32 @@ module('Integration | Component | two step button', function(hooks) {
assert.notOk(find('[data-test-idle-button]'), 'No more idle button');
});
});
test('canceling in the promptForConfirmation state calls the onCancel hook and resets to the idle state', async function(assert) {
const props = commonProperties();
this.setProperties(props);
await render(commonTemplate);
TwoStepButton.idle();
await TwoStepButton.idle();
return settled().then(() => {
TwoStepButton.cancel();
await TwoStepButton.cancel();
return settled().then(() => {
assert.ok(props.onCancel.calledOnce, 'The onCancel hook fired');
assert.ok(find('[data-test-idle-button]'), 'Idle button is back');
});
});
});
test('confirming the promptForConfirmation state calls the onConfirm hook and resets to the idle state', async function(assert) {
const props = commonProperties();
this.setProperties(props);
await render(commonTemplate);
TwoStepButton.idle();
await TwoStepButton.idle();
return settled().then(() => {
TwoStepButton.confirm();
await TwoStepButton.confirm();
return settled().then(() => {
assert.ok(props.onConfirm.calledOnce, 'The onConfirm hook fired');
assert.ok(find('[data-test-idle-button]'), 'Idle button is back');
});
});
});
test('when awaitingConfirmation is true, the cancel and submit buttons are disabled and the submit button is loading', async function(assert) {
const props = commonProperties();
@ -112,27 +101,23 @@ module('Integration | Component | two step button', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
TwoStepButton.idle();
await TwoStepButton.idle();
return settled().then(() => {
assert.ok(TwoStepButton.cancelIsDisabled, 'The cancel button is disabled');
assert.ok(TwoStepButton.confirmIsDisabled, 'The confirm button is disabled');
assert.ok(TwoStepButton.isRunning, 'The confirm button is in a loading state');
});
});
test('when in the prompt state, clicking outside will reset state back to idle', async function(assert) {
const props = commonProperties();
this.setProperties(props);
await render(commonTemplate);
TwoStepButton.idle();
await settled();
await TwoStepButton.idle();
assert.ok(find('[data-test-cancel-button]'), 'In the prompt state');
click(document.body);
await settled();
await click(document.body);
assert.ok(find('[data-test-idle-button]'), 'Back in the idle state');
});
@ -142,13 +127,11 @@ module('Integration | Component | two step button', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
TwoStepButton.idle();
await settled();
await TwoStepButton.idle();
assert.ok(find('[data-test-cancel-button]'), 'In the prompt state');
click('[data-test-confirmation-message]');
await settled();
await click('[data-test-confirmation-message]');
assert.notOk(find('[data-test-idle-button]'), 'Still in the prompt state');
});
@ -159,13 +142,11 @@ module('Integration | Component | two step button', function(hooks) {
this.setProperties(props);
await render(commonTemplate);
TwoStepButton.idle();
await settled();
await TwoStepButton.idle();
assert.ok(find('[data-test-cancel-button]'), 'In the prompt state');
click(document.body);
await settled();
await click(document.body);
assert.notOk(find('[data-test-idle-button]'), 'Still in the prompt state');
});
@ -178,7 +159,7 @@ module('Integration | Component | two step button', function(hooks) {
assert.ok(TwoStepButton.isDisabled, 'The idle button is disabled');
TwoStepButton.idle();
await TwoStepButton.idle();
assert.ok(find('[data-test-idle-button]'), 'Still in the idle state after clicking');
});
});

View file

@ -4824,7 +4824,7 @@ ember-moment@^7.8.1:
ember-getowner-polyfill "^2.2.0"
ember-macro-helpers "^2.1.0"
ember-native-dom-helpers@^0.5.3, ember-native-dom-helpers@^0.5.4:
ember-native-dom-helpers@^0.5.3:
version "0.5.10"
resolved "https://registry.yarnpkg.com/ember-native-dom-helpers/-/ember-native-dom-helpers-0.5.10.tgz#9c7172e4ddfa5dd86830c46a936e2f8eca3e5896"
integrity sha512-bPJX49vlgnBGwFn/3WJPPJjjyd7/atvzW5j01u1dbyFf3bXvHg9Rs1qaZJdk8js0qZ1FINadIEC9vWtgN3w7tg==