081db3a240
* Update ember-cli to ~3.20 * Remove bad optional-feature * Remove ember-fetch dep * re-install ember-fetch * update model fragments pr * update ember model fragments correct package name * update ember composable helpers to solve array helper error * update ember-concurrency * add back engine dependencies, automatically removed during ember-cli-upgrade * make author-form-options component js file otherwise error * for now comment out withTestWaiter * add eslint-node and fix if not with unless in templates * fix linting for tab index of false is now -1 and add type button to all buttons without types * fix href errors for linting, likely have to come back and fix * using eslint fix flag to fix all this.gets * ember modules codemode removed files that had module twice, will fix in next commit * finish codemode ember-data-codemod needed to rename const model * more this.get removal codemode did not work * cont. removal of this.get * stop mixin rules until figure out how to reconfig them all * smaller eslint ignores * get codemode * testing app small fixes to bring it back after all the changes * small changes to eslint * test removal of getProperties * fix issue with baseKey because value could be unknown needed to add a question mark in nested get * smaller linting fixes * get nested fixes * small linting error fixes * small linting changes * working through more small linting changes * another round of linting modifications * liniting fixes * ember module codemod * quinit dom codemod * angle bracket codemod * discovered that components must have js files * ran all codemods this is all that's left * small changes to fix get needs two object, should not have been using get. * fix issue with one input in form field * fun times with set and onChange from oninput * fix issue with model not being passed through on secret-edit-display * fix issue with yarn run test not working, revert without npm run all * linting and small fix when loading without a selectAuthBackend * fix failing test with ui-wizard issue * fix test failure due to model not being asked for correctly with new changes, probably run into this more. * fix issue with component helper and at props specific to wizard * rename log to clilog due to conflict with new eslint rule * small changes for test failures * component helper at fixes * Revert to old component style something with new one broke this and can't figure it out for now * small fishy smelling test fixes will revisit * small test changes * more small test changes, appears upgrade treats spaces differently * comment out code and test that no longer seems relevant but confirm * clean run on component test though still some potential timing issues on ui-console test * fixing one auth test issue and timing issue on enable-test * small mods * fix this conditional check from upgrade * linting fixes after master merge * package updates using yarn upgrade-interactive * update libraries that did not effect any of the test failures. * update ember truth helpers library * settling tests * Fix ui-panel control group output * fix features selection test failures * Fix auth tests (x-vault-token) * fix shared test * fix issue with data null on backend * Revert "Fix auth tests (x-vault-token)" This reverts commit 89cb174b2f1998efa56d9604d14131415ae65d6f. * Fix auth tests (x-vault-token) without updating this.set * Update redirect-to tests * fix wrapped token test * skip some flaky test * fix issue with href and a tags vs buttons * fix linting * updates to get tests running (#10409) * yarn isntall * increasing resource_class * whoops * trying large * back to xlarge * Fix param issue on transform item routes * test fixes * settle on policies (old) test * fix browserstack test warning and skips of test confirmed worked * Fix redirect-to test * skips * fix transformation test and skip some kmip * Skip tests * Add meep marker to remaining failing tests * Skip test with failing component * rever skip on secret-create test * Skip piece of test that fails due to navigation-input * fix settings test where can and skip in others after confirming * fix circle ci test failures * ssh role settle * Fix navigate-input and add settled to test * Remove extra import * secret cubbyhole and alicloud * Add settled to gcpkms test * settles on redirect to test * Bump browserstack test resource to large * Update browserstack resource size to xlarge * update todos * add back in withTestWaiter * try and fix credentials conditional action added comment instead * Update volatile computed properies to get functions * this step was never reached and we never defined secretType anywhere so I removed * add settled to policy old test * Fix navigate-input on policies and leases * replace ssh test with no var hoping that helps and add settled to other failing tests, unskip console tests * kmip, transit, role test remove a skip and add in settled * fix hover copy button, had to remove some testing functionality * Remove private router service * remove skip on control ssh and ui panel, fix search select by restructuring how to read the error * final bit of working through skipped test * Replace clearNonGlobalModels by linking directly to namespace with href-to * Remove unused var * Fix role-ssh id bug by updating form-field-from-model to form-field-group-loop * Fix transit create id would not update * Update option toggle selector for ssh-role * Fix ssh selector * cleanup pt1 * small clean up * cleanup part2 * Fix computed on pricing-metrics-form * small cleanup based on chelseas comments. Co-authored-by: Chelsea Shaw <chelshaw.dev@gmail.com> Co-authored-by: Sarah Thompson <sthompson@hashicorp.com>
293 lines
12 KiB
JavaScript
293 lines
12 KiB
JavaScript
import { module, test } from 'qunit';
|
|
import { setupRenderingTest } from 'ember-qunit';
|
|
import { create } from 'ember-cli-page-object';
|
|
import { typeInSearch, clickTrigger } from 'ember-power-select/test-support/helpers';
|
|
import Service from '@ember/service';
|
|
import { render, settled } from '@ember/test-helpers';
|
|
import { run } from '@ember/runloop';
|
|
import hbs from 'htmlbars-inline-precompile';
|
|
import sinon from 'sinon';
|
|
import waitForError from 'vault/tests/helpers/wait-for-error';
|
|
|
|
import searchSelect from '../../pages/components/search-select';
|
|
|
|
const component = create(searchSelect);
|
|
|
|
const storeService = Service.extend({
|
|
query(modelType) {
|
|
return new Promise((resolve, reject) => {
|
|
switch (modelType) {
|
|
case 'policy/acl':
|
|
resolve([{ id: '1', name: '1' }, { id: '2', name: '2' }, { id: '3', name: '3' }]);
|
|
break;
|
|
case 'policy/rgp':
|
|
reject({ httpStatus: 403, message: 'permission denied' });
|
|
break;
|
|
case 'identity/entity':
|
|
resolve([{ id: '7', name: 'seven' }, { id: '8', name: 'eight' }, { id: '9', name: 'nine' }]);
|
|
break;
|
|
case 'server/error':
|
|
var error = new Error('internal server error');
|
|
error.httpStatus = 500;
|
|
reject(error);
|
|
break;
|
|
case 'transform/transformation':
|
|
resolve([
|
|
{ id: 'foo', name: 'bar' },
|
|
{ id: 'foobar', name: '' },
|
|
{ id: 'barfoo1', name: 'different' },
|
|
]);
|
|
break;
|
|
default:
|
|
reject({ httpStatus: 404, message: 'not found' });
|
|
break;
|
|
}
|
|
reject({ httpStatus: 404, message: 'not found' });
|
|
});
|
|
},
|
|
});
|
|
|
|
module('Integration | Component | search select', function(hooks) {
|
|
setupRenderingTest(hooks);
|
|
|
|
hooks.beforeEach(function() {
|
|
run(() => {
|
|
this.owner.unregister('service:store');
|
|
this.owner.register('service:store', storeService);
|
|
});
|
|
});
|
|
|
|
test('it renders', async function(assert) {
|
|
const models = ['policy/acl'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" models=models onChange=onChange}}`);
|
|
await settled();
|
|
assert.ok(component.hasLabel, 'it renders the label');
|
|
assert.equal(component.labelText, 'foo', 'the label text is correct');
|
|
assert.ok(component.hasTrigger, 'it renders the power select trigger');
|
|
assert.equal(component.selectedOptions.length, 0, 'there are no selected options');
|
|
});
|
|
|
|
test('it shows options when trigger is clicked', async function(assert) {
|
|
const models = ['policy/acl'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" models=models onChange=onChange}}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
assert.equal(
|
|
component.options.objectAt(0).text,
|
|
component.selectedOptionText,
|
|
'first object in list is focused'
|
|
);
|
|
});
|
|
|
|
test('it filters options and adds option to create new item when text is entered', async function(assert) {
|
|
const models = ['identity/entity'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" models=models onChange=onChange}}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
await typeInSearch('n');
|
|
assert.equal(component.options.length, 3, 'list still shows three options, including the add option');
|
|
await typeInSearch('ni');
|
|
assert.equal(component.options.length, 2, 'list shows two options, including the add option');
|
|
await typeInSearch('nine');
|
|
assert.equal(component.options.length, 1, 'list shows one option');
|
|
});
|
|
|
|
test('it counts options when wildcard is used and displays the count', async function(assert) {
|
|
const models = ['transform/transformation'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" models=models onChange=onChange wildcardLabel="role" }}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
await settled();
|
|
await typeInSearch('*bar*');
|
|
await settled();
|
|
await component.selectOption();
|
|
await settled();
|
|
assert.dom('[data-test-count="2"]').exists('correctly counts with wildcard filter and shows the count');
|
|
});
|
|
|
|
test('it behaves correctly if new items not allowed', async function(assert) {
|
|
const models = ['identity/entity'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" models=models onChange=onChange disallowNewItems=true}}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
await typeInSearch('p');
|
|
assert.equal(component.options.length, 1, 'list shows one option');
|
|
assert.equal(component.options[0].text, 'No results found');
|
|
await clickTrigger();
|
|
assert.ok(this.onChange.notCalled, 'on change not called when empty state clicked');
|
|
});
|
|
|
|
test('it moves option from drop down to list when clicked', async function(assert) {
|
|
const models = ['identity/entity'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" models=models onChange=onChange}}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
await component.selectOption();
|
|
await settled();
|
|
assert.equal(component.selectedOptions.length, 1, 'there is 1 selected option');
|
|
assert.ok(this.onChange.calledOnce);
|
|
assert.ok(this.onChange.calledWith(['7']));
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 2, 'shows two options');
|
|
});
|
|
|
|
test('it pre-populates list with passed in selectedOptions', async function(assert) {
|
|
const models = ['identity/entity'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
this.set('inputValue', ['8']);
|
|
await render(hbs`{{search-select label="foo" inputValue=inputValue models=models onChange=onChange}}`);
|
|
await settled();
|
|
assert.equal(component.selectedOptions.length, 1, 'there is 1 selected option');
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 2, 'shows two options');
|
|
});
|
|
|
|
test('it adds discarded list items back into select', async function(assert) {
|
|
const models = ['identity/entity'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
this.set('inputValue', ['8']);
|
|
await render(hbs`{{search-select label="foo" inputValue=inputValue models=models onChange=onChange}}`);
|
|
await settled();
|
|
assert.equal(component.selectedOptions.length, 1, 'there is 1 selected option');
|
|
await component.deleteButtons.objectAt(0).click();
|
|
await settled();
|
|
assert.equal(component.selectedOptions.length, 0, 'there are no selected options');
|
|
assert.ok(this.onChange.calledOnce);
|
|
assert.ok(this.onChange.calledWith([]));
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
});
|
|
|
|
test('it adds created item to list items on create and removes without adding back to options on delete', async function(assert) {
|
|
const models = ['identity/entity'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" models=models onChange=onChange}}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
await typeInSearch('n');
|
|
assert.equal(component.options.length, 3, 'list still shows three options, including the add option');
|
|
await typeInSearch('ni');
|
|
await component.selectOption();
|
|
await settled();
|
|
assert.equal(component.selectedOptions.length, 1, 'there is 1 selected option');
|
|
assert.ok(this.onChange.calledOnce);
|
|
assert.ok(this.onChange.calledWith(['ni']));
|
|
await component.deleteButtons.objectAt(0).click();
|
|
await settled();
|
|
assert.equal(component.selectedOptions.length, 0, 'there are no selected options');
|
|
assert.ok(this.onChange.calledWith([]));
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 3, 'does not add deleted option back to list');
|
|
});
|
|
|
|
test('it uses fallback component if endpoint 403s', async function(assert) {
|
|
const models = ['policy/rgp'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(
|
|
hbs`{{search-select label="foo" inputValue=inputValue models=models fallbackComponent="string-list" onChange=onChange}}`
|
|
);
|
|
await settled();
|
|
assert.ok(component.hasStringList);
|
|
});
|
|
|
|
test('it shows no results if endpoint 404s', async function(assert) {
|
|
const models = ['test'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(
|
|
hbs`{{search-select label="foo" inputValue=inputValue models=models fallbackComponent="string-list" onChange=onChange}}`
|
|
);
|
|
await settled();
|
|
await clickTrigger();
|
|
await settled();
|
|
assert.equal(component.options.length, 1, 'prompts for search to add new options');
|
|
assert.equal(component.options.objectAt(0).text, 'Type to search', 'text of option shows Type to search');
|
|
});
|
|
|
|
test('it shows add suggestion if there are no options', async function(assert) {
|
|
const models = [];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(
|
|
hbs`{{search-select label="foo" inputValue=inputValue models=models fallbackComponent="string-list" onChange=onChange}}`
|
|
);
|
|
await settled();
|
|
await clickTrigger();
|
|
await settled();
|
|
|
|
await typeInSearch('new item');
|
|
assert.equal(component.options.objectAt(0).text, 'Add new foo: new item', 'shows the create suggestion');
|
|
});
|
|
test('it shows items not in the returned response', async function(assert) {
|
|
const models = ['test'];
|
|
this.set('models', models);
|
|
this.set('inputValue', ['test', 'two']);
|
|
await render(
|
|
hbs`{{search-select label="foo" inputValue=inputValue models=models fallbackComponent="string-list" onChange=onChange}}`
|
|
);
|
|
await settled();
|
|
assert.equal(component.selectedOptions.length, 2, 'renders inputOptions as selectedOptions');
|
|
});
|
|
|
|
test('it shows both name and smaller id for identity endpoints', async function(assert) {
|
|
const models = ['identity/entity'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" inputValue=inputValue models=models onChange=onChange}}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
assert.equal(component.smallOptionIds.length, 3, 'shows the smaller id text and the name');
|
|
});
|
|
|
|
test('it does not show name and smaller id for non-identity endpoints', async function(assert) {
|
|
const models = ['policy/acl'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
await render(hbs`{{search-select label="foo" inputValue=inputValue models=models onChange=onChange}}`);
|
|
await settled();
|
|
await clickTrigger();
|
|
assert.equal(component.options.length, 3, 'shows all options');
|
|
assert.equal(component.smallOptionIds.length, 0, 'only shows the regular sized id');
|
|
});
|
|
|
|
test('it throws an error if endpoint 500s', async function(assert) {
|
|
const models = ['server/error'];
|
|
this.set('models', models);
|
|
this.set('onChange', sinon.spy());
|
|
let promise = waitForError();
|
|
render(hbs`{{search-select label="foo" inputValue=inputValue models=models onChange=onChange}}`);
|
|
let err = await promise;
|
|
assert.ok(err.message.includes('internal server error'), 'it throws an internal server error');
|
|
});
|
|
});
|