github.com/hernad/nomad@v1.6.112/ui/tests/acceptance/keyboard-test.js (about)

     1  /**
     2   * Copyright (c) HashiCorp, Inc.
     3   * SPDX-License-Identifier: MPL-2.0
     4   */
     5  
     6  /* eslint-disable qunit/require-expect */
     7  import { module, test } from 'qunit';
     8  import { setupApplicationTest } from 'ember-qunit';
     9  import {
    10    click,
    11    currentURL,
    12    visit,
    13    triggerEvent,
    14    triggerKeyEvent,
    15    findAll,
    16  } from '@ember/test-helpers';
    17  import { setupMirage } from 'ember-cli-mirage/test-support';
    18  import Layout from 'nomad-ui/tests/pages/layout';
    19  import percySnapshot from '@percy/ember';
    20  import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
    21  import faker from 'nomad-ui/mirage/faker';
    22  
    23  module('Acceptance | keyboard', function (hooks) {
    24    setupApplicationTest(hooks);
    25    setupMirage(hooks);
    26  
    27    module('modal', function () {
    28      test('Opening and closing shortcuts modal with key commands', async function (assert) {
    29        faker.seed(1);
    30        assert.expect(4);
    31        await visit('/');
    32        assert.notOk(Layout.keyboard.modalShown);
    33        await triggerEvent('.page-layout', 'keydown', { key: '?' });
    34        assert.ok(Layout.keyboard.modalShown);
    35        await percySnapshot(assert);
    36        await a11yAudit(assert);
    37        await triggerEvent('.page-layout', 'keydown', { key: 'Escape' });
    38        assert.notOk(Layout.keyboard.modalShown);
    39      });
    40  
    41      test('closing shortcuts modal by clicking dismiss', async function (assert) {
    42        await visit('/');
    43        await triggerEvent('.page-layout', 'keydown', { key: '?' });
    44        assert.ok(Layout.keyboard.modalShown);
    45        assert.dom('button.dismiss').isFocused();
    46        await click('button.dismiss');
    47        assert.notOk(Layout.keyboard.modalShown);
    48      });
    49  
    50      test('closing shortcuts modal by clicking outside', async function (assert) {
    51        await visit('/');
    52        await triggerEvent('.page-layout', 'keydown', { key: '?' });
    53        assert.ok(Layout.keyboard.modalShown);
    54        await click('.page-layout');
    55        assert.notOk(Layout.keyboard.modalShown);
    56      });
    57    });
    58  
    59    module('Enable/Disable', function (enableDisableHooks) {
    60      enableDisableHooks.beforeEach(function () {
    61        window.localStorage.clear();
    62      });
    63  
    64      test('Shortcuts work by default and stops working when disabled', async function (assert) {
    65        await visit('/');
    66  
    67        triggerEvent('.page-layout', 'keydown', { key: 'g' });
    68        await triggerEvent('.page-layout', 'keydown', { key: 'c' });
    69        assert.equal(
    70          currentURL(),
    71          `/clients`,
    72          'end up on the clients page after typing g c'
    73        );
    74        assert.notOk(Layout.keyboard.modalShown);
    75        await triggerEvent('.page-layout', 'keydown', { key: '?' });
    76        assert.ok(Layout.keyboard.modalShown);
    77        assert.dom('[data-test-enable-shortcuts-toggle]').hasClass('is-active');
    78        await click('[data-test-enable-shortcuts-toggle]');
    79        assert
    80          .dom('[data-test-enable-shortcuts-toggle]')
    81          .doesNotHaveClass('is-active');
    82        await triggerEvent('.page-layout', 'keydown', { key: 'Escape' });
    83        assert.notOk(Layout.keyboard.modalShown);
    84        triggerEvent('.page-layout', 'keydown', { key: 'g' });
    85        await triggerEvent('.page-layout', 'keydown', { key: 'j' });
    86        assert.equal(
    87          currentURL(),
    88          `/clients`,
    89          'typing g j did not bring you back to the jobs page, since shortcuts are disabled'
    90        );
    91        await triggerEvent('.page-layout', 'keydown', { key: '?' });
    92        await click('[data-test-enable-shortcuts-toggle]');
    93        assert.dom('[data-test-enable-shortcuts-toggle]').hasClass('is-active');
    94        await triggerEvent('.page-layout', 'keydown', { key: 'Escape' });
    95        triggerEvent('.page-layout', 'keydown', { key: 'g' });
    96        await triggerEvent('.page-layout', 'keydown', { key: 'j' });
    97        assert.equal(
    98          currentURL(),
    99          `/jobs`,
   100          'typing g j brings me to the jobs page after re-enabling shortcuts'
   101        );
   102      });
   103    });
   104  
   105    module('Local storage bind/rebind', function (rebindHooks) {
   106      rebindHooks.beforeEach(function () {
   107        window.localStorage.clear();
   108      });
   109  
   110      test('You can rebind shortcuts', async function (assert) {
   111        await visit('/');
   112  
   113        triggerEvent('.page-layout', 'keydown', { key: 'g' });
   114        await triggerEvent('.page-layout', 'keydown', { key: 'c' });
   115        assert.equal(
   116          currentURL(),
   117          `/clients`,
   118          'end up on the clients page after typing g c'
   119        );
   120  
   121        triggerEvent('.page-layout', 'keydown', { key: 'g' });
   122        await triggerEvent('.page-layout', 'keydown', { key: 'j' });
   123        assert.equal(
   124          currentURL(),
   125          `/jobs`,
   126          'end up on the clients page after typing g j'
   127        );
   128  
   129        assert.notOk(Layout.keyboard.modalShown);
   130        await triggerEvent('.page-layout', 'keydown', { key: '?' });
   131        assert.ok(Layout.keyboard.modalShown);
   132  
   133        await click(
   134          '[data-test-command-label="Go to Clients"] button[data-test-rebinder]'
   135        );
   136  
   137        triggerEvent('.page-layout', 'keydown', { key: 'r' });
   138        triggerEvent('.page-layout', 'keydown', { key: 'o' });
   139        triggerEvent('.page-layout', 'keydown', { key: 'f' });
   140        triggerEvent('.page-layout', 'keydown', { key: 'l' });
   141        await triggerEvent('.page-layout', 'keydown', { key: 'Enter' });
   142        assert
   143          .dom(
   144            '[data-test-command-label="Go to Clients"] button[data-test-rebinder]'
   145          )
   146          .hasText('r o f l');
   147  
   148        assert.equal(
   149          currentURL(),
   150          `/jobs`,
   151          'typing g c does not do anything, since I re-bound the shortcut'
   152        );
   153  
   154        triggerEvent('.page-layout', 'keydown', { key: 'r' });
   155        triggerEvent('.page-layout', 'keydown', { key: 'o' });
   156        triggerEvent('.page-layout', 'keydown', { key: 'f' });
   157        await triggerEvent('.page-layout', 'keydown', { key: 'l' });
   158  
   159        assert.equal(
   160          currentURL(),
   161          `/clients`,
   162          'typing the newly bound shortcut brings me to clients'
   163        );
   164  
   165        await click(
   166          '[data-test-command-label="Go to Clients"] button[data-test-rebinder]'
   167        );
   168  
   169        triggerEvent('.page-layout', 'keydown', { key: 'n' });
   170        triggerEvent('.page-layout', 'keydown', { key: 'o' });
   171        triggerEvent('.page-layout', 'keydown', { key: 'p' });
   172        triggerEvent('.page-layout', 'keydown', { key: 'e' });
   173        await triggerEvent('.page-layout', 'keydown', { key: 'Escape' });
   174        assert
   175          .dom(
   176            '[data-test-command-label="Go to Clients"] button[data-test-rebinder]'
   177          )
   178          .hasText(
   179            'r o f l',
   180            'text unchanged when I hit escape during recording'
   181          );
   182  
   183        await click(
   184          '[data-test-command-label="Go to Clients"] button.reset-to-default'
   185        );
   186        assert
   187          .dom(
   188            '[data-test-command-label="Go to Clients"] button[data-test-rebinder]'
   189          )
   190          .hasText('g c', 'Resetting to default rebinds the shortcut');
   191      });
   192  
   193      test('Rebound shortcuts persist from localStorage', async function (assert) {
   194        window.localStorage.setItem(
   195          'keyboard.command.Go to Clients',
   196          JSON.stringify(['b', 'o', 'o', 'p'])
   197        );
   198        await visit('/');
   199  
   200        triggerEvent('.page-layout', 'keydown', { key: 'g' });
   201        await triggerEvent('.page-layout', 'keydown', { key: 'c' });
   202        assert.equal(
   203          currentURL(),
   204          `/jobs`,
   205          'After a refresh with a localStorage-found binding, a default key binding doesnt do anything'
   206        );
   207  
   208        triggerEvent('.page-layout', 'keydown', { key: 'b' });
   209        triggerEvent('.page-layout', 'keydown', { key: 'o' });
   210        triggerEvent('.page-layout', 'keydown', { key: 'o' });
   211        await triggerEvent('.page-layout', 'keydown', { key: 'p' });
   212        assert.equal(
   213          currentURL(),
   214          `/clients`,
   215          'end up on the clients page after typing the localstorage-bound shortcut'
   216        );
   217  
   218        assert.notOk(Layout.keyboard.modalShown);
   219        await triggerEvent('.page-layout', 'keydown', { key: '?' });
   220        assert.ok(Layout.keyboard.modalShown);
   221        assert
   222          .dom(
   223            '[data-test-command-label="Go to Clients"] button[data-test-rebinder]'
   224          )
   225          .hasText('b o o p');
   226      });
   227    });
   228  
   229    module('Hints', function () {
   230      test('Hints show up on shift', async function (assert) {
   231        await visit('/');
   232  
   233        await triggerEvent('.page-layout', 'keydown', { key: 'Shift' });
   234        assert.equal(
   235          document.querySelectorAll('[data-test-keyboard-hint]').length,
   236          7,
   237          'Shows 7 hints by default'
   238        );
   239        await triggerEvent('.page-layout', 'keyup', { key: 'Shift' });
   240  
   241        assert.equal(
   242          document.querySelectorAll('[data-test-keyboard-hint]').length,
   243          0,
   244          'Hints disappear when you release Shift'
   245        );
   246      });
   247    });
   248  
   249    module('Dynamic Nav', function (dynamicHooks) {
   250      dynamicHooks.beforeEach(async function () {
   251        server.create('node-pool');
   252        server.create('node');
   253      });
   254      test('Dynamic Table Nav', async function (assert) {
   255        assert.expect(4);
   256        server.createList('job', 3, { createRecommendations: true });
   257        await visit('/jobs');
   258  
   259        await triggerEvent('.page-layout', 'keydown', { key: 'Shift' });
   260        assert.equal(
   261          document.querySelectorAll('[data-shortcut="Shift+01"]').length,
   262          1,
   263          'First job gets a shortcut hint'
   264        );
   265        assert.equal(
   266          document.querySelectorAll('[data-shortcut="Shift+02"]').length,
   267          1,
   268          'Second job gets a shortcut hint'
   269        );
   270        assert.equal(
   271          document.querySelectorAll('[data-shortcut="Shift+03"]').length,
   272          1,
   273          'Third job gets a shortcut hint'
   274        );
   275  
   276        triggerEvent('.page-layout', 'keydown', { key: 'Shift' });
   277        triggerEvent('.page-layout', 'keydown', { key: '0' });
   278        await triggerEvent('.page-layout', 'keydown', { key: '1' });
   279  
   280        const clickedJob = server.db.jobs.sortBy('modifyIndex').reverse()[0].id;
   281        assert.equal(
   282          currentURL(),
   283          `/jobs/${clickedJob}@default`,
   284          'Shift+01 takes you to the first job'
   285        );
   286      });
   287      test('Multi-Table Nav', async function (assert) {
   288        server.createList('job', 3, { createRecommendations: true });
   289        await visit(
   290          `/jobs/${server.db.jobs.sortBy('modifyIndex').reverse()[0].id}@default`
   291        );
   292        const numberOfGroups = findAll('.task-group-row').length;
   293        const numberOfAllocs = findAll('.allocation-row').length;
   294  
   295        await triggerEvent('.page-layout', 'keydown', { key: 'Shift' });
   296        [...Array(numberOfGroups + numberOfAllocs)].forEach((_, iter) => {
   297          assert.equal(
   298            document.querySelectorAll(`[data-shortcut="Shift+0${iter + 1}"]`)
   299              .length,
   300            1,
   301            `Dynamic item #${iter + 1} gets a shortcut hint`
   302          );
   303        });
   304        await triggerEvent('.page-layout', 'keyup', { key: 'Shift' });
   305      });
   306  
   307      test('Dynamic nav arrows and looping', async function (assert) {
   308        server.createList('job', 3, { createAllocations: true, type: 'system' });
   309        const jobID = server.db.jobs.sortBy('modifyIndex').reverse()[0].id;
   310        await visit(`/jobs/${jobID}@default`);
   311  
   312        await triggerKeyEvent('.page-layout', 'keydown', 'ArrowRight', {
   313          shiftKey: true,
   314        });
   315        assert.ok(
   316          currentURL().startsWith(`/jobs/${jobID}@default/definition`),
   317          'Shift+ArrowRight takes you to the next tab (Definition)'
   318        );
   319  
   320        await triggerKeyEvent('.page-layout', 'keydown', 'ArrowRight', {
   321          shiftKey: true,
   322        });
   323        assert.equal(
   324          currentURL(),
   325          `/jobs/${jobID}@default/versions`,
   326          'Shift+ArrowRight takes you to the next tab (Version)'
   327        );
   328  
   329        await triggerKeyEvent('.page-layout', 'keydown', 'ArrowRight', {
   330          shiftKey: true,
   331        });
   332        assert.equal(
   333          currentURL(),
   334          `/jobs/${jobID}@default/allocations`,
   335          'Shift+ArrowRight takes you to the next tab (Allocations)'
   336        );
   337  
   338        await triggerKeyEvent('.page-layout', 'keydown', 'ArrowRight', {
   339          shiftKey: true,
   340        });
   341        assert.equal(
   342          currentURL(),
   343          `/jobs/${jobID}@default/evaluations`,
   344          'Shift+ArrowRight takes you to the next tab (Evaluations)'
   345        );
   346  
   347        await triggerKeyEvent('.page-layout', 'keydown', 'ArrowRight', {
   348          shiftKey: true,
   349        });
   350        assert.equal(
   351          currentURL(),
   352          `/jobs/${jobID}@default/services`,
   353          'Shift+ArrowRight takes you to the next tab (Services)'
   354        );
   355  
   356        await triggerKeyEvent('.page-layout', 'keydown', 'ArrowRight', {
   357          shiftKey: true,
   358        });
   359        assert.equal(
   360          currentURL(),
   361          `/jobs/${jobID}@default`,
   362          'Shift+ArrowRight takes you to the first tab in the loop'
   363        );
   364      });
   365  
   366      test('Region switching', async function (assert) {
   367        ['Detroit', 'Halifax', 'Phoenix', 'Toronto', 'Windsor'].forEach((id) => {
   368          server.create('region', { id });
   369        });
   370  
   371        await visit('/jobs');
   372  
   373        // Regions are in the keynav modal
   374        await triggerEvent('.page-layout', 'keydown', { key: '?' });
   375        await triggerEvent('.page-layout', 'keydown', { key: '?' });
   376        assert.ok(Layout.keyboard.modalShown);
   377        assert
   378          .dom('[data-test-command-label="Switch to Detroit region"]')
   379          .exists('First created region is in the modal');
   380  
   381        assert
   382          .dom('[data-test-command-label="Switch to Windsor region"]')
   383          .exists('Last created region is in the modal');
   384  
   385        // Triggers a region switch to Halifax
   386        triggerEvent('.page-layout', 'keydown', { key: 'r' });
   387        await triggerEvent('.page-layout', 'keydown', { key: '2' });
   388        assert.ok(
   389          currentURL().includes('region=Halifax'),
   390          'r 2 command takes you to the second region'
   391        );
   392  
   393        // Triggers a region switch to Phoenix
   394        triggerEvent('.page-layout', 'keydown', { key: 'r' });
   395        await triggerEvent('.page-layout', 'keydown', { key: '3' });
   396        assert.ok(
   397          currentURL().includes('region=Phoenix'),
   398          'r 3 command takes you to the third region'
   399        );
   400      });
   401    });
   402  });