90ecbdf522
This adds a Revert two-step button to the JobVersions component for not-current versions, which redirects to the overview on success. It checks the job version before and after reversion to mitigate the edge case where reverting to an otherwise-identical version has no effect, as discussed in #10337. It uses existing facilities for handling other errors and disabling the button when permissions are lacking.
168 lines
6.2 KiB
JavaScript
168 lines
6.2 KiB
JavaScript
import { currentURL } from '@ember/test-helpers';
|
||
import { module, test } from 'qunit';
|
||
import { setupApplicationTest } from 'ember-qunit';
|
||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
|
||
import Versions from 'nomad-ui/tests/pages/jobs/job/versions';
|
||
import Layout from 'nomad-ui/tests/pages/layout';
|
||
import moment from 'moment';
|
||
|
||
let job;
|
||
let namespace;
|
||
let versions;
|
||
|
||
module('Acceptance | job versions', function(hooks) {
|
||
setupApplicationTest(hooks);
|
||
setupMirage(hooks);
|
||
|
||
hooks.beforeEach(async function() {
|
||
server.create('namespace');
|
||
namespace = server.create('namespace');
|
||
|
||
job = server.create('job', { namespaceId: namespace.id, createAllocations: false });
|
||
versions = server.db.jobVersions.where({ jobId: job.id });
|
||
|
||
const managementToken = server.create('token');
|
||
window.localStorage.nomadTokenSecret = managementToken.secretId;
|
||
|
||
await Versions.visit({ id: job.id, namespace: namespace.id });
|
||
});
|
||
|
||
test('it passes an accessibility audit', async function(assert) {
|
||
await a11yAudit(assert);
|
||
});
|
||
|
||
test('/jobs/:id/versions should list all job versions', async function(assert) {
|
||
assert.ok(Versions.versions.length, versions.length, 'Each version gets a row in the timeline');
|
||
assert.equal(document.title, `Job ${job.name} versions - Nomad`);
|
||
});
|
||
|
||
test('each version mentions the version number, the stability, and the submitted time', async function(assert) {
|
||
const version = versions.sortBy('submitTime').reverse()[0];
|
||
const formattedSubmitTime = moment(version.submitTime / 1000000).format(
|
||
"MMM DD, 'YY HH:mm:ss ZZ"
|
||
);
|
||
const versionRow = Versions.versions.objectAt(0);
|
||
|
||
assert.ok(versionRow.text.includes(`Version #${version.version}`), 'Version #');
|
||
assert.equal(versionRow.stability, version.stable.toString(), 'Stability');
|
||
assert.equal(versionRow.submitTime, formattedSubmitTime, 'Submit time');
|
||
});
|
||
|
||
test('all versions but the current one have a button to revert to that version', async function(assert) {
|
||
let versionRowToRevertTo;
|
||
|
||
Versions.versions.forEach((versionRow) => {
|
||
if (versionRow.number === job.version) {
|
||
assert.ok(versionRow.revertToButton.isHidden);
|
||
} else {
|
||
assert.ok(versionRow.revertToButton.isPresent);
|
||
|
||
versionRowToRevertTo = versionRow;
|
||
}
|
||
});
|
||
|
||
if (versionRowToRevertTo) {
|
||
const versionNumberRevertingTo = versionRowToRevertTo.number;
|
||
await versionRowToRevertTo.revertToButton.idle();
|
||
await versionRowToRevertTo.revertToButton.confirm();
|
||
|
||
const revertRequest = this.server.pretender.handledRequests.find(request => request.url.includes('revert'));
|
||
|
||
assert.equal(revertRequest.url, `/v1/job/${job.id}/revert?namespace=${namespace.id}`);
|
||
|
||
assert.deepEqual(JSON.parse(revertRequest.requestBody), {
|
||
JobID: job.id,
|
||
JobVersion: versionNumberRevertingTo,
|
||
});
|
||
|
||
assert.equal(currentURL(), `/jobs/${job.id}?namespace=${namespace.id}`);
|
||
}
|
||
});
|
||
|
||
test('when reversion fails, the error message from the API is piped through to the alert', async function(assert) {
|
||
const versionRowToRevertTo = Versions.versions.filter(versionRow => versionRow.revertToButton.isPresent)[0];
|
||
|
||
if (versionRowToRevertTo) {
|
||
const message = 'A plaintext error message';
|
||
server.pretender.post('/v1/job/:id/revert', () => [500, {}, message]);
|
||
|
||
await versionRowToRevertTo.revertToButton.idle();
|
||
await versionRowToRevertTo.revertToButton.confirm();
|
||
|
||
assert.ok(Layout.inlineError.isShown);
|
||
assert.ok(Layout.inlineError.isDanger);
|
||
assert.ok(Layout.inlineError.title.includes('Could Not Revert'));
|
||
assert.equal(Layout.inlineError.message, message);
|
||
|
||
await Layout.inlineError.dismiss();
|
||
|
||
assert.notOk(Layout.inlineError.isShown);
|
||
} else {
|
||
assert.expect(0);
|
||
}
|
||
});
|
||
|
||
test('when reversion has no effect, the error message explains', async function(assert) {
|
||
const versionRowToRevertTo = Versions.versions.filter(versionRow => versionRow.revertToButton.isPresent)[0];
|
||
|
||
if (versionRowToRevertTo) {
|
||
// The default Mirage implementation updates the job version as passed in, this does nothing
|
||
server.pretender.post('/v1/job/:id/revert', () => [200, {}, '']);
|
||
|
||
await versionRowToRevertTo.revertToButton.idle();
|
||
await versionRowToRevertTo.revertToButton.confirm();
|
||
|
||
assert.ok(Layout.inlineError.isShown);
|
||
assert.ok(Layout.inlineError.isWarning);
|
||
assert.ok(Layout.inlineError.title.includes('Reversion Had No Effect'));
|
||
assert.equal(Layout.inlineError.message, 'Reverting to an identical older version doesn’t produce a new version');
|
||
} else {
|
||
assert.expect(0);
|
||
}
|
||
});
|
||
|
||
test('when the job for the versions is not found, an error message is shown, but the URL persists', async function(assert) {
|
||
await Versions.visit({ id: 'not-a-real-job' });
|
||
|
||
assert.equal(
|
||
server.pretender.handledRequests
|
||
.filter(request => !request.url.includes('policy'))
|
||
.findBy('status', 404).url,
|
||
'/v1/job/not-a-real-job',
|
||
'A request to the nonexistent job is made'
|
||
);
|
||
assert.equal(currentURL(), '/jobs/not-a-real-job/versions', 'The URL persists');
|
||
assert.ok(Versions.error.isPresent, 'Error message is shown');
|
||
assert.equal(Versions.error.title, 'Not Found', 'Error message is for 404');
|
||
});
|
||
});
|
||
|
||
module('Acceptance | job versions (with client token)', function(hooks) {
|
||
setupApplicationTest(hooks);
|
||
setupMirage(hooks);
|
||
|
||
hooks.beforeEach(async function() {
|
||
job = server.create('job', { createAllocations: false });
|
||
versions = server.db.jobVersions.where({ jobId: job.id });
|
||
|
||
server.create('token');
|
||
const clientToken = server.create('token');
|
||
window.localStorage.nomadTokenSecret = clientToken.secretId;
|
||
|
||
await Versions.visit({ id: job.id });
|
||
});
|
||
|
||
test('reversion buttons are disabled when the token lacks permissions', async function(assert) {
|
||
const versionRowWithReversion = Versions.versions.filter(versionRow => versionRow.revertToButton.isPresent)[0];
|
||
|
||
if (versionRowWithReversion) {
|
||
assert.ok(versionRowWithReversion.revertToButtonIsDisabled);
|
||
} else {
|
||
assert.expect(0);
|
||
}
|
||
|
||
window.localStorage.clear();
|
||
});
|
||
});
|