2019-07-31 00:21:12 +00:00
|
|
|
import { module, test } from 'qunit';
|
|
|
|
import { setupRenderingTest } from 'ember-qunit';
|
2020-10-31 20:11:14 +00:00
|
|
|
import { find, click, render, settled } from '@ember/test-helpers';
|
2019-07-31 00:21:12 +00:00
|
|
|
import hbs from 'htmlbars-inline-precompile';
|
|
|
|
import Pretender from 'pretender';
|
2020-08-25 15:56:02 +00:00
|
|
|
import { logEncode } from '../../../../mirage/data/logs';
|
|
|
|
import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
|
2019-07-31 00:21:12 +00:00
|
|
|
|
|
|
|
const { assign } = Object;
|
|
|
|
const HOST = '1.1.1.1:1111';
|
|
|
|
|
2020-06-01 13:15:59 +00:00
|
|
|
module('Integration | Component | fs/file', function(hooks) {
|
2019-07-31 00:21:12 +00:00
|
|
|
setupRenderingTest(hooks);
|
|
|
|
|
|
|
|
hooks.beforeEach(function() {
|
|
|
|
this.server = new Pretender(function() {
|
2020-07-22 20:46:38 +00:00
|
|
|
this.get('/v1/agent/members', () => [
|
|
|
|
200,
|
|
|
|
{},
|
|
|
|
JSON.stringify({ ServerRegion: 'default', Members: [] }),
|
|
|
|
]);
|
|
|
|
this.get('/v1/regions', () => [200, {}, JSON.stringify(['default', 'region-2'])]);
|
2019-07-31 00:21:12 +00:00
|
|
|
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']);
|
|
|
|
});
|
2020-07-22 20:46:38 +00:00
|
|
|
this.system = this.owner.lookup('service:system');
|
2019-07-31 00:21:12 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
hooks.afterEach(function() {
|
|
|
|
this.server.shutdown();
|
2020-07-22 20:46:38 +00:00
|
|
|
window.localStorage.clear();
|
2019-07-31 00:21:12 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
const commonTemplate = hbs`
|
2020-07-09 17:30:11 +00:00
|
|
|
<Fs::File @allocation={{allocation}} @taskState={{taskState}} @file={{file}} @stat={{stat}} />
|
2019-07-31 00:21:12 +00:00
|
|
|
`;
|
|
|
|
|
|
|
|
const fileStat = (type, size = 0) => ({
|
|
|
|
stat: {
|
|
|
|
Size: size,
|
|
|
|
ContentType: type,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
const makeProps = (props = {}) =>
|
|
|
|
assign(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
allocation: {
|
|
|
|
id: 'alloc-1',
|
|
|
|
node: {
|
|
|
|
httpAddr: HOST,
|
|
|
|
},
|
|
|
|
},
|
2020-06-01 19:03:56 +00:00
|
|
|
taskState: {
|
2019-07-31 00:21:12 +00:00
|
|
|
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'
|
|
|
|
);
|
2020-08-25 15:56:02 +00:00
|
|
|
|
|
|
|
await componentA11yAudit(this.element, assert);
|
2019-07-31 00:21:12 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
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'
|
|
|
|
);
|
2020-08-25 15:56:02 +00:00
|
|
|
|
|
|
|
await componentA11yAudit(this.element, assert);
|
2019-07-31 00:21:12 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
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');
|
2020-08-25 15:56:02 +00:00
|
|
|
await componentA11yAudit(this.element, assert);
|
2019-07-31 00:21:12 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
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);
|
2020-10-31 20:11:14 +00:00
|
|
|
click('[data-test-log-action="raw"]');
|
|
|
|
await settled();
|
|
|
|
assert.ok(
|
|
|
|
this.server.handledRequests.find(
|
|
|
|
({ url: url }) =>
|
|
|
|
url ===
|
|
|
|
`/v1/client/fs/cat/${props.allocation.id}?path=${encodeURIComponent(
|
|
|
|
`${props.taskState.name}/${props.file}`
|
|
|
|
)}`
|
|
|
|
),
|
|
|
|
'Request to file is made'
|
2019-07-31 00:21:12 +00:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2020-07-22 20:46:38 +00:00
|
|
|
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);
|
|
|
|
|
2020-10-31 20:11:14 +00:00
|
|
|
click('[data-test-log-action="raw"]');
|
|
|
|
await settled();
|
|
|
|
assert.ok(
|
|
|
|
this.server.handledRequests.find(
|
|
|
|
({ url: url }) =>
|
|
|
|
url ===
|
|
|
|
`/v1/client/fs/cat/${props.allocation.id}?path=${encodeURIComponent(
|
|
|
|
`${props.taskState.name}/${props.file}`
|
|
|
|
)}®ion=${region}`
|
|
|
|
),
|
|
|
|
'Request to file is made with region'
|
2020-07-22 20:46:38 +00:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2019-07-31 00:21:12 +00:00
|
|
|
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`
|
2020-07-09 17:30:11 +00:00
|
|
|
<Fs::File @allocation={{allocation}} @taskState={{taskState}} @file={{file}} @stat={{stat}}>
|
2019-07-31 00:21:12 +00:00
|
|
|
<div data-test-yield-spy>Yielded content</div>
|
2020-07-09 17:30:11 +00:00
|
|
|
</Fs::File>
|
2019-07-31 00:21:12 +00:00
|
|
|
`);
|
|
|
|
|
|
|
|
assert.ok(
|
|
|
|
find('[data-test-header] [data-test-yield-spy]'),
|
|
|
|
'Yielded content shows up in the header'
|
|
|
|
);
|
2020-08-25 15:56:02 +00:00
|
|
|
|
|
|
|
await componentA11yAudit(this.element, assert);
|
2019-07-31 00:21:12 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
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');
|
|
|
|
});
|
|
|
|
});
|