github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/tests/acceptance/job-versions-test.js (about)

     1  /* eslint-disable qunit/require-expect */
     2  /* eslint-disable qunit/no-conditional-assertions */
     3  import { currentURL } from '@ember/test-helpers';
     4  import { module, test } from 'qunit';
     5  import { setupApplicationTest } from 'ember-qunit';
     6  import { setupMirage } from 'ember-cli-mirage/test-support';
     7  import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
     8  import Versions from 'nomad-ui/tests/pages/jobs/job/versions';
     9  import Layout from 'nomad-ui/tests/pages/layout';
    10  import moment from 'moment';
    11  
    12  let job;
    13  let namespace;
    14  let versions;
    15  
    16  module('Acceptance | job versions', function (hooks) {
    17    setupApplicationTest(hooks);
    18    setupMirage(hooks);
    19  
    20    hooks.beforeEach(async function () {
    21      server.create('namespace');
    22      namespace = server.create('namespace');
    23  
    24      job = server.create('job', {
    25        namespaceId: namespace.id,
    26        createAllocations: false,
    27      });
    28      versions = server.db.jobVersions.where({ jobId: job.id });
    29  
    30      const managementToken = server.create('token');
    31      window.localStorage.nomadTokenSecret = managementToken.secretId;
    32  
    33      await Versions.visit({ id: `${job.id}@${namespace.id}` });
    34    });
    35  
    36    test('it passes an accessibility audit', async function (assert) {
    37      await a11yAudit(assert);
    38    });
    39  
    40    test('/jobs/:id/versions should list all job versions', async function (assert) {
    41      assert.equal(
    42        Versions.versions.length,
    43        versions.length,
    44        'Each version gets a row in the timeline'
    45      );
    46      assert.equal(document.title, `Job ${job.name} versions - Nomad`);
    47    });
    48  
    49    test('each version mentions the version number, the stability, and the submitted time', async function (assert) {
    50      const version = versions.sortBy('submitTime').reverse()[0];
    51      const formattedSubmitTime = moment(version.submitTime / 1000000).format(
    52        "MMM DD, 'YY HH:mm:ss ZZ"
    53      );
    54      const versionRow = Versions.versions.objectAt(0);
    55  
    56      assert.ok(
    57        versionRow.text.includes(`Version #${version.version}`),
    58        'Version #'
    59      );
    60      assert.equal(versionRow.stability, version.stable.toString(), 'Stability');
    61      assert.equal(versionRow.submitTime, formattedSubmitTime, 'Submit time');
    62    });
    63  
    64    test('all versions but the current one have a button to revert to that version', async function (assert) {
    65      let versionRowToRevertTo;
    66  
    67      Versions.versions.forEach((versionRow) => {
    68        if (versionRow.number === job.version) {
    69          assert.ok(versionRow.revertToButton.isHidden);
    70        } else {
    71          assert.ok(versionRow.revertToButton.isPresent);
    72  
    73          versionRowToRevertTo = versionRow;
    74        }
    75      });
    76  
    77      if (versionRowToRevertTo) {
    78        const versionNumberRevertingTo = versionRowToRevertTo.number;
    79        await versionRowToRevertTo.revertToButton.idle();
    80        await versionRowToRevertTo.revertToButton.confirm();
    81  
    82        const revertRequest = this.server.pretender.handledRequests.find(
    83          (request) => request.url.includes('revert')
    84        );
    85  
    86        assert.equal(
    87          revertRequest.url,
    88          `/v1/job/${job.id}/revert?namespace=${namespace.id}`
    89        );
    90  
    91        assert.deepEqual(JSON.parse(revertRequest.requestBody), {
    92          JobID: job.id,
    93          JobVersion: versionNumberRevertingTo,
    94        });
    95  
    96        assert.equal(currentURL(), `/jobs/${job.id}?namespace=${namespace.id}`);
    97      }
    98    });
    99  
   100    test('when reversion fails, the error message from the API is piped through to the alert', async function (assert) {
   101      const versionRowToRevertTo = Versions.versions.filter(
   102        (versionRow) => versionRow.revertToButton.isPresent
   103      )[0];
   104  
   105      if (versionRowToRevertTo) {
   106        const message = 'A plaintext error message';
   107        server.pretender.post('/v1/job/:id/revert', () => [500, {}, message]);
   108  
   109        await versionRowToRevertTo.revertToButton.idle();
   110        await versionRowToRevertTo.revertToButton.confirm();
   111  
   112        assert.ok(Layout.inlineError.isShown);
   113        assert.ok(Layout.inlineError.isDanger);
   114        assert.ok(Layout.inlineError.title.includes('Could Not Revert'));
   115        assert.equal(Layout.inlineError.message, message);
   116  
   117        await Layout.inlineError.dismiss();
   118  
   119        assert.notOk(Layout.inlineError.isShown);
   120      } else {
   121        assert.expect(0);
   122      }
   123    });
   124  
   125    test('when reversion has no effect, the error message explains', async function (assert) {
   126      const versionRowToRevertTo = Versions.versions.filter(
   127        (versionRow) => versionRow.revertToButton.isPresent
   128      )[0];
   129  
   130      if (versionRowToRevertTo) {
   131        // The default Mirage implementation updates the job version as passed in, this does nothing
   132        server.pretender.post('/v1/job/:id/revert', () => [200, {}, '{}']);
   133  
   134        await versionRowToRevertTo.revertToButton.idle();
   135        await versionRowToRevertTo.revertToButton.confirm();
   136  
   137        assert.ok(Layout.inlineError.isShown);
   138        assert.ok(Layout.inlineError.isWarning);
   139        assert.ok(Layout.inlineError.title.includes('Reversion Had No Effect'));
   140        assert.equal(
   141          Layout.inlineError.message,
   142          'Reverting to an identical older version doesn’t produce a new version'
   143        );
   144      } else {
   145        assert.expect(0);
   146      }
   147    });
   148  
   149    test('when the job for the versions is not found, an error message is shown, but the URL persists', async function (assert) {
   150      await Versions.visit({ id: 'not-a-real-job' });
   151  
   152      assert.equal(
   153        server.pretender.handledRequests
   154          .filter((request) => !request.url.includes('policy'))
   155          .findBy('status', 404).url,
   156        '/v1/job/not-a-real-job',
   157        'A request to the nonexistent job is made'
   158      );
   159      assert.equal(
   160        currentURL(),
   161        '/jobs/not-a-real-job/versions',
   162        'The URL persists'
   163      );
   164      assert.ok(Versions.error.isPresent, 'Error message is shown');
   165      assert.equal(Versions.error.title, 'Not Found', 'Error message is for 404');
   166    });
   167  });
   168  
   169  module('Acceptance | job versions (with client token)', function (hooks) {
   170    setupApplicationTest(hooks);
   171    setupMirage(hooks);
   172  
   173    hooks.beforeEach(async function () {
   174      job = server.create('job', { createAllocations: false });
   175      versions = server.db.jobVersions.where({ jobId: job.id });
   176  
   177      server.create('token');
   178      const clientToken = server.create('token');
   179      window.localStorage.nomadTokenSecret = clientToken.secretId;
   180  
   181      await Versions.visit({ id: job.id });
   182    });
   183  
   184    test('reversion buttons are disabled when the token lacks permissions', async function (assert) {
   185      const versionRowWithReversion = Versions.versions.filter(
   186        (versionRow) => versionRow.revertToButton.isPresent
   187      )[0];
   188  
   189      if (versionRowWithReversion) {
   190        assert.ok(versionRowWithReversion.revertToButtonIsDisabled);
   191      } else {
   192        assert.expect(0);
   193      }
   194  
   195      window.localStorage.clear();
   196    });
   197  
   198    test('reversion buttons are available when the client token has permissions', async function (assert) {
   199      const REVERT_NAMESPACE = 'revert-namespace';
   200      window.localStorage.clear();
   201      const clientToken = server.create('token');
   202  
   203      server.create('namespace', { id: REVERT_NAMESPACE });
   204  
   205      const job = server.create('job', {
   206        groupCount: 0,
   207        createAllocations: false,
   208        shallow: true,
   209        noActiveDeployment: true,
   210        namespaceId: REVERT_NAMESPACE,
   211      });
   212  
   213      const policy = server.create('policy', {
   214        id: 'something',
   215        name: 'something',
   216        rulesJSON: {
   217          Namespaces: [
   218            {
   219              Name: REVERT_NAMESPACE,
   220              Capabilities: ['submit-job'],
   221            },
   222          ],
   223        },
   224      });
   225  
   226      clientToken.policyIds = [policy.id];
   227      clientToken.save();
   228  
   229      window.localStorage.nomadTokenSecret = clientToken.secretId;
   230  
   231      versions = server.db.jobVersions.where({ jobId: job.id });
   232      await Versions.visit({ id: job.id, namespace: REVERT_NAMESPACE });
   233      const versionRowWithReversion = Versions.versions.filter(
   234        (versionRow) => versionRow.revertToButton.isPresent
   235      )[0];
   236  
   237      if (versionRowWithReversion) {
   238        assert.ok(versionRowWithReversion.revertToButtonIsDisabled);
   239      } else {
   240        assert.expect(0);
   241      }
   242    });
   243  });