3350f3fb11
Async tests should use in integrations tests. Acceptance tests are using Mirage and can't use since we can't know the number of assertions.
220 lines
6.5 KiB
JavaScript
220 lines
6.5 KiB
JavaScript
/* eslint-disable qunit/require-expect */
|
|
import { currentURL } from '@ember/test-helpers';
|
|
import { module, test } from 'qunit';
|
|
import { setupApplicationTest } from 'ember-qunit';
|
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
|
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
|
|
import Clients from 'nomad-ui/tests/pages/jobs/job/clients';
|
|
|
|
let job;
|
|
let clients;
|
|
|
|
const makeSearchableClients = (server, job) => {
|
|
Array(10)
|
|
.fill(null)
|
|
.map((_, index) => {
|
|
const node = server.create('node', {
|
|
id: index < 5 ? `ffffff-dddddd-${index}` : `111111-222222-${index}`,
|
|
datacenter: 'dc1',
|
|
status: 'ready',
|
|
});
|
|
server.create('allocation', { jobId: job.id, nodeId: node.id });
|
|
});
|
|
};
|
|
|
|
module('Acceptance | job clients', function (hooks) {
|
|
setupApplicationTest(hooks);
|
|
setupMirage(hooks);
|
|
|
|
hooks.beforeEach(function () {
|
|
clients = server.createList('node', 12, {
|
|
datacenter: 'dc1',
|
|
status: 'ready',
|
|
});
|
|
// Job with 1 task group.
|
|
job = server.create('job', {
|
|
status: 'running',
|
|
datacenters: ['dc1'],
|
|
type: 'sysbatch',
|
|
resourceSpec: ['M: 256, C: 500'],
|
|
createAllocations: false,
|
|
});
|
|
clients.forEach((c) => {
|
|
server.create('allocation', { jobId: job.id, nodeId: c.id });
|
|
});
|
|
|
|
// Create clients without allocations to have some 'not scheduled' job status.
|
|
clients = clients.concat(
|
|
server.createList('node', 3, {
|
|
datacenter: 'dc1',
|
|
status: 'ready',
|
|
})
|
|
);
|
|
});
|
|
|
|
test('it passes an accessibility audit', async function (assert) {
|
|
await Clients.visit({ id: job.id });
|
|
await a11yAudit(assert);
|
|
});
|
|
|
|
test('lists all clients for the job', async function (assert) {
|
|
await Clients.visit({ id: job.id });
|
|
assert.equal(Clients.clients.length, 15, 'Clients are shown in a table');
|
|
|
|
const clientIDs = clients.sortBy('id').map((c) => c.id);
|
|
const clientsInTable = Clients.clients.map((c) => c.id).sort();
|
|
assert.deepEqual(clientsInTable, clientIDs);
|
|
|
|
assert.equal(document.title, `Job ${job.name} clients - Nomad`);
|
|
});
|
|
|
|
test('dates have tooltip', async function (assert) {
|
|
await Clients.visit({ id: job.id });
|
|
|
|
Clients.clients.forEach((clientRow, index) => {
|
|
const jobStatus = Clients.clientFor(clientRow.id).status;
|
|
|
|
['createTime', 'modifyTime'].forEach((col) => {
|
|
if (jobStatus === 'not scheduled') {
|
|
/* eslint-disable-next-line qunit/no-conditional-assertions */
|
|
assert.equal(
|
|
clientRow[col].text,
|
|
'-',
|
|
`row ${index} doesn't have ${col} tooltip`
|
|
);
|
|
/* eslint-disable-next-line qunit/no-early-return */
|
|
return;
|
|
}
|
|
|
|
const hasTooltip = clientRow[col].tooltip.isPresent;
|
|
const tooltipText = clientRow[col].tooltip.text;
|
|
assert.true(hasTooltip, `row ${index} has ${col} tooltip`);
|
|
assert.ok(
|
|
tooltipText,
|
|
`row ${index} has ${col} tooltip content ${tooltipText}`
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
test('clients table is sortable', async function (assert) {
|
|
await Clients.visit({ id: job.id });
|
|
await Clients.sortBy('node.name');
|
|
|
|
assert.equal(
|
|
currentURL(),
|
|
`/jobs/${job.id}/clients?desc=true&sort=node.name`,
|
|
'the URL persists the sort parameter'
|
|
);
|
|
|
|
const sortedClients = clients.sortBy('name').reverse();
|
|
Clients.clients.forEach((client, index) => {
|
|
const shortId = sortedClients[index].id.split('-')[0];
|
|
assert.equal(
|
|
client.shortId,
|
|
shortId,
|
|
`Client ${index} is ${shortId} with name ${sortedClients[index].name}`
|
|
);
|
|
});
|
|
});
|
|
|
|
test('clients table is searchable', async function (assert) {
|
|
makeSearchableClients(server, job);
|
|
|
|
await Clients.visit({ id: job.id });
|
|
await Clients.search('ffffff');
|
|
|
|
assert.equal(Clients.clients.length, 5, 'List is filtered by search term');
|
|
});
|
|
|
|
test('when a search yields no results, the search box remains', async function (assert) {
|
|
makeSearchableClients(server, job);
|
|
|
|
await Clients.visit({ id: job.id });
|
|
await Clients.search('^nothing will ever match this long regex$');
|
|
|
|
assert.equal(
|
|
Clients.emptyState.headline,
|
|
'No Matches',
|
|
'List is empty and the empty state is about search'
|
|
);
|
|
|
|
assert.ok(Clients.hasSearchBox, 'Search box is still shown');
|
|
});
|
|
|
|
test('when the job for the clients is not found, an error message is shown, but the URL persists', async function (assert) {
|
|
await Clients.visit({ id: 'not-a-real-job' });
|
|
|
|
assert.equal(
|
|
server.pretender.handledRequests
|
|
.filter((request) => !request.url.includes('policy'))
|
|
.findBy('status', 404).url,
|
|
'/v1/job/not-a-real-job',
|
|
'A request to the nonexistent job is made'
|
|
);
|
|
assert.equal(
|
|
currentURL(),
|
|
'/jobs/not-a-real-job/clients',
|
|
'The URL persists'
|
|
);
|
|
assert.ok(Clients.error.isPresent, 'Error message is shown');
|
|
assert.equal(Clients.error.title, 'Not Found', 'Error message is for 404');
|
|
});
|
|
|
|
test('clicking row goes to client details', async function (assert) {
|
|
const client = clients[0];
|
|
|
|
await Clients.visit({ id: job.id });
|
|
await Clients.clientFor(client.id).click();
|
|
assert.equal(currentURL(), `/clients/${client.id}`);
|
|
|
|
await Clients.visit({ id: job.id });
|
|
await Clients.clientFor(client.id).visit();
|
|
assert.equal(currentURL(), `/clients/${client.id}`);
|
|
|
|
await Clients.visit({ id: job.id });
|
|
await Clients.clientFor(client.id).visitRow();
|
|
assert.equal(currentURL(), `/clients/${client.id}`);
|
|
});
|
|
|
|
testFacet('Job Status', {
|
|
facet: Clients.facets.jobStatus,
|
|
paramName: 'jobStatus',
|
|
expectedOptions: [
|
|
'Queued',
|
|
'Not Scheduled',
|
|
'Starting',
|
|
'Running',
|
|
'Complete',
|
|
'Degraded',
|
|
'Failed',
|
|
'Lost',
|
|
],
|
|
async beforeEach() {
|
|
await Clients.visit({ id: job.id });
|
|
},
|
|
});
|
|
|
|
function testFacet(label, { facet, paramName, beforeEach, expectedOptions }) {
|
|
test(`the ${label} facet has the correct options`, async function (assert) {
|
|
await beforeEach();
|
|
await facet.toggle();
|
|
|
|
let expectation;
|
|
if (typeof expectedOptions === 'function') {
|
|
expectation = expectedOptions();
|
|
} else {
|
|
expectation = expectedOptions;
|
|
}
|
|
|
|
assert.deepEqual(
|
|
facet.options.map((option) => option.label.trim()),
|
|
expectation,
|
|
`Options for facet ${paramName} are as expected`
|
|
);
|
|
});
|
|
|
|
// TODO: add facet tests for actual list filtering
|
|
}
|
|
});
|