29de8f4f76
This continues #8455 by adding accessibility audits to component integration tests and fixing associated errors. It adds audits to existing tests rather than adding separate ones to facilitate auditing the various permutations a component’s rendering can go through. It also adds linting to ensure audits happen in component tests. This necessitated consolidating test files that were scattered.
263 lines
8.3 KiB
JavaScript
263 lines
8.3 KiB
JavaScript
import { module, test } from 'qunit';
|
|
import { setupRenderingTest } from 'ember-qunit';
|
|
import { find, render, settled } from '@ember/test-helpers';
|
|
import hbs from 'htmlbars-inline-precompile';
|
|
import Pretender from 'pretender';
|
|
import { logEncode } from '../../../../mirage/data/logs';
|
|
import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
|
|
|
|
const { assign } = Object;
|
|
const HOST = '1.1.1.1:1111';
|
|
|
|
module('Integration | Component | fs/file', function(hooks) {
|
|
setupRenderingTest(hooks);
|
|
|
|
hooks.beforeEach(function() {
|
|
this.server = new Pretender(function() {
|
|
this.get('/v1/agent/members', () => [
|
|
200,
|
|
{},
|
|
JSON.stringify({ ServerRegion: 'default', Members: [] }),
|
|
]);
|
|
this.get('/v1/regions', () => [200, {}, JSON.stringify(['default', 'region-2'])]);
|
|
this.get('/v1/client/fs/stream/:alloc_id', () => [200, {}, logEncode(['Hello World'], 0)]);
|
|
this.get('/v1/client/fs/cat/:alloc_id', () => [200, {}, 'Hello World']);
|
|
this.get('/v1/client/fs/readat/:alloc_id', () => [200, {}, 'Hello World']);
|
|
});
|
|
this.system = this.owner.lookup('service:system');
|
|
});
|
|
|
|
hooks.afterEach(function() {
|
|
this.server.shutdown();
|
|
window.localStorage.clear();
|
|
});
|
|
|
|
const commonTemplate = hbs`
|
|
<Fs::File @allocation={{allocation}} @taskState={{taskState}} @file={{file}} @stat={{stat}} />
|
|
`;
|
|
|
|
const fileStat = (type, size = 0) => ({
|
|
stat: {
|
|
Size: size,
|
|
ContentType: type,
|
|
},
|
|
});
|
|
const makeProps = (props = {}) =>
|
|
assign(
|
|
{},
|
|
{
|
|
allocation: {
|
|
id: 'alloc-1',
|
|
node: {
|
|
httpAddr: HOST,
|
|
},
|
|
},
|
|
taskState: {
|
|
name: 'task-name',
|
|
},
|
|
file: 'path/to/file',
|
|
stat: {
|
|
Size: 12345,
|
|
ContentType: 'text/plain',
|
|
},
|
|
},
|
|
props
|
|
);
|
|
|
|
test('When a file is text-based, the file mode is streaming', async function(assert) {
|
|
const props = makeProps(fileStat('text/plain', 500));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
assert.ok(
|
|
find('[data-test-file-box] [data-test-log-cli]'),
|
|
'The streaming file component was rendered'
|
|
);
|
|
assert.notOk(
|
|
find('[data-test-file-box] [data-test-image-file]'),
|
|
'The image file component was not rendered'
|
|
);
|
|
|
|
await componentA11yAudit(this.element, assert);
|
|
});
|
|
|
|
test('When a file is an image, the file mode is image', async function(assert) {
|
|
const props = makeProps(fileStat('image/png', 1234));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
assert.ok(
|
|
find('[data-test-file-box] [data-test-image-file]'),
|
|
'The image file component was rendered'
|
|
);
|
|
assert.notOk(
|
|
find('[data-test-file-box] [data-test-log-cli]'),
|
|
'The streaming file component was not rendered'
|
|
);
|
|
|
|
await componentA11yAudit(this.element, assert);
|
|
});
|
|
|
|
test('When the file is neither text-based or an image, the unsupported file type empty state is shown', async function(assert) {
|
|
const props = makeProps(fileStat('wat/ohno', 1234));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
assert.notOk(
|
|
find('[data-test-file-box] [data-test-image-file]'),
|
|
'The image file component was not rendered'
|
|
);
|
|
assert.notOk(
|
|
find('[data-test-file-box] [data-test-log-cli]'),
|
|
'The streaming file component was not rendered'
|
|
);
|
|
assert.ok(find('[data-test-unsupported-type]'), 'Unsupported file type message is shown');
|
|
await componentA11yAudit(this.element, assert);
|
|
});
|
|
|
|
test('The unsupported file type empty state includes a link to the raw file', async function(assert) {
|
|
const props = makeProps(fileStat('wat/ohno', 1234));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
assert.ok(
|
|
find('[data-test-unsupported-type] [data-test-log-action="raw"]'),
|
|
'Unsupported file type message includes a link to the raw file'
|
|
);
|
|
|
|
assert.notOk(
|
|
find('[data-test-header] [data-test-log-action="raw"]'),
|
|
'Raw link is no longer in the header'
|
|
);
|
|
});
|
|
|
|
test('The view raw button goes to the correct API url', async function(assert) {
|
|
const props = makeProps(fileStat('image/png', 1234));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
const rawLink = find('[data-test-log-action="raw"]');
|
|
assert.equal(
|
|
rawLink.getAttribute('href'),
|
|
`/v1/client/fs/cat/${props.allocation.id}?path=${encodeURIComponent(
|
|
`${props.taskState.name}/${props.file}`
|
|
)}`,
|
|
'Raw link href is correct'
|
|
);
|
|
|
|
assert.equal(rawLink.getAttribute('target'), '_blank', 'Raw link opens in a new tab');
|
|
assert.equal(
|
|
rawLink.getAttribute('rel'),
|
|
'noopener noreferrer',
|
|
'Raw link rel correctly bars openers and referrers'
|
|
);
|
|
});
|
|
|
|
test('The view raw button respects the active region', async function(assert) {
|
|
const region = 'region-2';
|
|
window.localStorage.nomadActiveRegion = region;
|
|
|
|
const props = makeProps(fileStat('image/png', 1234));
|
|
this.setProperties(props);
|
|
|
|
await this.system.get('regions');
|
|
await render(commonTemplate);
|
|
|
|
const rawLink = find('[data-test-log-action="raw"]');
|
|
assert.equal(
|
|
rawLink.getAttribute('href'),
|
|
`/v1/client/fs/cat/${props.allocation.id}?path=${encodeURIComponent(
|
|
`${props.taskState.name}/${props.file}`
|
|
)}®ion=${region}`,
|
|
'Raw link href includes the active region from local storage'
|
|
);
|
|
});
|
|
|
|
test('The head and tail buttons are not shown when the file is small', async function(assert) {
|
|
const props = makeProps(fileStat('application/json', 5000));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
assert.notOk(find('[data-test-log-action="head"]'), 'No head button');
|
|
assert.notOk(find('[data-test-log-action="tail"]'), 'No tail button');
|
|
|
|
this.set('stat.Size', 100000);
|
|
|
|
await settled();
|
|
|
|
assert.ok(find('[data-test-log-action="head"]'), 'Head button is shown');
|
|
assert.ok(find('[data-test-log-action="tail"]'), 'Tail button is shown');
|
|
});
|
|
|
|
test('The head and tail buttons are not shown for an image file', async function(assert) {
|
|
const props = makeProps(fileStat('image/svg', 5000));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
assert.notOk(find('[data-test-log-action="head"]'), 'No head button');
|
|
assert.notOk(find('[data-test-log-action="tail"]'), 'No tail button');
|
|
|
|
this.set('stat.Size', 100000);
|
|
|
|
await settled();
|
|
|
|
assert.notOk(find('[data-test-log-action="head"]'), 'Still no head button');
|
|
assert.notOk(find('[data-test-log-action="tail"]'), 'Still no tail button');
|
|
});
|
|
|
|
test('Yielded content goes in the top-left header area', async function(assert) {
|
|
const props = makeProps(fileStat('image/svg', 5000));
|
|
this.setProperties(props);
|
|
|
|
await render(hbs`
|
|
<Fs::File @allocation={{allocation}} @taskState={{taskState}} @file={{file}} @stat={{stat}}>
|
|
<div data-test-yield-spy>Yielded content</div>
|
|
</Fs::File>
|
|
`);
|
|
|
|
assert.ok(
|
|
find('[data-test-header] [data-test-yield-spy]'),
|
|
'Yielded content shows up in the header'
|
|
);
|
|
|
|
await componentA11yAudit(this.element, assert);
|
|
});
|
|
|
|
test('The body is full-bleed and dark when the file is streaming', async function(assert) {
|
|
const props = makeProps(fileStat('application/json', 5000));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
const classes = Array.from(find('[data-test-file-box]').classList);
|
|
assert.ok(classes.includes('is-dark'), 'Body is dark');
|
|
assert.ok(classes.includes('is-full-bleed'), 'Body is full-bleed');
|
|
});
|
|
|
|
test('The body has padding and a light background when the file is not streaming', async function(assert) {
|
|
const props = makeProps(fileStat('image/jpeg', 5000));
|
|
this.setProperties(props);
|
|
|
|
await render(commonTemplate);
|
|
|
|
let classes = Array.from(find('[data-test-file-box]').classList);
|
|
assert.notOk(classes.includes('is-dark'), 'Body is not dark');
|
|
assert.notOk(classes.includes('is-full-bleed'), 'Body is not full-bleed');
|
|
|
|
this.set('stat.ContentType', 'something/unknown');
|
|
|
|
await settled();
|
|
|
|
classes = Array.from(find('[data-test-file-box]').classList);
|
|
assert.notOk(classes.includes('is-dark'), 'Body is still not dark');
|
|
assert.notOk(classes.includes('is-full-bleed'), 'Body is still not full-bleed');
|
|
});
|
|
});
|