github.com/hernad/nomad@v1.6.112/ui/tests/integration/components/fs/file-test.js (about)

     1  /**
     2   * Copyright (c) HashiCorp, Inc.
     3   * SPDX-License-Identifier: MPL-2.0
     4   */
     5  
     6  import { module, test } from 'qunit';
     7  import { setupRenderingTest } from 'ember-qunit';
     8  import { find, click, render, settled } from '@ember/test-helpers';
     9  import hbs from 'htmlbars-inline-precompile';
    10  import Pretender from 'pretender';
    11  import { logEncode } from '../../../../mirage/data/logs';
    12  import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
    13  
    14  const { assign } = Object;
    15  const HOST = '1.1.1.1:1111';
    16  
    17  module('Integration | Component | fs/file', function (hooks) {
    18    setupRenderingTest(hooks);
    19  
    20    hooks.beforeEach(function () {
    21      this.server = new Pretender(function () {
    22        this.get('/v1/agent/members', () => [
    23          200,
    24          {},
    25          JSON.stringify({ ServerRegion: 'default', Members: [] }),
    26        ]);
    27        this.get('/v1/regions', () => [
    28          200,
    29          {},
    30          JSON.stringify(['default', 'region-2']),
    31        ]);
    32        this.get('/v1/client/fs/stream/:alloc_id', () => [
    33          200,
    34          {},
    35          logEncode(['Hello World'], 0),
    36        ]);
    37        this.get('/v1/client/fs/cat/:alloc_id', () => [200, {}, 'Hello World']);
    38        this.get('/v1/client/fs/readat/:alloc_id', () => [
    39          200,
    40          {},
    41          'Hello World',
    42        ]);
    43      });
    44      this.system = this.owner.lookup('service:system');
    45    });
    46  
    47    hooks.afterEach(function () {
    48      this.server.shutdown();
    49      window.localStorage.clear();
    50    });
    51  
    52    const commonTemplate = hbs`
    53      <Fs::File @allocation={{this.allocation}} @taskState={{this.taskState}} @file={{this.file}} @stat={{this.stat}} />
    54    `;
    55  
    56    const fileStat = (type, size = 0) => ({
    57      stat: {
    58        Size: size,
    59        ContentType: type,
    60      },
    61    });
    62    const makeProps = (props = {}) =>
    63      assign(
    64        {},
    65        {
    66          allocation: {
    67            id: 'alloc-1',
    68            node: {
    69              httpAddr: HOST,
    70            },
    71          },
    72          taskState: {
    73            name: 'task-name',
    74          },
    75          file: 'path/to/file',
    76          stat: {
    77            Size: 12345,
    78            ContentType: 'text/plain',
    79          },
    80        },
    81        props
    82      );
    83  
    84    test('When a file is text-based, the file mode is streaming', async function (assert) {
    85      assert.expect(3);
    86  
    87      const props = makeProps(fileStat('text/plain', 500));
    88      this.setProperties(props);
    89  
    90      await render(commonTemplate);
    91  
    92      assert.ok(
    93        find('[data-test-file-box] [data-test-log-cli]'),
    94        'The streaming file component was rendered'
    95      );
    96      assert.notOk(
    97        find('[data-test-file-box] [data-test-image-file]'),
    98        'The image file component was not rendered'
    99      );
   100  
   101      await componentA11yAudit(this.element, assert);
   102    });
   103  
   104    test('When a file is an image, the file mode is image', async function (assert) {
   105      assert.expect(3);
   106  
   107      const props = makeProps(fileStat('image/png', 1234));
   108      this.setProperties(props);
   109  
   110      await render(commonTemplate);
   111  
   112      assert.ok(
   113        find('[data-test-file-box] [data-test-image-file]'),
   114        'The image file component was rendered'
   115      );
   116      assert.notOk(
   117        find('[data-test-file-box] [data-test-log-cli]'),
   118        'The streaming file component was not rendered'
   119      );
   120  
   121      await componentA11yAudit(this.element, assert);
   122    });
   123  
   124    test('When the file is neither text-based or an image, the unsupported file type empty state is shown', async function (assert) {
   125      assert.expect(4);
   126  
   127      const props = makeProps(fileStat('wat/ohno', 1234));
   128      this.setProperties(props);
   129  
   130      await render(commonTemplate);
   131  
   132      assert.notOk(
   133        find('[data-test-file-box] [data-test-image-file]'),
   134        'The image file component was not rendered'
   135      );
   136      assert.notOk(
   137        find('[data-test-file-box] [data-test-log-cli]'),
   138        'The streaming file component was not rendered'
   139      );
   140      assert.ok(
   141        find('[data-test-unsupported-type]'),
   142        'Unsupported file type message is shown'
   143      );
   144      await componentA11yAudit(this.element, assert);
   145    });
   146  
   147    test('The unsupported file type empty state includes a link to the raw file', async function (assert) {
   148      const props = makeProps(fileStat('wat/ohno', 1234));
   149      this.setProperties(props);
   150  
   151      await render(commonTemplate);
   152  
   153      assert.ok(
   154        find('[data-test-unsupported-type] [data-test-log-action="raw"]'),
   155        'Unsupported file type message includes a link to the raw file'
   156      );
   157  
   158      assert.notOk(
   159        find('[data-test-header] [data-test-log-action="raw"]'),
   160        'Raw link is no longer in the header'
   161      );
   162    });
   163  
   164    test('The view raw button goes to the correct API url', async function (assert) {
   165      const props = makeProps(fileStat('image/png', 1234));
   166      this.setProperties(props);
   167  
   168      await render(commonTemplate);
   169      click('[data-test-log-action="raw"]');
   170      await settled();
   171      assert.ok(
   172        this.server.handledRequests.find(
   173          ({ url: url }) =>
   174            url ===
   175            `/v1/client/fs/cat/${props.allocation.id}?path=${encodeURIComponent(
   176              `${props.taskState.name}/${props.file}`
   177            )}`
   178        ),
   179        'Request to file is made'
   180      );
   181    });
   182  
   183    test('The view raw button respects the active region', async function (assert) {
   184      const region = 'region-2';
   185      window.localStorage.nomadActiveRegion = region;
   186  
   187      const props = makeProps(fileStat('image/png', 1234));
   188      this.setProperties(props);
   189  
   190      await this.system.get('regions');
   191      await render(commonTemplate);
   192  
   193      click('[data-test-log-action="raw"]');
   194      await settled();
   195      assert.ok(
   196        this.server.handledRequests.find(
   197          ({ url: url }) =>
   198            url ===
   199            `/v1/client/fs/cat/${props.allocation.id}?path=${encodeURIComponent(
   200              `${props.taskState.name}/${props.file}`
   201            )}&region=${region}`
   202        ),
   203        'Request to file is made with region'
   204      );
   205    });
   206  
   207    test('The head and tail buttons are not shown when the file is small', async function (assert) {
   208      const props = makeProps(fileStat('application/json', 5000));
   209      this.setProperties(props);
   210  
   211      await render(commonTemplate);
   212  
   213      assert.notOk(find('[data-test-log-action="head"]'), 'No head button');
   214      assert.notOk(find('[data-test-log-action="tail"]'), 'No tail button');
   215  
   216      this.set('stat.Size', 100000);
   217  
   218      await settled();
   219  
   220      assert.ok(find('[data-test-log-action="head"]'), 'Head button is shown');
   221      assert.ok(find('[data-test-log-action="tail"]'), 'Tail button is shown');
   222    });
   223  
   224    test('The  head and tail buttons are not shown for an image file', async function (assert) {
   225      const props = makeProps(fileStat('image/svg', 5000));
   226      this.setProperties(props);
   227  
   228      await render(commonTemplate);
   229  
   230      assert.notOk(find('[data-test-log-action="head"]'), 'No head button');
   231      assert.notOk(find('[data-test-log-action="tail"]'), 'No tail button');
   232  
   233      this.set('stat.Size', 100000);
   234  
   235      await settled();
   236  
   237      assert.notOk(find('[data-test-log-action="head"]'), 'Still no head button');
   238      assert.notOk(find('[data-test-log-action="tail"]'), 'Still no tail button');
   239    });
   240  
   241    test('Yielded content goes in the top-left header area', async function (assert) {
   242      assert.expect(2);
   243  
   244      const props = makeProps(fileStat('image/svg', 5000));
   245      this.setProperties(props);
   246  
   247      await render(hbs`
   248        <Fs::File @allocation={{this.allocation}} @taskState={{this.taskState}} @file={{this.file}} @stat={{this.stat}}>
   249          <div data-test-yield-spy>Yielded content</div>
   250        </Fs::File>
   251      `);
   252  
   253      assert.ok(
   254        find('[data-test-header] [data-test-yield-spy]'),
   255        'Yielded content shows up in the header'
   256      );
   257  
   258      await componentA11yAudit(this.element, assert);
   259    });
   260  
   261    test('The body is full-bleed and dark when the file is streaming', async function (assert) {
   262      const props = makeProps(fileStat('application/json', 5000));
   263      this.setProperties(props);
   264  
   265      await render(commonTemplate);
   266  
   267      const classes = Array.from(find('[data-test-file-box]').classList);
   268      assert.ok(classes.includes('is-dark'), 'Body is dark');
   269      assert.ok(classes.includes('is-full-bleed'), 'Body is full-bleed');
   270    });
   271  
   272    test('The body has padding and a light background when the file is not streaming', async function (assert) {
   273      const props = makeProps(fileStat('image/jpeg', 5000));
   274      this.setProperties(props);
   275  
   276      await render(commonTemplate);
   277  
   278      let classes = Array.from(find('[data-test-file-box]').classList);
   279      assert.notOk(classes.includes('is-dark'), 'Body is not dark');
   280      assert.notOk(classes.includes('is-full-bleed'), 'Body is not full-bleed');
   281  
   282      this.set('stat.ContentType', 'something/unknown');
   283  
   284      await settled();
   285  
   286      classes = Array.from(find('[data-test-file-box]').classList);
   287      assert.notOk(classes.includes('is-dark'), 'Body is still not dark');
   288      assert.notOk(
   289        classes.includes('is-full-bleed'),
   290        'Body is still not full-bleed'
   291      );
   292    });
   293  });