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

     1  /**
     2   * Copyright (c) HashiCorp, Inc.
     3   * SPDX-License-Identifier: MPL-2.0
     4   */
     5  
     6  /* eslint-disable ember-a11y-testing/a11y-audit-called */
     7  /* eslint-disable qunit/require-expect */
     8  import { module, test } from 'qunit';
     9  import { currentURL, triggerEvent, visit } from '@ember/test-helpers';
    10  import { setupApplicationTest } from 'ember-qunit';
    11  import { setupMirage } from 'ember-cli-mirage/test-support';
    12  import Layout from 'nomad-ui/tests/pages/layout';
    13  import JobsList from 'nomad-ui/tests/pages/jobs/list';
    14  import { selectSearch } from 'ember-power-select/test-support';
    15  import Response from 'ember-cli-mirage/response';
    16  
    17  module('Acceptance | search', function (hooks) {
    18    setupApplicationTest(hooks);
    19    setupMirage(hooks);
    20  
    21    test('search exposes and navigates to results from the fuzzy search endpoint', async function (assert) {
    22      server.create('node-pool');
    23      server.create('node', { name: 'xyz' });
    24      const otherNode = server.create('node', { name: 'ghi' });
    25  
    26      server.create('namespace');
    27      server.create('namespace', { id: 'dev' });
    28  
    29      server.create('job', {
    30        id: 'vwxyz',
    31        namespaceId: 'default',
    32        groupsCount: 1,
    33        groupTaskCount: 1,
    34      });
    35      server.create('job', {
    36        id: 'xyz',
    37        name: 'xyz job',
    38        namespaceId: 'default',
    39        groupsCount: 1,
    40        groupTaskCount: 1,
    41      });
    42      server.create('job', {
    43        id: 'xyzw',
    44        name: 'xyzw job',
    45        namespaceId: 'dev',
    46        groupsCount: 1,
    47        groupTaskCount: 1,
    48      });
    49      server.create('job', {
    50        id: 'abc',
    51        namespaceId: 'default',
    52        groupsCount: 1,
    53        groupTaskCount: 1,
    54      });
    55  
    56      const firstAllocation = server.schema.allocations.all().models[0];
    57      const firstTaskGroup = server.schema.taskGroups.all().models[0];
    58      const namespacedTaskGroup = server.schema.taskGroups.all().models[2];
    59  
    60      server.create('csi-plugin', { id: 'xyz-plugin', createVolumes: false });
    61  
    62      await visit('/');
    63  
    64      await selectSearch(Layout.navbar.search.scope, 'xy');
    65  
    66      Layout.navbar.search.as((search) => {
    67        assert.equal(search.groups.length, 5);
    68  
    69        search.groups[0].as((jobs) => {
    70          assert.equal(jobs.name, 'Jobs (3)');
    71          assert.equal(jobs.options.length, 3);
    72          assert.equal(jobs.options[0].text, 'default > vwxyz');
    73          assert.equal(jobs.options[1].text, 'default > xyz job');
    74          assert.equal(jobs.options[2].text, 'dev > xyzw job');
    75        });
    76  
    77        search.groups[1].as((clients) => {
    78          assert.equal(clients.name, 'Clients (1)');
    79          assert.equal(clients.options.length, 1);
    80          assert.equal(clients.options[0].text, 'xyz');
    81        });
    82  
    83        search.groups[2].as((allocs) => {
    84          assert.equal(allocs.name, 'Allocations (0)');
    85          assert.equal(allocs.options.length, 0);
    86        });
    87  
    88        search.groups[3].as((groups) => {
    89          assert.equal(groups.name, 'Task Groups (0)');
    90          assert.equal(groups.options.length, 0);
    91        });
    92  
    93        search.groups[4].as((plugins) => {
    94          assert.equal(plugins.name, 'CSI Plugins (1)');
    95          assert.equal(plugins.options.length, 1);
    96          assert.equal(plugins.options[0].text, 'xyz-plugin');
    97        });
    98      });
    99  
   100      await Layout.navbar.search.groups[0].options[1].click();
   101      assert.equal(currentURL(), '/jobs/xyz@default');
   102  
   103      await selectSearch(Layout.navbar.search.scope, 'xy');
   104      await Layout.navbar.search.groups[0].options[2].click();
   105      assert.equal(currentURL(), '/jobs/xyzw@dev');
   106  
   107      await selectSearch(Layout.navbar.search.scope, otherNode.name);
   108      await Layout.navbar.search.groups[1].options[0].click();
   109      assert.equal(currentURL(), `/clients/${otherNode.id}`);
   110  
   111      await selectSearch(Layout.navbar.search.scope, firstAllocation.name);
   112      assert.equal(
   113        Layout.navbar.search.groups[2].options[0].text,
   114        `${firstAllocation.namespace} > ${firstAllocation.name}`
   115      );
   116      await Layout.navbar.search.groups[2].options[0].click();
   117      assert.equal(currentURL(), `/allocations/${firstAllocation.id}`);
   118  
   119      await selectSearch(Layout.navbar.search.scope, firstTaskGroup.name);
   120      assert.equal(
   121        Layout.navbar.search.groups[3].options[0].text,
   122        `default > vwxyz > ${firstTaskGroup.name}`
   123      );
   124      await Layout.navbar.search.groups[3].options[0].click();
   125      assert.equal(currentURL(), `/jobs/vwxyz@default/${firstTaskGroup.name}`);
   126  
   127      await selectSearch(Layout.navbar.search.scope, namespacedTaskGroup.name);
   128      assert.equal(
   129        Layout.navbar.search.groups[3].options[0].text,
   130        `dev > xyzw > ${namespacedTaskGroup.name}`
   131      );
   132      await Layout.navbar.search.groups[3].options[0].click();
   133      assert.equal(currentURL(), `/jobs/xyzw@dev/${namespacedTaskGroup.name}`);
   134  
   135      await selectSearch(Layout.navbar.search.scope, 'xy');
   136      await Layout.navbar.search.groups[4].options[0].click();
   137      assert.equal(currentURL(), '/csi/plugins/xyz-plugin');
   138  
   139      const fuzzySearchQueries = server.pretender.handledRequests.filterBy(
   140        'url',
   141        '/v1/search/fuzzy'
   142      );
   143  
   144      const featureDetectionQueries = fuzzySearchQueries.filter((request) =>
   145        request.requestBody.includes('feature-detection-query')
   146      );
   147  
   148      assert.equal(
   149        featureDetectionQueries.length,
   150        1,
   151        'expect the feature detection query to only run once'
   152      );
   153  
   154      const realFuzzySearchQuery = fuzzySearchQueries[1];
   155  
   156      assert.deepEqual(JSON.parse(realFuzzySearchQuery.requestBody), {
   157        Context: 'all',
   158        Namespace: '*',
   159        Text: 'xy',
   160      });
   161    });
   162  
   163    test('search does not perform a request when only one character has been entered', async function (assert) {
   164      await visit('/');
   165  
   166      await selectSearch(Layout.navbar.search.scope, 'q');
   167  
   168      assert.ok(Layout.navbar.search.noOptionsShown);
   169      assert.equal(
   170        server.pretender.handledRequests.filterBy('url', '/v1/search/fuzzy')
   171          .length,
   172        1,
   173        'expect the feature detection query'
   174      );
   175    });
   176  
   177    test('when fuzzy search is disabled on the server, the search control is hidden', async function (assert) {
   178      server.post('/search/fuzzy', function () {
   179        return new Response(500, {}, '');
   180      });
   181  
   182      await visit('/');
   183  
   184      assert.ok(Layout.navbar.search.isHidden);
   185    });
   186  
   187    test('results are truncated at 10 per group', async function (assert) {
   188      server.create('node-pool');
   189      server.create('node', { name: 'xyz' });
   190  
   191      for (let i = 0; i < 11; i++) {
   192        server.create('job', { id: `job-${i}`, namespaceId: 'default' });
   193      }
   194  
   195      await visit('/');
   196  
   197      await selectSearch(Layout.navbar.search.scope, 'job');
   198  
   199      Layout.navbar.search.as((search) => {
   200        search.groups[0].as((jobs) => {
   201          assert.equal(jobs.name, 'Jobs (showing 10 of 11)');
   202          assert.equal(jobs.options.length, 10);
   203        });
   204      });
   205    });
   206  
   207    test('server-side truncation is indicated in the group label', async function (assert) {
   208      server.create('node-pool');
   209      server.create('node', { name: 'xyz' });
   210  
   211      for (let i = 0; i < 21; i++) {
   212        server.create('job', { id: `job-${i}`, namespaceId: 'default' });
   213      }
   214  
   215      await visit('/');
   216  
   217      await selectSearch(Layout.navbar.search.scope, 'job');
   218  
   219      Layout.navbar.search.as((search) => {
   220        search.groups[0].as((jobs) => {
   221          assert.equal(jobs.name, 'Jobs (showing 10 of 20+)');
   222        });
   223      });
   224    });
   225  
   226    test('clicking the search field starts search immediately', async function (assert) {
   227      await visit('/');
   228  
   229      assert.notOk(Layout.navbar.search.field.isPresent);
   230  
   231      await Layout.navbar.search.click();
   232  
   233      assert.ok(Layout.navbar.search.field.isPresent);
   234    });
   235  
   236    test('pressing slash starts a search', async function (assert) {
   237      await visit('/');
   238  
   239      assert.notOk(Layout.navbar.search.field.isPresent);
   240  
   241      await triggerEvent('.page-layout', 'keydown', { key: '/' });
   242  
   243      assert.ok(Layout.navbar.search.field.isPresent);
   244    });
   245  
   246    test('pressing slash when an input element is focused does not start a search', async function (assert) {
   247      server.create('node-pool');
   248      server.create('node');
   249      server.create('job');
   250  
   251      await visit('/');
   252  
   253      assert.notOk(Layout.navbar.search.field.isPresent);
   254  
   255      await JobsList.search.click();
   256      await JobsList.search.keydown({ key: '/' });
   257  
   258      assert.notOk(Layout.navbar.search.field.isPresent);
   259    });
   260  });