github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/tests/acceptance/job-versions-test.js (about) 1 /* eslint-disable qunit/require-expect */ 2 /* eslint-disable qunit/no-conditional-assertions */ 3 import { currentURL } from '@ember/test-helpers'; 4 import { module, test } from 'qunit'; 5 import { setupApplicationTest } from 'ember-qunit'; 6 import { setupMirage } from 'ember-cli-mirage/test-support'; 7 import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; 8 import Versions from 'nomad-ui/tests/pages/jobs/job/versions'; 9 import Layout from 'nomad-ui/tests/pages/layout'; 10 import moment from 'moment'; 11 12 let job; 13 let namespace; 14 let versions; 15 16 module('Acceptance | job versions', function (hooks) { 17 setupApplicationTest(hooks); 18 setupMirage(hooks); 19 20 hooks.beforeEach(async function () { 21 server.create('namespace'); 22 namespace = server.create('namespace'); 23 24 job = server.create('job', { 25 namespaceId: namespace.id, 26 createAllocations: false, 27 }); 28 versions = server.db.jobVersions.where({ jobId: job.id }); 29 30 const managementToken = server.create('token'); 31 window.localStorage.nomadTokenSecret = managementToken.secretId; 32 33 await Versions.visit({ id: `${job.id}@${namespace.id}` }); 34 }); 35 36 test('it passes an accessibility audit', async function (assert) { 37 await a11yAudit(assert); 38 }); 39 40 test('/jobs/:id/versions should list all job versions', async function (assert) { 41 assert.equal( 42 Versions.versions.length, 43 versions.length, 44 'Each version gets a row in the timeline' 45 ); 46 assert.equal(document.title, `Job ${job.name} versions - Nomad`); 47 }); 48 49 test('each version mentions the version number, the stability, and the submitted time', async function (assert) { 50 const version = versions.sortBy('submitTime').reverse()[0]; 51 const formattedSubmitTime = moment(version.submitTime / 1000000).format( 52 "MMM DD, 'YY HH:mm:ss ZZ" 53 ); 54 const versionRow = Versions.versions.objectAt(0); 55 56 assert.ok( 57 versionRow.text.includes(`Version #${version.version}`), 58 'Version #' 59 ); 60 assert.equal(versionRow.stability, version.stable.toString(), 'Stability'); 61 assert.equal(versionRow.submitTime, formattedSubmitTime, 'Submit time'); 62 }); 63 64 test('all versions but the current one have a button to revert to that version', async function (assert) { 65 let versionRowToRevertTo; 66 67 Versions.versions.forEach((versionRow) => { 68 if (versionRow.number === job.version) { 69 assert.ok(versionRow.revertToButton.isHidden); 70 } else { 71 assert.ok(versionRow.revertToButton.isPresent); 72 73 versionRowToRevertTo = versionRow; 74 } 75 }); 76 77 if (versionRowToRevertTo) { 78 const versionNumberRevertingTo = versionRowToRevertTo.number; 79 await versionRowToRevertTo.revertToButton.idle(); 80 await versionRowToRevertTo.revertToButton.confirm(); 81 82 const revertRequest = this.server.pretender.handledRequests.find( 83 (request) => request.url.includes('revert') 84 ); 85 86 assert.equal( 87 revertRequest.url, 88 `/v1/job/${job.id}/revert?namespace=${namespace.id}` 89 ); 90 91 assert.deepEqual(JSON.parse(revertRequest.requestBody), { 92 JobID: job.id, 93 JobVersion: versionNumberRevertingTo, 94 }); 95 96 assert.equal(currentURL(), `/jobs/${job.id}?namespace=${namespace.id}`); 97 } 98 }); 99 100 test('when reversion fails, the error message from the API is piped through to the alert', async function (assert) { 101 const versionRowToRevertTo = Versions.versions.filter( 102 (versionRow) => versionRow.revertToButton.isPresent 103 )[0]; 104 105 if (versionRowToRevertTo) { 106 const message = 'A plaintext error message'; 107 server.pretender.post('/v1/job/:id/revert', () => [500, {}, message]); 108 109 await versionRowToRevertTo.revertToButton.idle(); 110 await versionRowToRevertTo.revertToButton.confirm(); 111 112 assert.ok(Layout.inlineError.isShown); 113 assert.ok(Layout.inlineError.isDanger); 114 assert.ok(Layout.inlineError.title.includes('Could Not Revert')); 115 assert.equal(Layout.inlineError.message, message); 116 117 await Layout.inlineError.dismiss(); 118 119 assert.notOk(Layout.inlineError.isShown); 120 } else { 121 assert.expect(0); 122 } 123 }); 124 125 test('when reversion has no effect, the error message explains', async function (assert) { 126 const versionRowToRevertTo = Versions.versions.filter( 127 (versionRow) => versionRow.revertToButton.isPresent 128 )[0]; 129 130 if (versionRowToRevertTo) { 131 // The default Mirage implementation updates the job version as passed in, this does nothing 132 server.pretender.post('/v1/job/:id/revert', () => [200, {}, '{}']); 133 134 await versionRowToRevertTo.revertToButton.idle(); 135 await versionRowToRevertTo.revertToButton.confirm(); 136 137 assert.ok(Layout.inlineError.isShown); 138 assert.ok(Layout.inlineError.isWarning); 139 assert.ok(Layout.inlineError.title.includes('Reversion Had No Effect')); 140 assert.equal( 141 Layout.inlineError.message, 142 'Reverting to an identical older version doesn’t produce a new version' 143 ); 144 } else { 145 assert.expect(0); 146 } 147 }); 148 149 test('when the job for the versions is not found, an error message is shown, but the URL persists', async function (assert) { 150 await Versions.visit({ id: 'not-a-real-job' }); 151 152 assert.equal( 153 server.pretender.handledRequests 154 .filter((request) => !request.url.includes('policy')) 155 .findBy('status', 404).url, 156 '/v1/job/not-a-real-job', 157 'A request to the nonexistent job is made' 158 ); 159 assert.equal( 160 currentURL(), 161 '/jobs/not-a-real-job/versions', 162 'The URL persists' 163 ); 164 assert.ok(Versions.error.isPresent, 'Error message is shown'); 165 assert.equal(Versions.error.title, 'Not Found', 'Error message is for 404'); 166 }); 167 }); 168 169 module('Acceptance | job versions (with client token)', function (hooks) { 170 setupApplicationTest(hooks); 171 setupMirage(hooks); 172 173 hooks.beforeEach(async function () { 174 job = server.create('job', { createAllocations: false }); 175 versions = server.db.jobVersions.where({ jobId: job.id }); 176 177 server.create('token'); 178 const clientToken = server.create('token'); 179 window.localStorage.nomadTokenSecret = clientToken.secretId; 180 181 await Versions.visit({ id: job.id }); 182 }); 183 184 test('reversion buttons are disabled when the token lacks permissions', async function (assert) { 185 const versionRowWithReversion = Versions.versions.filter( 186 (versionRow) => versionRow.revertToButton.isPresent 187 )[0]; 188 189 if (versionRowWithReversion) { 190 assert.ok(versionRowWithReversion.revertToButtonIsDisabled); 191 } else { 192 assert.expect(0); 193 } 194 195 window.localStorage.clear(); 196 }); 197 198 test('reversion buttons are available when the client token has permissions', async function (assert) { 199 const REVERT_NAMESPACE = 'revert-namespace'; 200 window.localStorage.clear(); 201 const clientToken = server.create('token'); 202 203 server.create('namespace', { id: REVERT_NAMESPACE }); 204 205 const job = server.create('job', { 206 groupCount: 0, 207 createAllocations: false, 208 shallow: true, 209 noActiveDeployment: true, 210 namespaceId: REVERT_NAMESPACE, 211 }); 212 213 const policy = server.create('policy', { 214 id: 'something', 215 name: 'something', 216 rulesJSON: { 217 Namespaces: [ 218 { 219 Name: REVERT_NAMESPACE, 220 Capabilities: ['submit-job'], 221 }, 222 ], 223 }, 224 }); 225 226 clientToken.policyIds = [policy.id]; 227 clientToken.save(); 228 229 window.localStorage.nomadTokenSecret = clientToken.secretId; 230 231 versions = server.db.jobVersions.where({ jobId: job.id }); 232 await Versions.visit({ id: job.id, namespace: REVERT_NAMESPACE }); 233 const versionRowWithReversion = Versions.versions.filter( 234 (versionRow) => versionRow.revertToButton.isPresent 235 )[0]; 236 237 if (versionRowWithReversion) { 238 assert.ok(versionRowWithReversion.revertToButtonIsDisabled); 239 } else { 240 assert.expect(0); 241 } 242 }); 243 });