github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/tests/integration/components/job-page/periodic-test.js (about) 1 import { module, test } from 'qunit'; 2 import { setupRenderingTest } from 'ember-qunit'; 3 import { click, find, findAll, render } from '@ember/test-helpers'; 4 import hbs from 'htmlbars-inline-precompile'; 5 import moment from 'moment'; 6 import { create, collection } from 'ember-cli-page-object'; 7 import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; 8 import pageSizeSelect from 'nomad-ui/tests/acceptance/behaviors/page-size-select'; 9 import pageSizeSelectPageObject from 'nomad-ui/tests/pages/components/page-size-select'; 10 import { 11 jobURL, 12 stopJob, 13 startJob, 14 purgeJob, 15 expectError, 16 expectDeleteRequest, 17 expectStartRequest, 18 expectPurgeRequest, 19 } from './helpers'; 20 import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; 21 22 // A minimum viable page object to use with the pageSizeSelect behavior 23 const PeriodicJobPage = create({ 24 pageSize: 25, 25 jobs: collection('[data-test-job-row]'), 26 pageSizeSelect: pageSizeSelectPageObject(), 27 }); 28 29 module('Integration | Component | job-page/periodic', function (hooks) { 30 setupRenderingTest(hooks); 31 32 hooks.beforeEach(function () { 33 window.localStorage.clear(); 34 this.store = this.owner.lookup('service:store'); 35 this.server = startMirage(); 36 this.server.create('namespace'); 37 }); 38 39 hooks.afterEach(function () { 40 this.server.shutdown(); 41 window.localStorage.clear(); 42 }); 43 44 const commonTemplate = hbs` 45 <JobPage::Periodic 46 @job={{job}} 47 @sortProperty={{sortProperty}} 48 @sortDescending={{sortDescending}} 49 @currentPage={{currentPage}} 50 /> 51 `; 52 53 const commonProperties = (job) => ({ 54 job, 55 sortProperty: 'name', 56 sortDescending: true, 57 currentPage: 1, 58 }); 59 60 test('Clicking Force Launch launches a new periodic child job', async function (assert) { 61 const childrenCount = 3; 62 63 this.server.create('job', 'periodic', { 64 id: 'parent', 65 childrenCount, 66 createAllocations: false, 67 }); 68 69 await this.store.findAll('job'); 70 71 const job = this.store.peekAll('job').findBy('plainId', 'parent'); 72 73 this.setProperties(commonProperties(job)); 74 await render(commonTemplate); 75 76 const currentJobCount = server.db.jobs.length; 77 78 assert.equal( 79 findAll('[data-test-job-row] [data-test-job-name]').length, 80 childrenCount, 81 'The new periodic job launch is in the children list' 82 ); 83 84 await click('[data-test-force-launch]'); 85 86 const expectedURL = jobURL(job, '/periodic/force'); 87 88 assert.ok( 89 this.server.pretender.handledRequests 90 .filterBy('method', 'POST') 91 .find((req) => req.url === expectedURL), 92 'POST URL was correct' 93 ); 94 95 assert.equal( 96 server.db.jobs.length, 97 currentJobCount + 1, 98 'POST request was made' 99 ); 100 }); 101 102 test('Clicking force launch without proper permissions shows an error message', async function (assert) { 103 this.server.pretender.post('/v1/job/:id/periodic/force', () => [ 104 403, 105 {}, 106 '', 107 ]); 108 109 this.server.create('job', 'periodic', { 110 id: 'parent', 111 childrenCount: 1, 112 createAllocations: false, 113 status: 'running', 114 }); 115 116 await this.store.findAll('job'); 117 118 const job = this.store.peekAll('job').findBy('plainId', 'parent'); 119 120 this.setProperties(commonProperties(job)); 121 await render(commonTemplate); 122 123 assert.notOk(find('[data-test-job-error-title]'), 'No error message yet'); 124 125 await click('[data-test-force-launch]'); 126 127 assert.equal( 128 find('[data-test-job-error-title]').textContent, 129 'Could Not Force Launch', 130 'Appropriate error is shown' 131 ); 132 assert.ok( 133 find('[data-test-job-error-body]').textContent.includes('ACL'), 134 'The error message mentions ACLs' 135 ); 136 137 await click('[data-test-job-error-close]'); 138 139 assert.notOk( 140 find('[data-test-job-error-title]'), 141 'Error message is dismissable' 142 ); 143 }); 144 145 test('Stopping a job sends a delete request for the job', async function (assert) { 146 assert.expect(1); 147 148 const mirageJob = this.server.create('job', 'periodic', { 149 childrenCount: 0, 150 createAllocations: false, 151 status: 'running', 152 }); 153 154 let job; 155 await this.store.findAll('job'); 156 157 job = this.store.peekAll('job').findBy('plainId', mirageJob.id); 158 159 this.setProperties(commonProperties(job)); 160 await render(commonTemplate); 161 await stopJob(); 162 163 expectDeleteRequest(assert, this.server, job); 164 }); 165 166 test('Stopping a job without proper permissions shows an error message', async function (assert) { 167 assert.expect(4); 168 169 this.server.pretender.delete('/v1/job/:id', () => [403, {}, '']); 170 171 const mirageJob = this.server.create('job', 'periodic', { 172 childrenCount: 0, 173 createAllocations: false, 174 status: 'running', 175 }); 176 177 await this.store.findAll('job'); 178 179 const job = this.store.peekAll('job').findBy('plainId', mirageJob.id); 180 181 this.setProperties(commonProperties(job)); 182 await render(commonTemplate); 183 184 await stopJob(); 185 expectError(assert, 'Could Not Stop Job'); 186 187 await componentA11yAudit(this.element, assert); 188 }); 189 190 test('Starting a job sends a post request for the job using the current definition', async function (assert) { 191 assert.expect(2); 192 193 const mirageJob = this.server.create('job', 'periodic', { 194 childrenCount: 0, 195 createAllocations: false, 196 status: 'dead', 197 }); 198 await this.store.findAll('job'); 199 200 const job = this.store.peekAll('job').findBy('plainId', mirageJob.id); 201 202 this.setProperties(commonProperties(job)); 203 await render(commonTemplate); 204 205 await startJob(); 206 expectStartRequest(assert, this.server, job); 207 }); 208 209 test('Starting a job without proper permissions shows an error message', async function (assert) { 210 assert.expect(3); 211 212 this.server.pretender.post('/v1/job/:id', () => [403, {}, '']); 213 214 const mirageJob = this.server.create('job', 'periodic', { 215 childrenCount: 0, 216 createAllocations: false, 217 status: 'dead', 218 }); 219 await this.store.findAll('job'); 220 221 const job = this.store.peekAll('job').findBy('plainId', mirageJob.id); 222 223 this.setProperties(commonProperties(job)); 224 await render(commonTemplate); 225 226 await startJob(); 227 228 await expectError(assert, 'Could Not Start Job'); 229 }); 230 231 test('Purging a job sends a purge request for the job', async function (assert) { 232 assert.expect(1); 233 234 const mirageJob = this.server.create('job', 'periodic', { 235 childrenCount: 0, 236 createAllocations: false, 237 status: 'dead', 238 }); 239 await this.store.findAll('job'); 240 241 const job = this.store.peekAll('job').findBy('plainId', mirageJob.id); 242 243 this.setProperties(commonProperties(job)); 244 await render(commonTemplate); 245 246 await purgeJob(); 247 expectPurgeRequest(assert, this.server, job); 248 }); 249 250 test('Each job row includes the submitted time', async function (assert) { 251 this.server.create('job', 'periodic', { 252 id: 'parent', 253 childrenCount: 1, 254 createAllocations: false, 255 }); 256 257 await this.store.findAll('job'); 258 259 const job = this.store.peekAll('job').findBy('plainId', 'parent'); 260 261 this.setProperties(commonProperties(job)); 262 await render(commonTemplate); 263 264 assert.equal( 265 find('[data-test-job-submit-time]').textContent.trim(), 266 moment(job.get('children.firstObject.submitTime')).format( 267 'MMM DD HH:mm:ss ZZ' 268 ), 269 'The new periodic job launch is in the children list' 270 ); 271 }); 272 273 pageSizeSelect({ 274 resourceName: 'job', 275 pageObject: PeriodicJobPage, 276 pageObjectList: PeriodicJobPage.jobs, 277 async setup() { 278 this.server.create('job', 'periodic', { 279 id: 'parent', 280 childrenCount: PeriodicJobPage.pageSize, 281 createAllocations: false, 282 }); 283 284 await this.store.findAll('job'); 285 286 const job = this.store.peekAll('job').findBy('plainId', 'parent'); 287 288 this.setProperties(commonProperties(job)); 289 await render(commonTemplate); 290 }, 291 }); 292 });