github.com/hernad/nomad@v1.6.112/ui/tests/acceptance/task-logs-test.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 /* eslint-disable qunit/require-expect */ 7 import { 8 click, 9 currentURL, 10 findAll, 11 triggerKeyEvent, 12 } from '@ember/test-helpers'; 13 import { run } from '@ember/runloop'; 14 import { module, test } from 'qunit'; 15 import { setupApplicationTest } from 'ember-qunit'; 16 import { setupMirage } from 'ember-cli-mirage/test-support'; 17 import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; 18 import TaskLogs from 'nomad-ui/tests/pages/allocations/task/logs'; 19 import percySnapshot from '@percy/ember'; 20 import faker from 'nomad-ui/mirage/faker'; 21 22 let allocation; 23 let task; 24 let job; 25 26 module('Acceptance | task logs', function (hooks) { 27 setupApplicationTest(hooks); 28 setupMirage(hooks); 29 30 hooks.beforeEach(async function () { 31 faker.seed(1); 32 server.create('agent'); 33 server.create('node-pool'); 34 server.create('node', 'forceIPv4'); 35 job = server.create('job', { createAllocations: false }); 36 37 allocation = server.create('allocation', { 38 jobId: job.id, 39 clientStatus: 'running', 40 }); 41 task = server.db.taskStates.where({ allocationId: allocation.id })[0]; 42 43 run.later(run, run.cancelTimers, 1000); 44 }); 45 46 test('it passes an accessibility audit', async function (assert) { 47 await TaskLogs.visit({ id: allocation.id, name: task.name }); 48 await a11yAudit(assert); 49 await percySnapshot(assert); 50 }); 51 52 test('/allocation/:id/:task_name/logs should have a log component', async function (assert) { 53 await TaskLogs.visit({ id: allocation.id, name: task.name }); 54 assert.equal( 55 currentURL(), 56 `/allocations/${allocation.id}/${task.name}/logs`, 57 'No redirect' 58 ); 59 assert.ok(TaskLogs.hasTaskLog, 'Task log component found'); 60 assert.ok(document.title.includes(`Task ${task.name}`)); 61 }); 62 63 test('the stdout log immediately starts streaming', async function (assert) { 64 await TaskLogs.visit({ id: allocation.id, name: task.name }); 65 const node = server.db.nodes.find(allocation.nodeId); 66 const logUrlRegex = new RegExp( 67 `${node.httpAddr}/v1/client/fs/logs/${allocation.id}` 68 ); 69 assert.ok( 70 server.pretender.handledRequests.filter((req) => 71 logUrlRegex.test(req.url) 72 ).length, 73 'Log requests were made' 74 ); 75 }); 76 77 test('logs can be word-wrapped', async function (assert) { 78 await TaskLogs.visit({ id: allocation.id, name: task.name }); 79 80 assert.dom('[data-test-word-wrap-toggle]').isNotChecked(); 81 assert.dom('[data-test-output]').doesNotHaveClass('wrapped'); 82 83 run.later(() => { 84 run.cancelTimers(); 85 }, 100); 86 await click('[data-test-word-wrap-toggle]'); 87 assert.dom('[data-test-word-wrap-toggle]').isChecked(); 88 assert.dom('[data-test-output]').hasClass('wrapped'); 89 90 run.later(() => { 91 run.cancelTimers(); 92 }, 100); 93 await click('[data-test-word-wrap-toggle]'); 94 assert.dom('[data-test-word-wrap-toggle]').isNotChecked(); 95 assert.dom('[data-test-output]').doesNotHaveClass('wrapped'); 96 97 window.localStorage.clear(); 98 }); 99 100 test('logs in sidebar can be word-wrapped', async function (assert) { 101 await TaskLogs.visitParentJob({ 102 id: job.id, 103 allocationId: allocation.id, 104 name: task.name, 105 }); 106 107 run.later(() => { 108 run.cancelTimers(); 109 }, 500); 110 111 const taskRow = [ 112 ...findAll('.task-sub-row').filter((row) => { 113 return row.textContent.includes(task.name); 114 }), 115 ][0]; 116 117 await click(taskRow.querySelector('button.logs-sidebar-trigger')); 118 119 assert.dom('[data-test-word-wrap-toggle]').isNotChecked(); 120 assert.dom('[data-test-output]').doesNotHaveClass('wrapped'); 121 122 run.later(() => { 123 run.cancelTimers(); 124 }, 500); 125 126 // type "ww" to trigger word wrap 127 const W_KEY = 87; 128 triggerKeyEvent('.sidebar', 'keydown', W_KEY); 129 await triggerKeyEvent('.sidebar', 'keydown', W_KEY); 130 131 assert.dom('[data-test-word-wrap-toggle]').isChecked(); 132 assert.dom('[data-test-output]').hasClass('wrapped'); 133 134 run.later(() => { 135 run.cancelTimers(); 136 }, 100); 137 138 triggerKeyEvent('.sidebar', 'keydown', W_KEY); 139 await triggerKeyEvent('.sidebar', 'keydown', W_KEY); 140 assert.dom('[data-test-word-wrap-toggle]').isNotChecked(); 141 assert.dom('[data-test-output]').doesNotHaveClass('wrapped'); 142 143 window.localStorage.clear(); 144 }); 145 146 test('logs are accessible in a sidebar context', async function (assert) { 147 await TaskLogs.visitParentJob({ 148 id: job.id, 149 allocationId: allocation.id, 150 name: task.name, 151 }); 152 assert.notOk(TaskLogs.sidebarIsPresent, 'Sidebar is not present'); 153 154 run.later(() => { 155 run.cancelTimers(); 156 }, 500); 157 158 const taskRow = [ 159 ...findAll('.task-sub-row').filter((row) => { 160 return row.textContent.includes(task.name); 161 }), 162 ][0]; 163 164 await click(taskRow.querySelector('button.logs-sidebar-trigger')); 165 166 assert.ok(TaskLogs.sidebarIsPresent, 'Sidebar is present'); 167 assert 168 .dom('.task-context-sidebar h1.title') 169 .includesText(task.name, 'Sidebar title is correct'); 170 assert 171 .dom('.task-context-sidebar h1.title') 172 .includesText(task.state, 'Task state is correctly displayed'); 173 await percySnapshot(assert, { 174 percyCSS: ` 175 .allocation-row td { display: none; } 176 .task-events table td:nth-child(1) { color: transparent; } 177 `, 178 }); 179 180 await click('.sidebar button.close'); 181 assert.notOk(TaskLogs.sidebarIsPresent, 'Sidebar is not present'); 182 }); 183 });