ui: fix remaining linting errors

This commit is contained in:
Jai Bhagat 2022-01-20 10:39:02 -05:00
parent 3350f3fb11
commit 52cf998e2c
25 changed files with 426 additions and 353 deletions

View file

@ -21,14 +21,14 @@ export default class Client extends AbstractAbility {
get policiesIncludeNodeRead() {
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [
'read',
'write'
'write',
]);
}
@computed('token.selfTokenPolicies.[]')
get policiesIncludeNodeWrite() {
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [
'write'
'write',
]);
}
}
@ -37,9 +37,9 @@ function policiesIncludePermissions(policies = [], permissions = []) {
// For each policy record, extract the Node policy
const nodePolicies = policies
.toArray()
.map(policy => get(policy, 'rulesJSON.Node.Policy'))
.map((policy) => get(policy, 'rulesJSON.Node.Policy'))
.compact();
// Check for requested permissions
return nodePolicies.some(policy => permissions.includes(policy));
return nodePolicies.some((policy) => permissions.includes(policy));
}

View file

@ -49,7 +49,7 @@ export default class Trigger extends Component {
this.error = null;
}
@task(function*() {
@task(function* () {
this._reset();
try {
this.result = yield this.args.do();

View file

@ -35,7 +35,12 @@ export default class AllocationsAllocationController extends Controller {
{
title: 'Task Group',
label: allocation.taskGroupName,
args: ['jobs.job.task-group', job.plainId, allocation.taskGroupName, jobQueryParams],
args: [
'jobs.job.task-group',
job.plainId,
allocation.taskGroupName,
jobQueryParams,
],
},
{
title: 'Allocation',

View file

@ -9,7 +9,11 @@ export default class AllocationsAllocationTaskController extends Controller {
return {
title: 'Task',
label: this.task.get('name'),
args: ['allocations.allocation.task', this.task.get('allocation'), this.task],
args: [
'allocations.allocation.task',
this.task.get('allocation'),
this.task,
],
};
}
}

View file

@ -25,7 +25,9 @@ export default class VolumeController extends Controller {
label: 'Volumes',
args: [
'csi.volumes',
qpBuilder({ volumeNamespace: volume.get('namespace.name') || 'default' }),
qpBuilder({
volumeNamespace: volume.get('namespace.name') || 'default',
}),
],
},
{
@ -33,7 +35,9 @@ export default class VolumeController extends Controller {
args: [
'csi.volumes.volume',
volume.plainId,
qpBuilder({ volumeNamespace: volume.get('namespace.name') || 'default' }),
qpBuilder({
volumeNamespace: volume.get('namespace.name') || 'default',
}),
],
},
];

View file

@ -35,9 +35,7 @@ export default class Allocation extends Model {
@attr('string') nodeName;
@computed
get shortNodeId() {
return this.belongsTo('node')
.id()
.split('-')[0];
return this.belongsTo('node').id().split('-')[0];
}
@attr('number') modifyIndex;

View file

@ -17,7 +17,7 @@ export default class AllocationRoute extends Route.extend(WithWatchers) {
// Preload the job for the allocation since it's required for the breadcrumb trail
return super
.model(...arguments)
.then(allocation =>
.then((allocation) =>
allocation
.get('job')
.then(() => this.store.findAll('namespace')) // namespaces belong to a job and are an asynchronous relationship so we can peak them later on

View file

@ -16,7 +16,7 @@ export default class VolumeRoute extends Route.extend(WithWatchers) {
if (!model) return;
controller.set('watchers', {
model: this.watch.perform(model)
model: this.watch.perform(model),
});
}
@ -30,9 +30,9 @@ export default class VolumeRoute extends Route.extend(WithWatchers) {
const fullId = JSON.stringify([`csi/${name}`, namespace || 'default']);
return RSVP.hash({
volume: this.store.findRecord('volume', fullId, { reload: true }),
namespaces: this.store.findAll('namespace')
namespaces: this.store.findAll('namespace'),
})
.then(hash => hash.volume)
.then((hash) => hash.volume)
.catch(notifyError(this));
}

View file

@ -5,7 +5,7 @@ import {
watchRecord,
watchRelationship,
watchAll,
watchQuery
watchQuery,
} from 'nomad-ui/utils/properties/watch';
import WithWatchers from 'nomad-ui/mixins/with-watchers';
@ -43,12 +43,12 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
list:
model.job.get('hasChildren') &&
this.watchAllJobs.perform({
namespace: model.job.namespace.get('name')
namespace: model.job.namespace.get('name'),
}),
nodes:
this.can.can('read client') &&
model.job.get('hasClientStatus') &&
this.watchNodes.perform()
this.watchNodes.perform(),
});
}
@ -61,7 +61,7 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
) {
controller.setProperties({
sortProperty: 'submitTime',
sortDescending: true
sortDescending: true,
});
}
return super.setupController(...arguments);

View file

@ -4,7 +4,7 @@ import EmberError from '@ember/error';
import { resolve, all } from 'rsvp';
import {
watchRecord,
watchRelationship
watchRelationship,
} from 'nomad-ui/utils/properties/watch';
import WithWatchers from 'nomad-ui/mixins/with-watchers';
import notifyError from 'nomad-ui/utils/notify-error';
@ -34,7 +34,7 @@ export default class TaskGroupRoute extends Route.extend(WithWatchers) {
// Refresh job allocations before-hand (so page sort works on load)
return all([
job.hasMany('allocations').reload(),
job.get('scaleState')
job.get('scaleState'),
]).then(() => taskGroup);
})
.catch(notifyError(this));
@ -50,7 +50,7 @@ export default class TaskGroupRoute extends Route.extend(WithWatchers) {
allocations: this.watchAllocations.perform(job),
latestDeployment:
job.get('supportsDeployments') &&
this.watchLatestDeployment.perform(job)
this.watchLatestDeployment.perform(job),
});
}
}

View file

@ -13,7 +13,7 @@ export default class BucketService extends Service {
}
@action deregisterBreadcrumb(crumb) {
const newCrumbs = this.crumbs.filter(c => c !== crumb);
const newCrumbs = this.crumbs.filter((c) => c !== crumb);
this.crumbs = newCrumbs;
}

View file

@ -19,12 +19,12 @@ export default function jobClientStatus(nodesKey, jobKey) {
return computed(
`${nodesKey}.[]`,
`${jobKey}.{datacenters,status,allocations.@each.clientStatus,taskGroups}`,
function() {
function () {
const job = this.get(jobKey);
const nodes = this.get(nodesKey);
// Filter nodes by the datacenters defined in the job.
const filteredNodes = nodes.filter(n => {
const filteredNodes = nodes.filter((n) => {
return job.datacenters.indexOf(n.datacenter) >= 0;
});
@ -34,7 +34,7 @@ export default function jobClientStatus(nodesKey, jobKey) {
// Group the job allocations by the ID of the client that is running them.
const allocsByNodeID = {};
job.allocations.forEach(a => {
job.allocations.forEach((a) => {
const nodeId = a.belongsTo('node').id();
if (!allocsByNodeID[nodeId]) {
allocsByNodeID[nodeId] = [];
@ -47,7 +47,7 @@ export default function jobClientStatus(nodesKey, jobKey) {
byStatus: {},
totalNodes: filteredNodes.length,
};
filteredNodes.forEach(n => {
filteredNodes.forEach((n) => {
const status = jobStatus(allocsByNodeID[n.id], job.taskGroups.length);
result.byNode[n.id] = status;
@ -63,9 +63,9 @@ export default function jobClientStatus(nodesKey, jobKey) {
}
function allQueued(nodes) {
const nodeIDs = nodes.map(n => n.id);
const nodeIDs = nodes.map((n) => n.id);
return {
byNode: Object.fromEntries(nodeIDs.map(id => [id, 'queued'])),
byNode: Object.fromEntries(nodeIDs.map((id) => [id, 'queued'])),
byStatus: canonicalizeStatus({ queued: nodeIDs }),
totalNodes: nodes.length,
};
@ -105,7 +105,7 @@ function jobStatus(allocs, expected) {
// Count how many allocations are in each `clientStatus` value.
const summary = allocs
.filter(a => !a.isOld)
.filter((a) => !a.isOld)
.reduce((acc, a) => {
const status = a.clientStatus;
if (!acc[status]) {

View file

@ -16,21 +16,21 @@ let job;
let node;
let allocation;
module('Acceptance | allocation detail', function(hooks) {
module('Acceptance | allocation detail', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
node = server.create('node');
job = server.create('job', {
groupsCount: 1,
withGroupServices: true,
createAllocations: false
createAllocations: false,
});
allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'running'
clientStatus: 'running',
});
// Make sure the node has an unhealthy driver
@ -38,14 +38,14 @@ module('Acceptance | allocation detail', function(hooks) {
driver: assign(node.drivers, {
docker: {
detected: true,
healthy: false
}
})
healthy: false,
},
}),
});
// Make sure a task for the allocation depends on the unhealthy driver
server.schema.tasks.first().update({
driver: 'docker'
driver: 'docker',
});
window.localStorage.clear();
@ -53,11 +53,11 @@ module('Acceptance | allocation detail', function(hooks) {
await Allocation.visit({ id: allocation.id });
});
test('it passes an accessibility audit', async function(assert) {
test('it passes an accessibility audit', async function (assert) {
await a11yAudit(assert);
});
test('/allocation/:id should name the allocation and link to the corresponding job and node', async function(assert) {
test('/allocation/:id should name the allocation and link to the corresponding job and node', async function (assert) {
assert.ok(
Allocation.title.includes(allocation.name),
'Allocation name is in the heading'
@ -93,7 +93,7 @@ module('Acceptance | allocation detail', function(hooks) {
);
});
test('/allocation/:id should include resource utilization graphs', async function(assert) {
test('/allocation/:id should include resource utilization graphs', async function (assert) {
assert.equal(
Allocation.resourceCharts.length,
2,
@ -111,17 +111,17 @@ module('Acceptance | allocation detail', function(hooks) {
);
});
test('/allocation/:id should present task lifecycles', async function(assert) {
test('/allocation/:id should present task lifecycles', async function (assert) {
const job = server.create('job', {
groupsCount: 1,
groupTaskCount: 6,
withGroupServices: true,
createAllocations: false
createAllocations: false,
});
const allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'running',
jobId: job.id
jobId: job.id,
});
await Allocation.visit({ id: allocation.id });
@ -136,7 +136,7 @@ module('Acceptance | allocation detail', function(hooks) {
const prestartEphemeralTask = server.db.taskStates
.where({ allocationId: allocation.id })
.sortBy('name')
.find(taskState => {
.find((taskState) => {
const task = server.db.tasks.findBy({ name: taskState.name });
return (
task.Lifecycle &&
@ -151,7 +151,7 @@ module('Acceptance | allocation detail', function(hooks) {
);
});
test('/allocation/:id should list all tasks for the allocation', async function(assert) {
test('/allocation/:id should list all tasks for the allocation', async function (assert) {
assert.equal(
Allocation.tasks.length,
server.db.taskStates.where({ allocationId: allocation.id }).length,
@ -160,7 +160,7 @@ module('Acceptance | allocation detail', function(hooks) {
assert.notOk(Allocation.isEmpty, 'Task table empty state is not shown');
});
test('each task row should list high-level information for the task', async function(assert) {
test('each task row should list high-level information for the task', async function (assert) {
const task = server.db.taskStates
.where({ allocationId: allocation.id })
.sortBy('name')[0];
@ -169,16 +169,16 @@ module('Acceptance | allocation detail', function(hooks) {
const taskGroup = server.schema.taskGroups.where({
jobId: allocation.jobId,
name: allocation.taskGroup
name: allocation.taskGroup,
}).models[0];
const jobTask = taskGroup.tasks.models.find(m => m.name === task.name);
const volumes = jobTask.volumeMounts.map(volume => ({
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
const volumes = jobTask.volumeMounts.map((volume) => ({
name: volume.Volume,
source: taskGroup.volumes[volume.Volume].Source
source: taskGroup.volumes[volume.Volume].Source,
}));
Allocation.tasks[0].as(taskRow => {
Allocation.tasks[0].as((taskRow) => {
assert.equal(taskRow.name, task.name, 'Name');
assert.equal(taskRow.state, task.state, 'State');
assert.equal(taskRow.message, event.displayMessage, 'Event Message');
@ -189,7 +189,7 @@ module('Acceptance | allocation detail', function(hooks) {
);
const volumesText = taskRow.volumes;
volumes.forEach(volume => {
volumes.forEach((volume) => {
assert.ok(
volumesText.includes(volume.name),
`Found label ${volume.name}`
@ -202,7 +202,7 @@ module('Acceptance | allocation detail', function(hooks) {
});
});
test('each task row should link to the task detail page', async function(assert) {
test('each task row should link to the task detail page', async function (assert) {
const task = server.db.taskStates
.where({ allocationId: allocation.id })
.sortBy('name')[0];
@ -226,16 +226,16 @@ module('Acceptance | allocation detail', function(hooks) {
);
});
test('tasks with an unhealthy driver have a warning icon', async function(assert) {
test('tasks with an unhealthy driver have a warning icon', async function (assert) {
// Driver health status require node:read permission.
const policy = server.create('policy', {
id: 'node-read',
name: 'node-read',
rulesJSON: {
Node: {
Policy: 'read'
}
}
Policy: 'read',
},
},
});
const clientToken = server.create('token', { type: 'client' });
clientToken.policyIds = [policy.id];
@ -253,17 +253,17 @@ module('Acceptance | allocation detail', function(hooks) {
);
});
test('proxy task has a proxy tag', async function(assert) {
test('proxy task has a proxy tag', async function (assert) {
// Must create a new job as existing one has loaded and it contains the tasks
job = server.create('job', {
groupsCount: 1,
withGroupServices: true,
createAllocations: false
createAllocations: false,
});
allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'running',
jobId: job.id
jobId: job.id,
});
const taskState = allocation.taskStates.models.sortBy('name')[0];
@ -276,24 +276,24 @@ module('Acceptance | allocation detail', function(hooks) {
assert.ok(Allocation.tasks[0].hasProxyTag);
});
test('when there are no tasks, an empty state is shown', async function(assert) {
test('when there are no tasks, an empty state is shown', async function (assert) {
// Make sure the allocation is pending in order to ensure there are no tasks
allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'pending'
clientStatus: 'pending',
});
await Allocation.visit({ id: allocation.id });
assert.ok(Allocation.isEmpty, 'Task table empty state is shown');
});
test('when the allocation has not been rescheduled, the reschedule events section is not rendered', async function(assert) {
test('when the allocation has not been rescheduled, the reschedule events section is not rendered', async function (assert) {
assert.notOk(
Allocation.hasRescheduleEvents,
'Reschedule Events section exists'
);
});
test('ports are listed', async function(assert) {
test('ports are listed', async function (assert) {
const allServerPorts = allocation.taskResources.models[0].resources.Ports;
allServerPorts.sortBy('Label').forEach((serverPort, index) => {
@ -308,9 +308,9 @@ module('Acceptance | allocation detail', function(hooks) {
});
});
test('services are listed', async function(assert) {
test('services are listed', async function (assert) {
const taskGroup = server.schema.taskGroups.findBy({
name: allocation.taskGroup
name: allocation.taskGroup,
});
assert.equal(Allocation.services.length, taskGroup.services.length);
@ -331,7 +331,7 @@ module('Acceptance | allocation detail', function(hooks) {
const upstreams = serverService.Connect.SidecarService.Proxy.Upstreams;
const serverUpstreamsString = upstreams
.map(
upstream => `${upstream.DestinationName}:${upstream.LocalBindPort}`
(upstream) => `${upstream.DestinationName}:${upstream.LocalBindPort}`
)
.join(' ');
@ -339,12 +339,12 @@ module('Acceptance | allocation detail', function(hooks) {
});
});
test('when the allocation is not found, an error message is shown, but the URL persists', async function(assert) {
test('when the allocation is not found, an error message is shown, but the URL persists', async function (assert) {
await Allocation.visit({ id: 'not-a-real-allocation' });
assert.equal(
server.pretender.handledRequests
.filter(request => !request.url.includes('policy'))
.filter((request) => !request.url.includes('policy'))
.findBy('status', 404).url,
'/v1/allocation/not-a-real-allocation',
'A request to the nonexistent allocation is made'
@ -362,20 +362,20 @@ module('Acceptance | allocation detail', function(hooks) {
);
});
test('allocation can be stopped', async function(assert) {
test('allocation can be stopped', async function (assert) {
await Allocation.stop.idle();
await Allocation.stop.confirm();
assert.equal(
server.pretender.handledRequests
.reject(request => request.url.includes('fuzzy'))
.reject((request) => request.url.includes('fuzzy'))
.findBy('method', 'POST').url,
`/v1/allocation/${allocation.id}/stop`,
'Stop request is made for the allocation'
);
});
test('allocation can be restarted', async function(assert) {
test('allocation can be restarted', async function (assert) {
await Allocation.restart.idle();
await Allocation.restart.confirm();
@ -386,7 +386,7 @@ module('Acceptance | allocation detail', function(hooks) {
);
});
test('while an allocation is being restarted, the stop button is disabled', async function(assert) {
test('while an allocation is being restarted, the stop button is disabled', async function (assert) {
server.pretender.post('/v1/allocation/:id/stop', () => [204, {}, ''], true);
await Allocation.stop.idle();
@ -400,7 +400,7 @@ module('Acceptance | allocation detail', function(hooks) {
await Allocation.stop.confirm();
});
test('if stopping or restarting fails, an error message is shown', async function(assert) {
test('if stopping or restarting fails, an error message is shown', async function (assert) {
server.pretender.post('/v1/allocation/:id/stop', () => [403, {}, '']);
await Allocation.stop.idle();
@ -425,11 +425,11 @@ module('Acceptance | allocation detail', function(hooks) {
});
});
module('Acceptance | allocation detail (rescheduled)', function(hooks) {
module('Acceptance | allocation detail (rescheduled)', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
node = server.create('node');
@ -439,7 +439,7 @@ module('Acceptance | allocation detail (rescheduled)', function(hooks) {
await Allocation.visit({ id: allocation.id });
});
test('when the allocation has been rescheduled, the reschedule events section is rendered', async function(assert) {
test('when the allocation has been rescheduled, the reschedule events section is rendered', async function (assert) {
assert.ok(
Allocation.hasRescheduleEvents,
'Reschedule Events section exists'
@ -447,11 +447,11 @@ module('Acceptance | allocation detail (rescheduled)', function(hooks) {
});
});
module('Acceptance | allocation detail (not running)', function(hooks) {
module('Acceptance | allocation detail (not running)', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
node = server.create('node');
@ -461,7 +461,7 @@ module('Acceptance | allocation detail (not running)', function(hooks) {
await Allocation.visit({ id: allocation.id });
});
test('when the allocation is not running, the utilization graphs are replaced by an empty message', async function(assert) {
test('when the allocation is not running, the utilization graphs are replaced by an empty message', async function (assert) {
assert.equal(Allocation.resourceCharts.length, 0, 'No resource charts');
assert.equal(
Allocation.resourceEmptyMessage,
@ -470,25 +470,25 @@ module('Acceptance | allocation detail (not running)', function(hooks) {
);
});
test('the exec and stop/restart buttons are absent', async function(assert) {
test('the exec and stop/restart buttons are absent', async function (assert) {
assert.notOk(Allocation.execButton.isPresent);
assert.notOk(Allocation.stop.isPresent);
assert.notOk(Allocation.restart.isPresent);
});
});
module('Acceptance | allocation detail (preemptions)', function(hooks) {
module('Acceptance | allocation detail (preemptions)', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
node = server.create('node');
job = server.create('job', { createAllocations: false });
window.localStorage.clear();
});
test('shows a dedicated section to the allocation that preempted this allocation', async function(assert) {
test('shows a dedicated section to the allocation that preempted this allocation', async function (assert) {
allocation = server.create('allocation', 'preempted');
const preempter = server.schema.find(
'allocation',
@ -539,7 +539,7 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
);
});
test('shows a dedicated section to the allocations this allocation preempted', async function(assert) {
test('shows a dedicated section to the allocations this allocation preempted', async function (assert) {
allocation = server.create('allocation', 'preempter');
await Allocation.visit({ id: allocation.id });
assert.ok(
@ -548,12 +548,12 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
);
});
test('each preempted allocation in the table lists basic allocation information', async function(assert) {
test('each preempted allocation in the table lists basic allocation information', async function (assert) {
allocation = server.create('allocation', 'preempter');
await Allocation.visit({ id: allocation.id });
const preemption = allocation.preemptedAllocations
.map(id => server.schema.find('allocation', id))
.map((id) => server.schema.find('allocation', id))
.sortBy('modifyIndex')
.reverse()[0];
const preemptionRow = Allocation.preemptions.objectAt(0);
@ -596,16 +596,16 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
);
});
test('clicking the client ID in the preempted allocation row naviates to the client page', async function(assert) {
test('clicking the client ID in the preempted allocation row naviates to the client page', async function (assert) {
// Navigating to the client page requires node:read permission.
const policy = server.create('policy', {
id: 'node-read',
name: 'node-read',
rulesJSON: {
Node: {
Policy: 'read'
}
}
Policy: 'read',
},
},
});
const clientToken = server.create('token', { type: 'client' });
clientToken.policyIds = [policy.id];
@ -616,7 +616,7 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
await Allocation.visit({ id: allocation.id });
const preemption = allocation.preemptedAllocations
.map(id => server.schema.find('allocation', id))
.map((id) => server.schema.find('allocation', id))
.sortBy('modifyIndex')
.reverse()[0];
const preemptionRow = Allocation.preemptions.objectAt(0);
@ -629,7 +629,7 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
);
});
test('when an allocation both preempted allocations and was preempted itself, both preemptions sections are shown', async function(assert) {
test('when an allocation both preempted allocations and was preempted itself, both preemptions sections are shown', async function (assert) {
allocation = server.create('allocation', 'preempter', 'preempted');
await Allocation.visit({ id: allocation.id });
assert.ok(

View file

@ -11,11 +11,11 @@ let node;
let managementToken;
let clientToken;
module('Acceptance | client monitor', function(hooks) {
module('Acceptance | client monitor', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(function() {
hooks.beforeEach(function () {
node = server.create('node');
managementToken = server.create('token');
@ -27,12 +27,14 @@ module('Acceptance | client monitor', function(hooks) {
run.later(run, run.cancelTimers, 500);
});
test('it passes an accessibility audit', async function(assert) {
test('it passes an accessibility audit', async function (assert) {
assert.expect(1);
await ClientMonitor.visit({ id: node.id });
await a11yAudit(assert);
});
test('/clients/:id/monitor should have a breadcrumb trail linking back to clients', async function(assert) {
test('/clients/:id/monitor should have a breadcrumb trail linking back to clients', async function (assert) {
await ClientMonitor.visit({ id: node.id });
assert.equal(Layout.breadcrumbFor('clients.index').text, 'Clients');
@ -45,10 +47,10 @@ module('Acceptance | client monitor', function(hooks) {
assert.equal(currentURL(), '/clients');
});
test('the monitor page immediately streams agent monitor output at the info level', async function(assert) {
test('the monitor page immediately streams agent monitor output at the info level', async function (assert) {
await ClientMonitor.visit({ id: node.id });
const logRequest = server.pretender.handledRequests.find(req =>
const logRequest = server.pretender.handledRequests.find((req) =>
req.url.startsWith('/v1/agent/monitor')
);
assert.ok(ClientMonitor.logsArePresent);
@ -56,13 +58,13 @@ module('Acceptance | client monitor', function(hooks) {
assert.ok(logRequest.url.includes('log_level=info'));
});
test('switching the log level persists the new log level as a query param', async function(assert) {
test('switching the log level persists the new log level as a query param', async function (assert) {
await ClientMonitor.visit({ id: node.id });
await ClientMonitor.selectLogLevel('Debug');
assert.equal(currentURL(), `/clients/${node.id}/monitor?level=debug`);
});
test('when the current access token does not include the agent:read rule, a descriptive error message is shown', async function(assert) {
test('when the current access token does not include the agent:read rule, a descriptive error message is shown', async function (assert) {
window.localStorage.nomadTokenSecret = clientToken.secretId;
await ClientMonitor.visit({ id: node.id });

View file

@ -40,7 +40,10 @@ module('Acceptance | server monitor', function (hooks) {
'Servers',
'The page should read the breadcrumb Servers'
);
assert.equal(Layout.breadcrumbFor('servers.server').text, `Server ${agent.name}`);
assert.equal(
Layout.breadcrumbFor('servers.server').text,
`Server ${agent.name}`
);
await Layout.breadcrumbFor('servers.index').visit();
assert.equal(currentURL(), '/servers');

View file

@ -1,3 +1,4 @@
/* eslint-disable qunit/require-expect */
import { currentURL, waitFor } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
@ -10,27 +11,29 @@ import moment from 'moment';
let allocation;
let task;
module('Acceptance | task detail', function(hooks) {
module('Acceptance | task detail', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
server.create('node');
server.create('job', { createAllocations: false });
allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'running'
clientStatus: 'running',
});
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
await Task.visit({ id: allocation.id, name: task.name });
});
test('it passes an accessibility audit', async function(assert) {
test('it passes an accessibility audit', async function (assert) {
assert.expect(1);
await a11yAudit(assert);
});
test('/allocation/:id/:task_name should name the task and list high-level task information', async function(assert) {
test('/allocation/:id/:task_name should name the task and list high-level task information', async function (assert) {
assert.ok(Task.title.text.includes(task.name), 'Task name');
assert.ok(Task.state.includes(task.state), 'Task state');
@ -61,7 +64,7 @@ module('Acceptance | task detail', function(hooks) {
assert.equal(document.title, `Task ${task.name} - Nomad`);
});
test('breadcrumbs match jobs / job / task group / allocation / task', async function(assert) {
test('breadcrumbs match jobs / job / task group / allocation / task', async function (assert) {
const { jobId, taskGroup } = allocation;
const job = server.db.jobs.find(jobId);
@ -122,7 +125,7 @@ module('Acceptance | task detail', function(hooks) {
);
});
test('/allocation/:id/:task_name should include resource utilization graphs', async function(assert) {
test('/allocation/:id/:task_name should include resource utilization graphs', async function (assert) {
assert.equal(
Task.resourceCharts.length,
2,
@ -140,7 +143,7 @@ module('Acceptance | task detail', function(hooks) {
);
});
test('the events table lists all recent events', async function(assert) {
test('the events table lists all recent events', async function (assert) {
const events = server.db.taskEvents.where({ taskStateId: task.id });
assert.equal(
@ -150,26 +153,26 @@ module('Acceptance | task detail', function(hooks) {
);
});
test('when a task has volumes, the volumes table is shown', async function(assert) {
test('when a task has volumes, the volumes table is shown', async function (assert) {
const taskGroup = server.schema.taskGroups.where({
jobId: allocation.jobId,
name: allocation.taskGroup
name: allocation.taskGroup,
}).models[0];
const jobTask = taskGroup.tasks.models.find(m => m.name === task.name);
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
assert.ok(Task.hasVolumes);
assert.equal(Task.volumes.length, jobTask.volumeMounts.length);
});
test('when a task does not have volumes, the volumes table is not shown', async function(assert) {
test('when a task does not have volumes, the volumes table is not shown', async function (assert) {
const job = server.create('job', {
createAllocations: false,
noHostVolumes: true
noHostVolumes: true,
});
allocation = server.create('allocation', {
jobId: job.id,
clientStatus: 'running'
clientStatus: 'running',
});
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
@ -177,16 +180,16 @@ module('Acceptance | task detail', function(hooks) {
assert.notOk(Task.hasVolumes);
});
test('each volume in the volumes table shows information about the volume', async function(assert) {
test('each volume in the volumes table shows information about the volume', async function (assert) {
const taskGroup = server.schema.taskGroups.where({
jobId: allocation.jobId,
name: allocation.taskGroup
name: allocation.taskGroup,
}).models[0];
const jobTask = taskGroup.tasks.models.find(m => m.name === task.name);
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
const volume = jobTask.volumeMounts[0];
Task.volumes[0].as(volumeRow => {
Task.volumes[0].as((volumeRow) => {
assert.equal(volumeRow.name, volume.Volume);
assert.equal(volumeRow.destination, volume.Destination);
assert.equal(
@ -200,7 +203,7 @@ module('Acceptance | task detail', function(hooks) {
});
});
test('each recent event should list the time, type, and description of the event', async function(assert) {
test('each recent event should list the time, type, and description of the event', async function (assert) {
const event = server.db.taskEvents.where({ taskStateId: task.id })[0];
const recentEvent = Task.events.objectAt(Task.events.length - 1);
@ -213,12 +216,12 @@ module('Acceptance | task detail', function(hooks) {
assert.equal(recentEvent.message, event.displayMessage, 'Event message');
});
test('when the allocation is not found, the application errors', async function(assert) {
test('when the allocation is not found, the application errors', async function (assert) {
await Task.visit({ id: 'not-a-real-allocation', name: task.name });
assert.equal(
server.pretender.handledRequests
.filter(request => !request.url.includes('policy'))
.filter((request) => !request.url.includes('policy'))
.findBy('status', 404).url,
'/v1/allocation/not-a-real-allocation',
'A request to the nonexistent allocation is made'
@ -232,7 +235,7 @@ module('Acceptance | task detail', function(hooks) {
assert.equal(Task.error.title, 'Not Found', 'Error message is for 404');
});
test('when the allocation is found but the task is not, the application errors', async function(assert) {
test('when the allocation is found but the task is not, the application errors', async function (assert) {
await Task.visit({ id: allocation.id, name: 'not-a-real-task-name' });
assert.ok(
@ -251,7 +254,7 @@ module('Acceptance | task detail', function(hooks) {
assert.equal(Task.error.title, 'Not Found', 'Error message is for 404');
});
test('task can be restarted', async function(assert) {
test('task can be restarted', async function (assert) {
await Task.restart.idle();
await Task.restart.confirm();
@ -269,11 +272,11 @@ module('Acceptance | task detail', function(hooks) {
);
});
test('when task restart fails (403), an ACL permissions error message is shown', async function(assert) {
test('when task restart fails (403), an ACL permissions error message is shown', async function (assert) {
server.pretender.put('/v1/client/allocation/:id/restart', () => [
403,
{},
''
'',
]);
await Task.restart.idle();
@ -294,12 +297,12 @@ module('Acceptance | task detail', function(hooks) {
assert.notOk(Task.inlineError.isShown, 'Inline error is no longer shown');
});
test('when task restart fails (500), the error message from the API is piped through to the alert', async function(assert) {
test('when task restart fails (500), the error message from the API is piped through to the alert', async function (assert) {
const message = 'A plaintext error message';
server.pretender.put('/v1/client/allocation/:id/restart', () => [
500,
{},
message
message,
]);
await Task.restart.idle();
@ -314,21 +317,21 @@ module('Acceptance | task detail', function(hooks) {
assert.notOk(Task.inlineError.isShown);
});
test('exec button is present', async function(assert) {
test('exec button is present', async function (assert) {
assert.ok(Task.execButton.isPresent);
});
});
module('Acceptance | task detail (no addresses)', function(hooks) {
module('Acceptance | task detail (no addresses)', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
server.create('node');
server.create('job');
allocation = server.create('allocation', 'withoutTaskWithPorts', {
clientStatus: 'running'
clientStatus: 'running',
});
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
@ -336,28 +339,28 @@ module('Acceptance | task detail (no addresses)', function(hooks) {
});
});
module('Acceptance | task detail (different namespace)', function(hooks) {
module('Acceptance | task detail (different namespace)', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
server.create('node');
server.create('namespace');
server.create('namespace', { id: 'other-namespace' });
server.create('job', {
createAllocations: false,
namespaceId: 'other-namespace'
namespaceId: 'other-namespace',
});
allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'running'
clientStatus: 'running',
});
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
await Task.visit({ id: allocation.id, name: task.name });
});
test('breadcrumbs match jobs / job / task group / allocation / task', async function(assert) {
test('breadcrumbs match jobs / job / task group / allocation / task', async function (assert) {
const { jobId, taskGroup } = allocation;
const job = server.db.jobs.find(jobId);
@ -394,28 +397,28 @@ module('Acceptance | task detail (different namespace)', function(hooks) {
});
});
module('Acceptance | task detail (not running)', function(hooks) {
module('Acceptance | task detail (not running)', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
server.create('node');
server.create('namespace');
server.create('namespace', { id: 'other-namespace' });
server.create('job', {
createAllocations: false,
namespaceId: 'other-namespace'
namespaceId: 'other-namespace',
});
allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'complete'
clientStatus: 'complete',
});
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
await Task.visit({ id: allocation.id, name: task.name });
});
test('when the allocation for a task is not running, the resource utilization graphs are replaced by an empty message', async function(assert) {
test('when the allocation for a task is not running, the resource utilization graphs are replaced by an empty message', async function (assert) {
assert.equal(Task.resourceCharts.length, 0, 'No resource charts');
assert.equal(
Task.resourceEmptyMessage,
@ -424,21 +427,21 @@ module('Acceptance | task detail (not running)', function(hooks) {
);
});
test('exec button is absent', async function(assert) {
test('exec button is absent', async function (assert) {
assert.notOk(Task.execButton.isPresent);
});
});
module('Acceptance | proxy task detail', function(hooks) {
module('Acceptance | proxy task detail', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
server.create('node');
server.create('job', { createAllocations: false });
allocation = server.create('allocation', 'withTaskWithPorts', {
clientStatus: 'running'
clientStatus: 'running',
});
const taskState = allocation.taskStates.models[0];
@ -449,7 +452,7 @@ module('Acceptance | proxy task detail', function(hooks) {
await Task.visit({ id: allocation.id, name: taskState.name });
});
test('a proxy tag is shown', async function(assert) {
test('a proxy tag is shown', async function (assert) {
assert.ok(Task.title.proxyTag.isPresent);
});
});

View file

@ -9,7 +9,7 @@ import {
formatBytes,
formatHertz,
formatScheduledBytes,
formatScheduledHertz
formatScheduledHertz,
} from 'nomad-ui/utils/units';
import TaskGroup from 'nomad-ui/tests/pages/jobs/job/task-group';
import Layout from 'nomad-ui/tests/pages/layout';
@ -24,30 +24,30 @@ let managementToken;
const sum = (total, n) => total + n;
module('Acceptance | task group detail', function(hooks) {
module('Acceptance | task group detail', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('agent');
server.create('node', 'forceIPv4');
job = server.create('job', {
groupsCount: 2,
createAllocations: false
createAllocations: false,
});
const taskGroups = server.db.taskGroups.where({ jobId: job.id });
taskGroup = taskGroups[0];
tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id));
tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
server.create('node', 'forceIPv4');
allocations = server.createList('allocation', 2, {
jobId: job.id,
taskGroup: taskGroup.name,
clientStatus: 'running'
clientStatus: 'running',
});
// Allocations associated to a different task group on the job to
@ -55,20 +55,20 @@ module('Acceptance | task group detail', function(hooks) {
server.createList('allocation', 3, {
jobId: job.id,
taskGroup: taskGroups[1].name,
clientStatus: 'running'
clientStatus: 'running',
});
// Set a static name to make the search test deterministic
server.db.allocations.forEach(alloc => {
server.db.allocations.forEach((alloc) => {
alloc.name = 'aaaaa';
});
// Mark the first alloc as rescheduled
allocations[0].update({
nextAllocation: allocations[1].id
nextAllocation: allocations[1].id,
});
allocations[1].update({
previousAllocation: allocations[0].id
previousAllocation: allocations[0].id,
});
managementToken = server.create('token');
@ -76,16 +76,16 @@ module('Acceptance | task group detail', function(hooks) {
window.localStorage.clear();
});
test('it passes an accessibility audit', async function(assert) {
test('it passes an accessibility audit', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
await a11yAudit(assert);
});
test('/jobs/:id/:task-group should list high-level metrics for the allocation', async function(assert) {
test('/jobs/:id/:task-group should list high-level metrics for the allocation', async function (assert) {
const totalCPU = tasks.mapBy('resources.CPU').reduce(sum, 0);
const totalMemory = tasks.mapBy('resources.MemoryMB').reduce(sum, 0);
const totalMemoryMax = tasks
.map(t => t.resources.MemoryMaxMB || t.resources.MemoryMB)
.map((t) => t.resources.MemoryMaxMB || t.resources.MemoryMB)
.reduce(sum, 0);
const totalDisk = taskGroup.ephemeralDisk.SizeMB;
@ -127,7 +127,7 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', async function(assert) {
test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
assert.equal(
@ -147,14 +147,14 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('/jobs/:id/:task-group first breadcrumb should link to jobs', async function(assert) {
test('/jobs/:id/:task-group first breadcrumb should link to jobs', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
await Layout.breadcrumbFor('jobs.index').visit();
assert.equal(currentURL(), '/jobs', 'First breadcrumb links back to jobs');
});
test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', async function(assert) {
test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
await Layout.breadcrumbFor('jobs.job.index').visit();
@ -165,7 +165,7 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('when the user has a client token that has a namespace with a policy to run and scale a job the autoscaler options should be available', async function(assert) {
test('when the user has a client token that has a namespace with a policy to run and scale a job the autoscaler options should be available', async function (assert) {
window.localStorage.clear();
const SCALE_AND_WRITE_NAMESPACE = 'scale-and-write-namespace';
@ -174,7 +174,7 @@ module('Acceptance | task group detail', function(hooks) {
server.create('namespace', { id: SCALE_AND_WRITE_NAMESPACE });
const secondNamespace = server.create('namespace', {
id: READ_ONLY_NAMESPACE
id: READ_ONLY_NAMESPACE,
});
job = server.create('job', {
@ -182,14 +182,14 @@ module('Acceptance | task group detail', function(hooks) {
createAllocations: false,
shallow: true,
noActiveDeployment: true,
namespaceId: SCALE_AND_WRITE_NAMESPACE
namespaceId: SCALE_AND_WRITE_NAMESPACE,
});
const scalingGroup = server.create('task-group', {
job,
name: 'scaling',
count: 1,
shallow: true,
withScaling: true
withScaling: true,
});
job.update({ taskGroupIds: [scalingGroup.id] });
@ -198,14 +198,14 @@ module('Acceptance | task group detail', function(hooks) {
createAllocations: false,
shallow: true,
noActiveDeployment: true,
namespaceId: READ_ONLY_NAMESPACE
namespaceId: READ_ONLY_NAMESPACE,
});
const scalingGroup2 = server.create('task-group', {
job: job2,
name: 'scaling',
count: 1,
shallow: true,
withScaling: true
withScaling: true,
});
job2.update({ taskGroupIds: [scalingGroup2.id] });
@ -216,14 +216,14 @@ module('Acceptance | task group detail', function(hooks) {
Namespaces: [
{
Name: SCALE_AND_WRITE_NAMESPACE,
Capabilities: ['scale-job', 'submit-job', 'read-job', 'list-jobs']
Capabilities: ['scale-job', 'submit-job', 'read-job', 'list-jobs'],
},
{
Name: READ_ONLY_NAMESPACE,
Capabilities: ['list-jobs', 'read-job']
}
]
}
Capabilities: ['list-jobs', 'read-job'],
},
],
},
});
clientToken.policyIds = [policy.id];
@ -234,7 +234,7 @@ module('Acceptance | task group detail', function(hooks) {
await TaskGroup.visit({
id: job.id,
name: scalingGroup.name,
namespace: SCALE_AND_WRITE_NAMESPACE
namespace: SCALE_AND_WRITE_NAMESPACE,
});
assert.equal(
@ -246,7 +246,7 @@ module('Acceptance | task group detail', function(hooks) {
await TaskGroup.visit({
id: job2.id,
name: scalingGroup2.name,
namespace: secondNamespace.name
namespace: secondNamespace.name,
});
assert.equal(
currentURL(),
@ -255,11 +255,11 @@ module('Acceptance | task group detail', function(hooks) {
assert.ok(TaskGroup.countStepper.increment.isDisabled);
});
test('/jobs/:id/:task-group should list one page of allocations for the task group', async function(assert) {
test('/jobs/:id/:task-group should list one page of allocations for the task group', async function (assert) {
server.createList('allocation', TaskGroup.pageSize, {
jobId: job.id,
taskGroup: taskGroup.name,
clientStatus: 'running'
clientStatus: 'running',
});
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
@ -277,7 +277,7 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('each allocation should show basic information about the allocation', async function(assert) {
test('each allocation should show basic information about the allocation', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
const allocation = allocations.sortBy('modifyIndex').reverse()[0];
@ -320,16 +320,16 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('clicking the client ID in the allocation row naviates to the client page', async function(assert) {
test('clicking the client ID in the allocation row naviates to the client page', async function (assert) {
// Navigating to the client page requires node:read permission.
const policy = server.create('policy', {
id: 'node-read',
name: 'node-read',
rulesJSON: {
Node: {
Policy: 'read'
}
}
Policy: 'read',
},
},
});
const clientToken = server.create('token', { type: 'client' });
clientToken.policyIds = [policy.id];
@ -349,14 +349,14 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('each allocation should show stats about the allocation', async function(assert) {
test('each allocation should show stats about the allocation', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
const allocation = allocations.sortBy('name')[0];
const allocationRow = TaskGroup.allocations.objectAt(0);
const allocStats = server.db.clientAllocationStats.find(allocation.id);
const tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id));
const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0);
const memoryUsed = tasks.reduce(
@ -395,7 +395,7 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('when the allocation search has no matches, there is an empty message', async function(assert) {
test('when the allocation search has no matches, there is an empty message', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
await TaskGroup.search('zzzzzz');
@ -408,7 +408,7 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('when the allocation has reschedule events, the allocation row is denoted with an icon', async function(assert) {
test('when the allocation has reschedule events, the allocation row is denoted with an icon', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
const rescheduleRow = TaskGroup.allocationFor(allocations[0].id);
@ -421,10 +421,10 @@ module('Acceptance | task group detail', function(hooks) {
assert.notOk(normalRow.rescheduled, 'Normal row has no reschedule icon');
});
test('/jobs/:id/:task-group should present task lifecycles', async function(assert) {
test('/jobs/:id/:task-group should present task lifecycles', async function (assert) {
job = server.create('job', {
groupsCount: 2,
groupTaskCount: 3
groupTaskCount: 3,
});
const taskGroups = server.db.taskGroups.where({ jobId: job.id });
@ -438,21 +438,21 @@ module('Acceptance | task group detail', function(hooks) {
'Task Lifecycle Configuration'
);
tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id));
tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
const taskNames = tasks.mapBy('name');
// This is thoroughly tested in allocation detail tests, so this mostly checks whats different
assert.equal(TaskGroup.lifecycleChart.tasks.length, 3);
TaskGroup.lifecycleChart.tasks.forEach(Task => {
TaskGroup.lifecycleChart.tasks.forEach((Task) => {
assert.ok(taskNames.includes(Task.name));
assert.notOk(Task.isActive);
assert.notOk(Task.isFinished);
});
});
test('when the task group depends on volumes, the volumes table is shown', async function(assert) {
test('when the task group depends on volumes, the volumes table is shown', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
assert.ok(TaskGroup.hasVolumes);
@ -462,7 +462,7 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('when the task group does not depend on volumes, the volumes table is not shown', async function(assert) {
test('when the task group does not depend on volumes, the volumes table is not shown', async function (assert) {
job = server.create('job', { noHostVolumes: true, shallow: true });
taskGroup = server.db.taskGroups.where({ jobId: job.id })[0];
@ -471,10 +471,10 @@ module('Acceptance | task group detail', function(hooks) {
assert.notOk(TaskGroup.hasVolumes);
});
test('each row in the volumes table lists information about the volume', async function(assert) {
test('each row in the volumes table lists information about the volume', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
TaskGroup.volumes[0].as(volumeRow => {
TaskGroup.volumes[0].as((volumeRow) => {
const volume = taskGroup.volumes[volumeRow.name];
assert.equal(volumeRow.name, volume.Name);
assert.equal(volumeRow.type, volume.Type);
@ -486,21 +486,21 @@ module('Acceptance | task group detail', function(hooks) {
});
});
test('the count stepper sends the appropriate POST request', async function(assert) {
test('the count stepper sends the appropriate POST request', async function (assert) {
window.localStorage.nomadTokenSecret = managementToken.secretId;
job = server.create('job', {
groupCount: 0,
createAllocations: false,
shallow: true,
noActiveDeployment: true
noActiveDeployment: true,
});
const scalingGroup = server.create('task-group', {
job,
name: 'scaling',
count: 1,
shallow: true,
withScaling: true
withScaling: true,
});
job.update({ taskGroupIds: [scalingGroup.id] });
@ -509,28 +509,28 @@ module('Acceptance | task group detail', function(hooks) {
await settled();
const scaleRequest = server.pretender.handledRequests.find(
req => req.method === 'POST' && req.url.endsWith('/scale')
(req) => req.method === 'POST' && req.url.endsWith('/scale')
);
const requestBody = JSON.parse(scaleRequest.requestBody);
assert.equal(requestBody.Target.Group, scalingGroup.name);
assert.equal(requestBody.Count, scalingGroup.count + 1);
});
test('the count stepper is disabled when a deployment is running', async function(assert) {
test('the count stepper is disabled when a deployment is running', async function (assert) {
window.localStorage.nomadTokenSecret = managementToken.secretId;
job = server.create('job', {
groupCount: 0,
createAllocations: false,
shallow: true,
activeDeployment: true
activeDeployment: true,
});
const scalingGroup = server.create('task-group', {
job,
name: 'scaling',
count: 1,
shallow: true,
withScaling: true
withScaling: true,
});
job.update({ taskGroupIds: [scalingGroup.id] });
@ -541,15 +541,15 @@ module('Acceptance | task group detail', function(hooks) {
assert.ok(TaskGroup.countStepper.decrement.isDisabled);
});
test('when the job for the task group is not found, an error message is shown, but the URL persists', async function(assert) {
test('when the job for the task group is not found, an error message is shown, but the URL persists', async function (assert) {
await TaskGroup.visit({
id: 'not-a-real-job',
name: 'not-a-real-task-group'
name: 'not-a-real-task-group',
});
assert.equal(
server.pretender.handledRequests
.filter(request => !request.url.includes('policy'))
.filter((request) => !request.url.includes('policy'))
.findBy('status', 404).url,
'/v1/job/not-a-real-job',
'A request to the nonexistent job is made'
@ -567,7 +567,7 @@ module('Acceptance | task group detail', function(hooks) {
);
});
test('when the task group is not found on the job, an error message is shown, but the URL persists', async function(assert) {
test('when the task group is not found on the job, an error message is shown, but the URL persists', async function (assert) {
await TaskGroup.visit({ id: job.id, name: 'not-a-real-task-group' });
assert.ok(
@ -598,16 +598,16 @@ module('Acceptance | task group detail', function(hooks) {
server.createList('allocation', TaskGroup.pageSize, {
jobId: job.id,
taskGroup: taskGroup.name,
clientStatus: 'running'
clientStatus: 'running',
});
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
}
},
});
test('when a task group has no scaling events, there is no recent scaling events section', async function(assert) {
test('when a task group has no scaling events, there is no recent scaling events section', async function (assert) {
const taskGroupScale = job.jobScale.taskGroupScales.models.find(
m => m.name === taskGroup.name
(m) => m.name === taskGroup.name
);
taskGroupScale.update({ events: [] });
@ -616,9 +616,9 @@ module('Acceptance | task group detail', function(hooks) {
assert.notOk(TaskGroup.hasScaleEvents);
});
test('the recent scaling events section shows all recent scaling events in reverse chronological order', async function(assert) {
test('the recent scaling events section shows all recent scaling events in reverse chronological order', async function (assert) {
const taskGroupScale = job.jobScale.taskGroupScales.models.find(
m => m.name === taskGroup.name
(m) => m.name === taskGroup.name
);
taskGroupScale.update({
events: [
@ -627,8 +627,8 @@ module('Acceptance | task group detail', function(hooks) {
server.create('scale-event', { error: true }),
server.create('scale-event', { error: true }),
server.create('scale-event', { count: 3, error: false }),
server.create('scale-event', { count: 1, error: false })
]
server.create('scale-event', { count: 1, error: false }),
],
});
const scaleEvents = taskGroupScale.events.models.sortBy('time').reverse();
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
@ -660,9 +660,9 @@ module('Acceptance | task group detail', function(hooks) {
});
});
test('when a task group has at least two count scaling events and the count scaling events outnumber the non-count scaling events, a timeline is shown in addition to the accordion', async function(assert) {
test('when a task group has at least two count scaling events and the count scaling events outnumber the non-count scaling events, a timeline is shown in addition to the accordion', async function (assert) {
const taskGroupScale = job.jobScale.taskGroupScales.models.find(
m => m.name === taskGroup.name
(m) => m.name === taskGroup.name
);
taskGroupScale.update({
events: [
@ -674,8 +674,8 @@ module('Acceptance | task group detail', function(hooks) {
server.create('scale-event', { count: 3, error: false }),
server.create('scale-event', { count: 2, error: false }),
server.create('scale-event', { count: 9, error: false }),
server.create('scale-event', { count: 1, error: false })
]
server.create('scale-event', { count: 1, error: false }),
],
});
const scaleEvents = taskGroupScale.events.models.sortBy('time').reverse();
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
@ -685,7 +685,7 @@ module('Acceptance | task group detail', function(hooks) {
assert.equal(
TaskGroup.scalingAnnotations.length,
scaleEvents.filter(ev => ev.count == null).length
scaleEvents.filter((ev) => ev.count == null).length
);
});
@ -694,7 +694,7 @@ module('Acceptance | task group detail', function(hooks) {
paramName: 'status',
expectedOptions: ['Pending', 'Running', 'Complete', 'Failed', 'Lost'],
async beforeEach() {
['pending', 'running', 'complete', 'failed', 'lost'].forEach(s => {
['pending', 'running', 'complete', 'failed', 'lost'].forEach((s) => {
server.createList('allocation', 5, { clientStatus: s });
});
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
@ -702,7 +702,7 @@ module('Acceptance | task group detail', function(hooks) {
filter: (alloc, selection) =>
alloc.jobId == job.id &&
alloc.taskGroup == taskGroup.name &&
selection.includes(alloc.clientStatus)
selection.includes(alloc.clientStatus),
});
testFacet('Client', {
@ -713,21 +713,21 @@ module('Acceptance | task group detail', function(hooks) {
new Set(
allocs
.filter(
alloc =>
(alloc) =>
alloc.jobId == job.id && alloc.taskGroup == taskGroup.name
)
.mapBy('nodeId')
.map(id => id.split('-')[0])
.map((id) => id.split('-')[0])
)
).sort();
},
async beforeEach() {
const nodes = server.createList('node', 3, 'forceIPv4');
nodes.forEach(node =>
nodes.forEach((node) =>
server.createList('allocation', 5, {
nodeId: node.id,
jobId: job.id,
taskGroup: taskGroup.name
taskGroup: taskGroup.name,
})
);
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
@ -735,7 +735,7 @@ module('Acceptance | task group detail', function(hooks) {
filter: (alloc, selection) =>
alloc.jobId == job.id &&
alloc.taskGroup == taskGroup.name &&
selection.includes(alloc.nodeId.split('-')[0])
selection.includes(alloc.nodeId.split('-')[0]),
});
});
@ -743,7 +743,7 @@ function testFacet(
label,
{ facet, paramName, beforeEach, filter, expectedOptions }
) {
test(`facet ${label} | the ${label} facet has the correct options`, async function(assert) {
test(`facet ${label} | the ${label} facet has the correct options`, async function (assert) {
await beforeEach();
await facet.toggle();
@ -755,13 +755,13 @@ function testFacet(
}
assert.deepEqual(
facet.options.map(option => option.label.trim()),
facet.options.map((option) => option.label.trim()),
expectation,
'Options for facet are as expected'
);
});
test(`facet ${label} | the ${label} facet filters the allocations list by ${label}`, async function(assert) {
test(`facet ${label} | the ${label} facet filters the allocations list by ${label}`, async function (assert) {
let option;
await beforeEach();
@ -772,7 +772,7 @@ function testFacet(
const selection = [option.key];
const expectedAllocs = server.db.allocations
.filter(alloc => filter(alloc, selection))
.filter((alloc) => filter(alloc, selection))
.sortBy('modifyIndex')
.reverse();
@ -785,7 +785,7 @@ function testFacet(
});
});
test(`facet ${label} | selecting multiple options in the ${label} facet results in a broader search`, async function(assert) {
test(`facet ${label} | selecting multiple options in the ${label} facet results in a broader search`, async function (assert) {
const selection = [];
await beforeEach();
@ -799,7 +799,7 @@ function testFacet(
selection.push(option2.key);
const expectedAllocs = server.db.allocations
.filter(alloc => filter(alloc, selection))
.filter((alloc) => filter(alloc, selection))
.sortBy('modifyIndex')
.reverse();
@ -812,7 +812,7 @@ function testFacet(
});
});
test(`facet ${label} | selecting options in the ${label} facet updates the ${paramName} query param`, async function(assert) {
test(`facet ${label} | selecting options in the ${label} facet updates the ${paramName} query param`, async function (assert) {
const selection = [];
await beforeEach();

View file

@ -16,10 +16,10 @@ export default function moduleForJob(
) {
let job;
module(title, function(hooks) {
module(title, function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.before(function() {
hooks.before(function () {
if (context !== 'allocations' && context !== 'children') {
throw new Error(
`Invalid context provided to moduleForJob, expected either "allocations" or "children", got ${context}`
@ -27,7 +27,7 @@ export default function moduleForJob(
}
});
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
server.create('node');
job = jobFactory();
if (!job.namespace || job.namespace === 'default') {
@ -37,7 +37,7 @@ export default function moduleForJob(
}
});
test('visiting /jobs/:job_id', async function(assert) {
test('visiting /jobs/:job_id', async function (assert) {
const expectedURL = new URL(
urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}`, job.namespace),
window.location
@ -49,7 +49,7 @@ export default function moduleForJob(
assert.equal(document.title, `Job ${job.name} - Nomad`);
});
test('the subnav links to overview', async function(assert) {
test('the subnav links to overview', async function (assert) {
await JobDetail.tabFor('overview').visit();
const expectedURL = new URL(
@ -62,7 +62,7 @@ export default function moduleForJob(
assert.deepEqual(gotURL.searchParams, expectedURL.searchParams);
});
test('the subnav links to definition', async function(assert) {
test('the subnav links to definition', async function (assert) {
await JobDetail.tabFor('definition').visit();
assert.equal(
currentURL(),
@ -73,7 +73,7 @@ export default function moduleForJob(
);
});
test('the subnav links to versions', async function(assert) {
test('the subnav links to versions', async function (assert) {
await JobDetail.tabFor('versions').visit();
assert.equal(
currentURL(),
@ -84,7 +84,7 @@ export default function moduleForJob(
);
});
test('the subnav links to evaluations', async function(assert) {
test('the subnav links to evaluations', async function (assert) {
await JobDetail.tabFor('evaluations').visit();
assert.equal(
currentURL(),
@ -95,7 +95,7 @@ export default function moduleForJob(
);
});
test('the title buttons are dependent on job status', async function(assert) {
test('the title buttons are dependent on job status', async function (assert) {
if (job.status === 'dead') {
assert.ok(JobDetail.start.isPresent);
assert.notOk(JobDetail.stop.isPresent);
@ -108,7 +108,7 @@ export default function moduleForJob(
});
if (context === 'allocations') {
test('allocations for the job are shown in the overview', async function(assert) {
test('allocations for the job are shown in the overview', async function (assert) {
assert.ok(
JobDetail.allocationsSummary.isPresent,
'Allocations are shown in the summary section'
@ -119,7 +119,7 @@ export default function moduleForJob(
);
});
test('clicking in an allocation row navigates to that allocation', async function(assert) {
test('clicking in an allocation row navigates to that allocation', async function (assert) {
const allocationRow = JobDetail.allocations[0];
const allocationId = allocationRow.id;
@ -132,7 +132,7 @@ export default function moduleForJob(
);
});
test('clicking legend item navigates to a pre-filtered allocations table', async function(assert) {
test('clicking legend item navigates to a pre-filtered allocations table', async function (assert) {
const legendItem =
JobDetail.allocationsSummary.legend.clickableItems[1];
const status = legendItem.label;
@ -151,7 +151,7 @@ export default function moduleForJob(
assert.deepEqual(gotURL.searchParams, expectedURL.searchParams);
});
test('clicking in a slice takes you to a pre-filtered allocations table', async function(assert) {
test('clicking in a slice takes you to a pre-filtered allocations table', async function (assert) {
const slice = JobDetail.allocationsSummary.slices[1];
const status = slice.label;
await slice.click();
@ -180,7 +180,7 @@ export default function moduleForJob(
}
if (context === 'children') {
test('children for the job are shown in the overview', async function(assert) {
test('children for the job are shown in the overview', async function (assert) {
assert.ok(
JobDetail.childrenSummary.isPresent,
'Children are shown in the summary section'
@ -193,7 +193,7 @@ export default function moduleForJob(
}
for (var testName in additionalTests) {
test(testName, async function(assert) {
test(testName, async function (assert) {
await additionalTests[testName].call(this, job, assert);
});
}
@ -208,20 +208,20 @@ export function moduleForJobWithClientStatus(
) {
let job;
module(title, function(hooks) {
module(title, function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function() {
hooks.beforeEach(async function () {
// Displaying the job status in client requires node:read permission.
const policy = server.create('policy', {
id: 'node-read',
name: 'node-read',
rulesJSON: {
Node: {
Policy: 'read'
}
}
Policy: 'read',
},
},
});
const clientToken = server.create('token', { type: 'client' });
clientToken.policyIds = [policy.id];
@ -232,10 +232,10 @@ export function moduleForJobWithClientStatus(
const clients = server.createList('node', 3, {
datacenter: 'dc1',
status: 'ready'
status: 'ready',
});
job = jobFactory();
clients.forEach(c => {
clients.forEach((c) => {
server.create('allocation', { jobId: job.id, nodeId: c.id });
});
if (!job.namespace || job.namespace === 'default') {
@ -245,7 +245,7 @@ export function moduleForJobWithClientStatus(
}
});
test('job status summary is collapsed when not authorized', async function(assert) {
test('job status summary is collapsed when not authorized', async function (assert) {
const clientToken = server.create('token', { type: 'client' });
await Tokens.visit();
await Tokens.secret(clientToken.secretId).submit();
@ -262,7 +262,7 @@ export function moduleForJobWithClientStatus(
);
});
test('the subnav links to clients', async function(assert) {
test('the subnav links to clients', async function (assert) {
await JobDetail.tabFor('clients').visit();
assert.equal(
currentURL(),
@ -273,14 +273,14 @@ export function moduleForJobWithClientStatus(
);
});
test('job status summary is shown in the overview', async function(assert) {
test('job status summary is shown in the overview', async function (assert) {
assert.ok(
JobDetail.jobClientStatusSummary.statusBar.isPresent,
'Summary bar is displayed in the Job Status in Client summary section'
);
});
test('clicking legend item navigates to a pre-filtered clients table', async function(assert) {
test('clicking legend item navigates to a pre-filtered clients table', async function (assert) {
const legendItem =
JobDetail.jobClientStatusSummary.statusBar.legend.clickableItems[0];
const status = legendItem.label;
@ -299,7 +299,7 @@ export function moduleForJobWithClientStatus(
assert.deepEqual(gotURL.searchParams, expectedURL.searchParams);
});
test('clicking in a slice takes you to a pre-filtered clients table', async function(assert) {
test('clicking in a slice takes you to a pre-filtered clients table', async function (assert) {
const slice = JobDetail.jobClientStatusSummary.statusBar.slices[0];
const status = slice.label;
await slice.click();
@ -325,7 +325,7 @@ export function moduleForJobWithClientStatus(
});
for (var testName in additionalTests) {
test(testName, async function(assert) {
test(testName, async function (assert) {
await additionalTests[testName].call(this, job, assert);
});
}

View file

@ -8,10 +8,10 @@ import Response from 'ember-cli-mirage/response';
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
module('Integration | Component | allocation row', function(hooks) {
module('Integration | Component | allocation row', function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function() {
hooks.beforeEach(function () {
fragmentSerializerInitializer(this.owner);
this.store = this.owner.lookup('service:store');
this.token = this.owner.lookup('service:token');
@ -22,11 +22,11 @@ module('Integration | Component | allocation row', function(hooks) {
window.localStorage.clear();
});
hooks.afterEach(function() {
hooks.afterEach(function () {
this.server.shutdown();
});
test('Allocation row polls for stats, even when it errors or has an invalid response', async 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;
@ -35,10 +35,10 @@ module('Integration | Component | allocation row', function(hooks) {
JSON.stringify({ ResourceUsage: generateResources() }),
null,
'<Not>Valid JSON</Not>',
JSON.stringify({ ResourceUsage: generateResources() })
JSON.stringify({ ResourceUsage: generateResources() }),
];
this.server.get('/client/allocation/:id/stats', function() {
this.server.get('/client/allocation/:id/stats', function () {
const response = frames[++currentFrame];
// Disable polling to stop the EC task in the component
@ -60,7 +60,7 @@ module('Integration | Component | allocation row', function(hooks) {
this.setProperties({
allocation,
context: 'job',
enablePolling: true
enablePolling: true,
});
await render(hbs`
@ -80,16 +80,18 @@ module('Integration | Component | allocation row', function(hooks) {
);
});
test('Allocation row shows warning when it requires drivers that are unhealthy on the node it is running on', async function(assert) {
test('Allocation row shows warning when it requires drivers that are unhealthy on the node it is running on', async function (assert) {
assert.expect(2);
// Driver health status require node:read permission.
const policy = server.create('policy', {
id: 'node-read',
name: 'node-read',
rulesJSON: {
Node: {
Policy: 'read'
}
}
Policy: 'read',
},
},
});
const clientToken = server.create('token', { type: 'client' });
clientToken.policyIds = [policy.id];
@ -101,7 +103,7 @@ module('Integration | Component | allocation row', function(hooks) {
const node = this.server.schema.nodes.first();
const drivers = node.drivers;
Object.values(drivers).forEach(driver => {
Object.values(drivers).forEach((driver) => {
driver.Healthy = false;
driver.Detected = true;
});
@ -116,7 +118,7 @@ module('Integration | Component | allocation row', function(hooks) {
this.setProperties({
allocation,
context: 'job'
context: 'job',
});
await render(hbs`
@ -132,7 +134,9 @@ module('Integration | Component | allocation row', function(hooks) {
await componentA11yAudit(this.element, assert);
});
test('Allocation row shows an icon indicator when it was preempted', async function(assert) {
test('Allocation row shows an icon indicator when it was preempted', async function (assert) {
assert.expect(2);
const allocId = this.server.create('allocation', 'preempted').id;
const allocation = await this.store.findRecord('allocation', allocId);
@ -147,14 +151,16 @@ module('Integration | Component | allocation row', function(hooks) {
await componentA11yAudit(this.element, assert);
});
test('when an allocation is not running, the utilization graphs are omitted', async function(assert) {
test('when an allocation is not running, the utilization graphs are omitted', async function (assert) {
assert.expect(8);
this.setProperties({
context: 'job',
enablePolling: false
enablePolling: false,
});
// All non-running statuses need to be tested
['pending', 'complete', 'failed', 'lost'].forEach(clientStatus =>
['pending', 'complete', 'failed', 'lost'].forEach((clientStatus) =>
this.server.create('allocation', { clientStatus })
);

View file

@ -1,20 +1,21 @@
/* eslint-disable ember-a11y-testing/a11y-audit-called */
import { setComponentTemplate } from '@ember/component';
import Component from '@glimmer/component';
import templateOnlyComponent from '@ember/component/template-only';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { findAll, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | app breadcrumbs', function(hooks) {
module('Integration | Component | app breadcrumbs', function (hooks) {
setupRenderingTest(hooks);
const commonCrumbs = [
{ label: 'Jobs', args: ['jobs.index'] },
{ label: 'Job', args: ['jobs.job.index'] }
{ label: 'Job', args: ['jobs.job.index'] },
];
test('every breadcrumb is rendered correctly', async function(assert) {
test('every breadcrumb is rendered correctly', async function (assert) {
assert.expect(3);
this.set('commonCrumbs', commonCrumbs);
await render(hbs`
<AppBreadcrumbs />
@ -40,21 +41,20 @@ module('Integration | Component | app breadcrumbs', function(hooks) {
});
});
test('when we register a crumb with a type property, a dedicated breadcrumb/<type> component renders', async function(assert) {
test('when we register a crumb with a type property, a dedicated breadcrumb/<type> component renders', async function (assert) {
const crumbs = [
{ label: 'Jobs', args: ['jobs.index'] },
{ type: 'special', label: 'Job', args: ['jobs.job.index'] }
{ type: 'special', label: 'Job', args: ['jobs.job.index'] },
];
this.set('crumbs', crumbs);
class MockComponent extends Component {}
this.owner.register(
'component:breadcrumbs/special',
setComponentTemplate(
hbs`
<div data-test-breadcrumb-special>Test</div>
`,
MockComponent
templateOnlyComponent()
)
);

View file

@ -4,10 +4,10 @@ import { setupRenderingTest } from 'ember-qunit';
import { click, findAll, render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | breadcrumbs', function(hooks) {
module('Integration | Component | breadcrumbs', function (hooks) {
setupRenderingTest(hooks);
test('it declaratively renders a list of registered crumbs', async function(assert) {
test('it declaratively renders a list of registered crumbs', async function (assert) {
this.set('isRegistered', false);
this.set('toggleCrumb', () => this.set('isRegistered', !this.isRegistered));
await render(hbs`
@ -25,8 +25,12 @@ module('Integration | Component | breadcrumbs', function(hooks) {
{{/if}}
`);
assert.dom('[data-test-crumb]').exists({ count: 1 }, 'We register one crumb');
assert.dom('[data-test-crumb]').hasText('Zoey', 'The first registered crumb is Zoey');
assert
.dom('[data-test-crumb]')
.exists({ count: 1 }, 'We register one crumb');
assert
.dom('[data-test-crumb]')
.hasText('Zoey', 'The first registered crumb is Zoey');
await click('[data-test-button]');
const crumbs = await findAll('[data-test-crumb]');
@ -36,19 +40,30 @@ module('Integration | Component | breadcrumbs', function(hooks) {
.exists({ count: 2 }, 'The second crumb registered successfully');
assert
.dom(crumbs[0])
.hasText('Zoey', 'Breadcrumbs maintain the order in which they are declared');
.hasText(
'Zoey',
'Breadcrumbs maintain the order in which they are declared'
);
assert
.dom(crumbs[1])
.hasText('Tomster', 'Breadcrumbs maintain the order in which they are declared');
.hasText(
'Tomster',
'Breadcrumbs maintain the order in which they are declared'
);
await click('[data-test-button]');
assert.dom('[data-test-crumb]').exists({ count: 1 }, 'We deregister one crumb');
assert
.dom('[data-test-crumb]')
.hasText('Zoey', 'Zoey remains in the template after Tomster deregisters');
.exists({ count: 1 }, 'We deregister one crumb');
assert
.dom('[data-test-crumb]')
.hasText(
'Zoey',
'Zoey remains in the template after Tomster deregisters'
);
});
test('it can register complex crumb objects', async function(assert) {
test('it can register complex crumb objects', async function (assert) {
await render(hbs`
<Breadcrumbs as |bb|>
<ul>
@ -62,6 +77,9 @@ module('Integration | Component | breadcrumbs', function(hooks) {
assert
.dom('[data-test-crumb]')
.hasText('Tomster', 'We can access the registered breadcrumbs in the template');
.hasText(
'Tomster',
'We can access the registered breadcrumbs in the template'
);
});
});

View file

@ -4,11 +4,11 @@ import { setupRenderingTest } from 'ember-qunit';
import { render, click, waitFor } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | trigger', function(hooks) {
module('Integration | Component | trigger', function (hooks) {
setupRenderingTest(hooks);
module('Synchronous Interactions', function() {
test('it can trigger a synchronous action', async function(assert) {
module('Synchronous Interactions', function () {
test('it can trigger a synchronous action', async function (assert) {
this.set('name', 'Tomster');
this.set('changeName', () => this.set('name', 'Zoey'));
await render(hbs`
@ -17,16 +17,21 @@ module('Integration | Component | trigger', function(hooks) {
<button data-test-button type="button" {{on "click" trigger.fns.do}}>Change my name.</button>
</Trigger>
`);
assert.dom('[data-test-name]').hasText('Tomster', 'Initial state renders correctly.');
assert
.dom('[data-test-name]')
.hasText('Tomster', 'Initial state renders correctly.');
await click('[data-test-button]');
assert
.dom('[data-test-name]')
.hasText('Zoey', 'The name property changes when the button is clicked');
.hasText(
'Zoey',
'The name property changes when the button is clicked'
);
});
test('it sets the result of the action', async function(assert) {
test('it sets the result of the action', async function (assert) {
this.set('tomster', () => 'Tomster');
await render(hbs`
<Trigger @do={{this.tomster}} as |trigger|>
@ -38,22 +43,27 @@ module('Integration | Component | trigger', function(hooks) {
`);
assert
.dom('[data-test-name]')
.doesNotExist('Initial state does not render because there is no result yet.');
.doesNotExist(
'Initial state does not render because there is no result yet.'
);
await click('[data-test-button]');
assert
.dom('[data-test-name]')
.hasText('Tomster', 'The result state updates after the triggered action');
.hasText(
'Tomster',
'The result state updates after the triggered action'
);
});
});
module('Asynchronous Interactions', function() {
test('it can trigger an asynchronous action', async function(assert) {
module('Asynchronous Interactions', function () {
test('it can trigger an asynchronous action', async function (assert) {
this.set(
'onTrigger',
() =>
new Promise(resolve => {
new Promise((resolve) => {
this.set('resolve', resolve);
})
);
@ -72,15 +82,21 @@ module('Integration | Component | trigger', function(hooks) {
assert
.dom('[data-test-div]')
.doesNotExist('The div does not render until after the action dispatches successfully');
.doesNotExist(
'The div does not render until after the action dispatches successfully'
);
await click('[data-test-button]');
assert
.dom('[data-test-div-loading]')
.exists('Loading state is displayed when the action hasnt resolved yet');
.exists(
'Loading state is displayed when the action hasnt resolved yet'
);
assert
.dom('[data-test-div]')
.doesNotExist('Success message does not display until after promise resolves');
.doesNotExist(
'Success message does not display until after promise resolves'
);
this.resolve();
await waitFor('[data-test-div]');
@ -91,15 +107,21 @@ module('Integration | Component | trigger', function(hooks) {
);
assert
.dom('[data-test-div]')
.exists('Action has dispatched successfully after the promise resolves');
.exists(
'Action has dispatched successfully after the promise resolves'
);
await click('[data-test-button]');
assert
.dom('[data-test-div]')
.doesNotExist('Aftering clicking the button, again, the state is reset');
.doesNotExist(
'Aftering clicking the button, again, the state is reset'
);
assert
.dom('[data-test-div-loading]')
.exists('After clicking the button, again, we are back in the loading state');
.exists(
'After clicking the button, again, we are back in the loading state'
);
this.resolve();
await waitFor('[data-test-div]');
@ -111,11 +133,11 @@ module('Integration | Component | trigger', function(hooks) {
);
});
test('it handles the success state', async function(assert) {
test('it handles the success state', async function (assert) {
this.set(
'onTrigger',
() =>
new Promise(resolve => {
new Promise((resolve) => {
this.set('resolve', resolve);
})
);
@ -132,14 +154,16 @@ module('Integration | Component | trigger', function(hooks) {
assert
.dom('[data-test-div]')
.doesNotExist('No text should appear until after the onSuccess callback is fired');
.doesNotExist(
'No text should appear until after the onSuccess callback is fired'
);
await click('[data-test-button]');
this.resolve();
await waitFor('[data-test-div]');
assert.verifySteps(['On success happened']);
});
test('it handles the error state', async function(assert) {
test('it handles the error state', async function (assert) {
this.set(
'onTrigger',
() =>
@ -166,11 +190,15 @@ module('Integration | Component | trigger', function(hooks) {
await click('[data-test-button]');
assert
.dom('[data-test-div-loading]')
.exists('Loading state is displayed when the action hasnt resolved yet');
.exists(
'Loading state is displayed when the action hasnt resolved yet'
);
assert
.dom('[data-test-div]')
.doesNotExist('No text should appear until after the onError callback is fired');
.doesNotExist(
'No text should appear until after the onError callback is fired'
);
this.reject();
await waitFor('[data-test-span]');
@ -180,7 +208,9 @@ module('Integration | Component | trigger', function(hooks) {
assert
.dom('[data-test-div-loading]')
.exists('The previous error state was cleared and we show loading, again.');
.exists(
'The previous error state was cleared and we show loading, again.'
);
assert.dom('[data-test-div]').doesNotExist('The error state is cleared');

View file

@ -7,7 +7,7 @@ import {
isPresent,
property,
text,
visitable
visitable,
} from 'ember-cli-page-object';
import allocations from 'nomad-ui/tests/pages/components/allocations';
@ -22,7 +22,7 @@ export default create({
tabs: collection('[data-test-tab]', {
id: attribute('data-test-tab'),
visit: clickable('a')
visit: clickable('a'),
}),
tabFor(id) {
@ -44,22 +44,22 @@ export default create({
scope: '[data-test-exec-button]',
isDisabled: property('disabled'),
hasTooltip: hasClass('tooltip'),
tooltipText: attribute('aria-label')
tooltipText: attribute('aria-label'),
},
incrementButton: {
scope: '[data-test-scale-controls-increment]',
isDisabled: property('disabled')
isDisabled: property('disabled'),
},
dispatchButton: {
scope: '[data-test-dispatch-button]',
isDisabled: property('disabled')
isDisabled: property('disabled'),
},
stats: collection('[data-test-job-stat]', {
id: attribute('data-test-job-stat'),
text: text()
text: text(),
}),
statFor(id) {
@ -68,7 +68,7 @@ export default create({
packStats: collection('[data-test-pack-stat]', {
id: attribute('data-test-pack-stat'),
text: text()
text: text(),
}),
packStatFor(id) {
@ -82,8 +82,8 @@ export default create({
scope: '[data-test-accordion-head] [data-test-accordion-toggle]',
click: clickable(),
isDisabled: attribute('disabled'),
tooltip: attribute('aria-label')
}
tooltip: attribute('aria-label'),
},
},
childrenSummary: jobClientStatusBar(
'[data-test-job-summary] [data-test-children-status-bar]'
@ -98,7 +98,7 @@ export default create({
jobsHeader: {
scope: '[data-test-jobs-header]',
hasSubmitTime: isPresent('[data-test-jobs-submit-time-header]'),
hasNamespace: isPresent('[data-test-jobs-namespace-header]')
hasNamespace: isPresent('[data-test-jobs-namespace-header]'),
},
jobs: collection('[data-test-job-row]', {
@ -113,17 +113,17 @@ export default create({
taskGroups: text('[data-test-job-task-groups]'),
clickRow: clickable(),
clickName: clickable('[data-test-job-name] a')
clickName: clickable('[data-test-job-name] a'),
}),
error: {
isPresent: isPresent('[data-test-error]'),
title: text('[data-test-error-title]'),
message: text('[data-test-error-message]'),
seekHelp: clickable('[data-test-error-message] a')
seekHelp: clickable('[data-test-error-message] a'),
},
recentAllocationsEmptyState: {
headline: text('[data-test-empty-recent-allocations-headline]')
}
headline: text('[data-test-empty-recent-allocations-headline]'),
},
});

View file

@ -4,11 +4,11 @@ import { setupTest } from 'ember-qunit';
import Service from '@ember/service';
import setupAbility from 'nomad-ui/tests/helpers/setup-ability';
module('Unit | Ability | client', function(hooks) {
module('Unit | Ability | client', function (hooks) {
setupTest(hooks);
setupAbility('client')(hooks);
test('it permits client read and write when ACLs are disabled', function(assert) {
test('it permits client read and write when ACLs are disabled', function (assert) {
const mockToken = Service.extend({
aclEnabled: false,
});
@ -18,7 +18,7 @@ module('Unit | Ability | client', function(hooks) {
assert.ok(this.ability.canWrite);
});
test('it permits client read and write for management tokens', function(assert) {
test('it permits client read and write for management tokens', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'management' },
@ -29,7 +29,7 @@ module('Unit | Ability | client', function(hooks) {
assert.ok(this.ability.canWrite);
});
test('it permits client read and write for tokens with a policy that has node-write', function(assert) {
test('it permits client read and write for tokens with a policy that has node-write', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
@ -49,7 +49,7 @@ module('Unit | Ability | client', function(hooks) {
assert.ok(this.ability.canWrite);
});
test('it permits client read and write for tokens with a policy that allows write and another policy that disallows it', function(assert) {
test('it permits client read and write for tokens with a policy that allows write and another policy that disallows it', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
@ -76,7 +76,7 @@ module('Unit | Ability | client', function(hooks) {
assert.ok(this.ability.canWrite);
});
test('it permits client read and blocks client write for tokens with a policy that does not allow node-write', function(assert) {
test('it permits client read and blocks client write for tokens with a policy that does not allow node-write', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
@ -96,7 +96,7 @@ module('Unit | Ability | client', function(hooks) {
assert.notOk(this.ability.canWrite);
});
test('it blocks client read and write for tokens without a node policy', function(assert) {
test('it blocks client read and write for tokens without a node policy', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },

View file

@ -51,8 +51,8 @@ class AllocationMock {
}
}
module('Unit | Util | JobClientStatus', function() {
test('it handles the case where all nodes are running', async function(assert) {
module('Unit | Util | JobClientStatus', function () {
test('it handles the case where all nodes are running', async function (assert) {
const node = new NodeMock('node-1', 'dc1');
const nodes = [node];
const job = {
@ -84,7 +84,7 @@ module('Unit | Util | JobClientStatus', function() {
assert.deepEqual(result, expected);
});
test('it handles the degraded case where a node has a failing allocation', async function(assert) {
test('it handles the degraded case where a node has a failing allocation', async function (assert) {
const node = new NodeMock('node-2', 'dc1');
const nodes = [node];
const job = {
@ -120,7 +120,7 @@ module('Unit | Util | JobClientStatus', function() {
assert.deepEqual(result, expected);
});
test('it handles the case where a node has all lost allocations', async function(assert) {
test('it handles the case where a node has all lost allocations', async function (assert) {
const node = new NodeMock('node-1', 'dc1');
const nodes = [node];
const job = {
@ -156,7 +156,7 @@ module('Unit | Util | JobClientStatus', function() {
assert.deepEqual(result, expected);
});
test('it handles the case where a node has all failed allocations', async function(assert) {
test('it handles the case where a node has all failed allocations', async function (assert) {
const node = new NodeMock('node-1', 'dc1');
const nodes = [node];
const job = {
@ -192,7 +192,7 @@ module('Unit | Util | JobClientStatus', function() {
assert.deepEqual(result, expected);
});
test('it handles the degraded case where the expected number of allocations doesnt match the actual number of allocations', async function(assert) {
test('it handles the degraded case where the expected number of allocations doesnt match the actual number of allocations', async function (assert) {
const node = new NodeMock('node-1', 'dc1');
const nodes = [node];
const job = {
@ -228,7 +228,7 @@ module('Unit | Util | JobClientStatus', function() {
assert.deepEqual(result, expected);
});
test('it handles the not scheduled case where a node has no allocations', async function(assert) {
test('it handles the not scheduled case where a node has no allocations', async function (assert) {
const node = new NodeMock('node-1', 'dc1');
const nodes = [node];
const job = {
@ -260,7 +260,7 @@ module('Unit | Util | JobClientStatus', function() {
assert.deepEqual(result, expected);
});
test('it handles the queued case where the job is pending', async function(assert) {
test('it handles the queued case where the job is pending', async function (assert) {
const node = new NodeMock('node-1', 'dc1');
const nodes = [node];
const job = {
@ -296,7 +296,7 @@ module('Unit | Util | JobClientStatus', function() {
assert.deepEqual(result, expected);
});
test('it filters nodes by the datacenter of the job', async function(assert) {
test('it filters nodes by the datacenter of the job', async function (assert) {
const node1 = new NodeMock('node-1', 'dc1');
const node2 = new NodeMock('node-2', 'dc2');
const nodes = [node1, node2];