UI/add select dropdown (#7102)
* add SelectDropdown * use SelectDropdown instead of HttpRequestsDropdown * use html selector instead of class name * ensure SelectDropdown still works when rendered inside a Toolbar * add tests * remove old HttpRequests component * make SelectDropdown example easier to read in Storybook * add isFullwidth prop * add SelectDropbown inside a Toolbar story * fix tests * remove actions block and call this.onChange directly * replace dropdownLabel with label * rename SelectDropdown to SelecT * add test for onChange * remove selectedItem prop since we don't need it * make Select accept options as an array of strings or objects * Revert "remove selectedItem prop since we don't need it" This reverts commit 7278516de87bb1df60482edb005137252819931e. * use Select inside TtlPicker * remove debugger * use a test selector * fix pki test selectors * improve storybook docs * fix selected value in ttl picker * ensure httprequests dropdown updates the selected item * ensure select dropdown correctly matches selectedItem * rename selectedItem to selectedValue * remove debugger lol * update selectedItem test * add valueAttribute and labelAttribute to Storybook knobs * udpate jsdocs * remove old httprequestsdropdown component * add note that onChange will receive value of select * use Select inside AuthForm * use correct test selector
This commit is contained in:
parent
11508c78a4
commit
828185db49
|
@ -25,6 +25,21 @@ export default Component.extend({
|
|||
classNames: ['http-requests-container'],
|
||||
counters: null,
|
||||
timeWindow: 'All',
|
||||
dropdownOptions: computed('counters', function() {
|
||||
let counters = this.counters || [];
|
||||
let options = ['All', 'Last 12 Months'];
|
||||
if (counters.length) {
|
||||
const years = counters
|
||||
.map(counter => {
|
||||
const year = new Date(counter.start_time);
|
||||
return year.getUTCFullYear().toString();
|
||||
})
|
||||
.uniq();
|
||||
years.sort().reverse();
|
||||
options = options.concat(years);
|
||||
}
|
||||
return options;
|
||||
}),
|
||||
filteredCounters: computed('counters', 'timeWindow', function() {
|
||||
const { counters, timeWindow } = this;
|
||||
if (timeWindow === 'All') {
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
/**
|
||||
* @module HttpRequestsDropdown
|
||||
* HttpRequestsDropdown components are used to render a dropdown that filters the HttpRequestsBarChart.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <HttpRequestsDropdown @counters={counters} />
|
||||
* ```
|
||||
*
|
||||
* @param counters=null {Array} - A list of objects containing the total number of HTTP Requests for each month. `counters` should be the response from the `/internal/counters/requests` endpoint which looks like:
|
||||
* COUNTERS = [
|
||||
* {
|
||||
* "start_time": "2019-05-01T00:00:00Z",
|
||||
* "total": 50
|
||||
* }
|
||||
* ]
|
||||
*/
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ['http-requests-dropdown'],
|
||||
counters: null,
|
||||
timeWindow: 'All',
|
||||
options: computed('counters', function() {
|
||||
let counters = this.counters || [];
|
||||
let options = [];
|
||||
if (counters.length) {
|
||||
const years = counters
|
||||
.map(counter => {
|
||||
const year = new Date(counter.start_time);
|
||||
return year.getUTCFullYear().toString();
|
||||
})
|
||||
.uniq();
|
||||
years.sort().reverse();
|
||||
options = options.concat(years);
|
||||
}
|
||||
return options;
|
||||
}),
|
||||
onChange() {},
|
||||
actions: {
|
||||
onSelectTimeWindow(e) {
|
||||
const newValue = e.target.value;
|
||||
const { timeWindow } = this;
|
||||
if (newValue !== timeWindow) {
|
||||
this.onChange(newValue);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
/**
|
||||
* @module Select
|
||||
* Select components are used to render a dropdown.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Select @label='Date Range' @options={{[{ value: 'berry', label: 'Berry' }]}} @onChange={{onChange}}/>
|
||||
* ```
|
||||
*
|
||||
* @param label=null {String} - The label for the select element.
|
||||
* @param options=null {Array} - A list of items that the user will select from. This can be an array of strings or objects.
|
||||
* @param [selectedValue=null] {String} - The currently selected item. Can also be used to set the default selected item. This should correspond to the `value` of one of the `<option>`s.
|
||||
* @param [name=null] {String} - The name of the select, used for the test selector.
|
||||
* @param [valueAttribute=value] {String} - When `options` is an array objects, the key to check for when assigning the option elements value.
|
||||
* @param [labelAttribute=label] {String} - When `options` is an array objects, the key to check for when assigning the option elements' inner text.
|
||||
* @param [isInline=false] {Bool} - Whether or not the select should be displayed as inline-block or block.
|
||||
* @param [isFullwidth=false] {Bool} - Whether or not the select should take up the full width of the parent element.
|
||||
* @param onChange=null {Func} - The action to take once the user has selected an item. This method will be passed the `value` of the select.
|
||||
*/
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ['field'],
|
||||
label: null,
|
||||
selectedValue: null,
|
||||
name: null,
|
||||
options: null,
|
||||
valueAttribute: 'value',
|
||||
labelAttribute: 'label',
|
||||
isInline: false,
|
||||
isFullwidth: false,
|
||||
onChange() {},
|
||||
});
|
|
@ -24,6 +24,11 @@
|
|||
.select {
|
||||
min-width: 190px;
|
||||
}
|
||||
|
||||
label {
|
||||
padding: $spacing-xs;
|
||||
color: $grey;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-scroller {
|
||||
|
@ -95,11 +100,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.toolbar-label {
|
||||
padding: $spacing-xs;
|
||||
color: $grey;
|
||||
}
|
||||
|
||||
.toolbar-separator {
|
||||
border-right: $light-border;
|
||||
height: 32px;
|
||||
|
|
|
@ -32,27 +32,15 @@
|
|||
data-test-auth-error
|
||||
/>
|
||||
{{#if (or (not hasMethodsWithPath) (not selectedAuthIsPath))}}
|
||||
<div class="field">
|
||||
<label for="selectedMethod" class="is-label">
|
||||
Method
|
||||
</label>
|
||||
<div class="control is-expanded" >
|
||||
<div class="select is-fullwidth">
|
||||
<select
|
||||
name="selectedMethod"
|
||||
id="selectedMethod"
|
||||
onchange={{action (mut selectedAuth) value="target.value"}}
|
||||
data-test-method-select
|
||||
>
|
||||
{{#each (supported-auth-backends) as |method|}}
|
||||
<option selected={{eq selectedAuthBackend.type method.type}} value={{method.type}}>
|
||||
{{method.typeDisplay}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Select
|
||||
@label='Method'
|
||||
@name='auth-method'
|
||||
@options={{supported-auth-backends}}
|
||||
@valueAttribute={{'type'}}
|
||||
@labelAttribute={{'typeDisplay'}}
|
||||
@isFullwidth={{true}}
|
||||
@onChange={{action (mut selectedAuth)}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if (or (eq this.selectedAuthBackend.type "jwt") (eq this.selectedAuthBackend.type "oidc"))}}
|
||||
<AuthJwt
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
{{#if (gt counters.length 1) }}
|
||||
<Toolbar>
|
||||
<HttpRequestsDropdown @counters={{counters}} @onChange={{action "updateTimeWindow"}} @timeWindow={{timeWindow}}/>
|
||||
<Select
|
||||
@label='Date Range'
|
||||
@name='requests-timewindow'
|
||||
@options={{dropdownOptions}}
|
||||
@onChange={{action "updateTimeWindow"}}
|
||||
@selectedValue={{timeWindow}}
|
||||
@isInline={{true}}
|
||||
/>
|
||||
</Toolbar>
|
||||
|
||||
<HttpRequestsBarChart @counters={{filteredCounters}} />
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<label for="date-range" class="is-label toolbar-label">
|
||||
Date Range
|
||||
</label>
|
||||
<div class="select">
|
||||
<select class="select" id="date-range" data-test-date-range name="selectedTimeWindow" data-test-timewindow-select onchange={{action "onSelectTimeWindow"}}>
|
||||
<option value="All" selected={{eq timeWindow "All"}}>All</option>/>
|
||||
<option value="Last 12 Months" selected={{eq timeWindow "Last 12 Months"}}>Last 12 Months</option>
|
||||
{{#each options as |op|}}
|
||||
<option value={{op}} selected={{eq timeWindow op}}>{{op}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
{{#if label}}
|
||||
<label
|
||||
for="select-{{this.elementId}}"
|
||||
class="is-label"
|
||||
data-test-select-label
|
||||
>
|
||||
{{label}}
|
||||
</label>
|
||||
{{/if}}
|
||||
<div class="control {{if isInline "select is-inline-block"}}">
|
||||
<div class="select {{if isFullwidth "is-fullwidth"}}">
|
||||
<select
|
||||
class="select"
|
||||
id="select-{{this.elementId}}"
|
||||
onchange={{action this.onChange value="target.value"}}
|
||||
data-test-select={{name}}
|
||||
>
|
||||
{{#each options as |op|}}
|
||||
<option
|
||||
value={{or (get op valueAttribute) op}}
|
||||
selected={{eq selectedValue (or (get op valueAttribute) op)}}>
|
||||
{{or (get op labelAttribute) op}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -102,18 +102,17 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
actions: {
|
||||
changedValue(key, event) {
|
||||
let { type, value, checked } = event.target;
|
||||
let val = type === 'checkbox' ? checked : value;
|
||||
if (val && key === 'time') {
|
||||
val = parseInt(val, 10);
|
||||
if (Number.isNaN(val)) {
|
||||
changedValue(key, value) {
|
||||
if (value && key === 'time') {
|
||||
value = parseInt(value, 10);
|
||||
if (Number.isNaN(value)) {
|
||||
this.set('errorMessage', ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.set('errorMessage', null);
|
||||
set(this, key, val);
|
||||
|
||||
set(this, key, value);
|
||||
this.onChange(this.TTL);
|
||||
},
|
||||
},
|
||||
|
|
|
@ -2,18 +2,16 @@
|
|||
<MessageError @errorMessage={{errorMessage}} data-test-ttl-error />
|
||||
<div class="field is-grouped">
|
||||
<div class="control is-expanded">
|
||||
<input data-test-ttl-value value={{time}} id="time-{{elementId}}" type="text" name="time" class="input" oninput={{action 'changedValue' 'time'}}
|
||||
<input data-test-ttl-value value={{time}} id="time-{{elementId}}" type="text" name="time" class="input" oninput={{action (action 'changedValue' 'time') value="target.value"}}
|
||||
pattern="[0-9]*" />
|
||||
</div>
|
||||
<div class="control is-expanded">
|
||||
<div class="select is-fullwidth">
|
||||
<select data-test-ttl-unit name="unit" id="unit" onchange={{action 'changedValue' 'unit'}}>
|
||||
{{#each unitOptions as |unitOption|}}
|
||||
<option selected={{eq unit unitOption.value}} value={{unitOption.value}}>
|
||||
{{unitOption.label}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<Select
|
||||
@name='ttl-unit'
|
||||
@options={{unitOptions}}
|
||||
@onChange={{action 'changedValue' 'unit'}}
|
||||
@selectedValue={{unit.value}}
|
||||
@isFullwidth={{true}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<!--THIS FILE IS AUTO GENERATED. This file is generated from JSDoc comments in app/components/http-requests-dropdown.js. To make changes, first edit that file and run "yarn gen-story-md http-requests-dropdown" to re-generate the content.-->
|
||||
|
||||
## HttpRequestsDropdown
|
||||
HttpRequestsDropdown components are used to render a dropdown that filters the HttpRequestsBarChart.
|
||||
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| counters | <code>Array</code> | <code></code> | A list of objects containing the total number of HTTP Requests for each month. `counters` should be the response from the `/internal/counters/requests` endpoint. |
|
||||
|
||||
**Example**
|
||||
|
||||
```js
|
||||
<HttpRequestsDropdown @counters={counters} />
|
||||
```
|
||||
|
||||
**See**
|
||||
|
||||
- [Uses of HttpRequestsDropdown](https://github.com/hashicorp/vault/search?l=Handlebars&q=HttpRequestsDropdown+OR+http-requests-dropdown)
|
||||
- [HttpRequestsDropdown Source Code](https://github.com/hashicorp/vault/blob/master/ui/app/components/http-requests-dropdown.js)
|
||||
|
||||
---
|
|
@ -1,28 +0,0 @@
|
|||
/* eslint-disable import/extensions */
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { storiesOf } from '@storybook/ember';
|
||||
import { withKnobs, object } from '@storybook/addon-knobs';
|
||||
import notes from './http-requests-dropdown.md';
|
||||
|
||||
const COUNTERS = [
|
||||
{ start_time: '2019-04-01T00:00:00Z', total: 5500 },
|
||||
{ start_time: '2019-05-01T00:00:00Z', total: 4500 },
|
||||
{ start_time: '2019-06-01T00:00:00Z', total: 5000 },
|
||||
];
|
||||
|
||||
storiesOf('HttpRequests/Dropdown/', module)
|
||||
.addParameters({ options: { showPanel: true } })
|
||||
.addDecorator(withKnobs())
|
||||
.add(
|
||||
`HttpRequestsDropdown`,
|
||||
() => ({
|
||||
template: hbs`
|
||||
<h5 class="title is-5">Http Requests Dropdown</h5>
|
||||
<HttpRequestsDropdown @counters={{counters}}/>
|
||||
`,
|
||||
context: {
|
||||
counters: object('counters', COUNTERS),
|
||||
},
|
||||
}),
|
||||
{ notes }
|
||||
);
|
|
@ -0,0 +1,33 @@
|
|||
<!--THIS FILE IS AUTO GENERATED. This file is generated from JSDoc comments in app/components/select.js. To make changes, first edit that file and run "yarn gen-story-md select" to re-generate the content.-->
|
||||
|
||||
## Select
|
||||
Select components are used to render a dropdown.
|
||||
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| label | <code>String</code> | <code></code> | The label for the select element. |
|
||||
| options | <code>Array</code> | <code></code> | A list of items that the user will select from. This can be an array of strings or objects. |
|
||||
| [name] | <code>String</code> | <code></code> | The name of the select, used for the test selector. |
|
||||
| [selectedValue] | <code>String</code> | <code></code> | The currently selected item. Can also be used to set the default selected item. This should correspond to the `value` of one of the `<option>`s. |
|
||||
| [valueAttribute] | <code>String</code> | <code>value</code> | When `options` is an array objects, the key to check for when assigning the option elements value. |
|
||||
| [labelAttribute] | <code>String</code> | <code>label</code> | When `options` is an array objects, the key to check for when assigning the option elements' inner text. |
|
||||
| [isInline] | <code>Bool</code> | <code>false</code> | Whether or not the select should be displayed as inline-block or block. |
|
||||
| [isFullwidth] | <code>Bool</code> | <code>false</code> | Whether or not the select should take up the full width of the parent element. |
|
||||
| onChange | <code>Func</code> | <code></code> | The action to take once the user has selected an item. This method will be passed the `value` of the select. |
|
||||
|
||||
**Example**
|
||||
|
||||
```js
|
||||
<Select
|
||||
@label='Date Range'
|
||||
@options={{[{ value: 'berry', label: 'Berry' }]}}
|
||||
@onChange={{onChange}}/>
|
||||
```
|
||||
|
||||
**See**
|
||||
|
||||
- [Uses of Select](https://github.com/hashicorp/vault/search?l=Handlebars&q=Select+OR+select)
|
||||
- [Select Source Code](https://github.com/hashicorp/vault/blob/master/ui/app/components/select.js)
|
||||
|
||||
---
|
|
@ -0,0 +1,65 @@
|
|||
/* eslint-disable import/extensions */
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { storiesOf } from '@storybook/ember';
|
||||
import { withKnobs, object, text, boolean, select } from '@storybook/addon-knobs';
|
||||
import notes from './select.md';
|
||||
|
||||
const OPTIONS = [
|
||||
{ value: 'mon', label: 'Monday', spanish: 'lunes' },
|
||||
{ value: 'tues', label: 'Tuesday', spanish: 'martes' },
|
||||
{ value: 'weds', label: 'Wednesday', spanish: 'miercoles' },
|
||||
];
|
||||
|
||||
storiesOf('Select/', module)
|
||||
.addParameters({ options: { showPanel: true } })
|
||||
.addDecorator(withKnobs())
|
||||
.add(
|
||||
`Select`,
|
||||
() => ({
|
||||
template: hbs`
|
||||
<h5 class="title is-5">Select</h5>
|
||||
<Select
|
||||
@options={{options}}
|
||||
@label={{label}}
|
||||
@isInline={{isInline}}
|
||||
@isFullwidth={{isFullwidth}}
|
||||
@valueAttribute={{valueAttribute}}
|
||||
@labelAttribute={{labelAttribute}}
|
||||
@selectedValue={{selectedValue}}
|
||||
/>
|
||||
`,
|
||||
context: {
|
||||
options: object('options', OPTIONS),
|
||||
label: text('label', 'Day of the week'),
|
||||
isFullwidth: boolean('isFullwidth', false),
|
||||
isInline: boolean('isInline', false),
|
||||
valueAttribute: select('valueAttribute', Object.keys(OPTIONS[0]), 'value'),
|
||||
labelAttribute: select('labelAttribute', Object.keys(OPTIONS[0]), 'label'),
|
||||
selectedValue: select('selectedValue', OPTIONS.map(o => o.label), 'tues'),
|
||||
},
|
||||
}),
|
||||
{ notes }
|
||||
)
|
||||
.add(
|
||||
`Select in a Toolbar`,
|
||||
() => ({
|
||||
template: hbs`
|
||||
<h5 class="title is-5">Select</h5>
|
||||
<Toolbar>
|
||||
<Select
|
||||
@options={{options}}
|
||||
@label={{label}}
|
||||
@valueAttribute={{valueAttribute}}
|
||||
@labelAttribute={{labelAttribute}}
|
||||
@isInline={{true}}/>
|
||||
</Toolbar>
|
||||
`,
|
||||
context: {
|
||||
label: text('label', 'Day of the week'),
|
||||
options: object('options', OPTIONS),
|
||||
valueAttribute: select('valueAttribute', Object.keys(OPTIONS[0]), 'value'),
|
||||
labelAttribute: select('labelAttribute', Object.keys(OPTIONS[0]), 'label'),
|
||||
},
|
||||
}),
|
||||
{ notes }
|
||||
);
|
|
@ -18,8 +18,8 @@ module('Acceptance | settings/configure/secrets/pki/crl', function(hooks) {
|
|||
await page.visit({ backend: path, section: 'crl' });
|
||||
assert.equal(currentRouteName(), 'vault.cluster.settings.configure-secret-backend.section');
|
||||
|
||||
await page.form.fillInField('time', 3);
|
||||
await page.form.fillInField('unit', 'h');
|
||||
await page.form.fillInValue(3);
|
||||
await page.form.fillInUnit('h');
|
||||
await page.form.submit();
|
||||
assert.equal(page.lastMessage, 'The crl config for this backend has been updated.');
|
||||
});
|
||||
|
|
|
@ -21,8 +21,10 @@ module('Acceptance | settings/mount-secret-backend', function(hooks) {
|
|||
const maxTTLSeconds = maxTTLHours * 60 * 60;
|
||||
|
||||
await page.visit();
|
||||
|
||||
assert.equal(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
|
||||
await page.selectType('kv');
|
||||
|
||||
await page
|
||||
.next()
|
||||
.path(path)
|
||||
|
@ -32,6 +34,7 @@ module('Acceptance | settings/mount-secret-backend', function(hooks) {
|
|||
.maxTTLVal(maxTTLHours)
|
||||
.maxTTLUnit('h')
|
||||
.submit();
|
||||
|
||||
await configPage.visit({ backend: path });
|
||||
assert.equal(configPage.defaultTTL, defaultTTLSeconds, 'shows the proper TTL');
|
||||
assert.equal(configPage.maxTTL, maxTTLSeconds, 'shows the proper max TTL');
|
||||
|
|
|
@ -21,7 +21,7 @@ module('Integration | Component | http-requests-container', function(hooks) {
|
|||
await render(hbs`<HttpRequestsContainer @counters={{counters}}/>`);
|
||||
|
||||
assert.dom('.http-requests-container').exists();
|
||||
assert.dom('.http-requests-dropdown').exists();
|
||||
assert.dom('.select').exists();
|
||||
assert.dom('.http-requests-bar-chart-container').exists();
|
||||
assert.dom('.http-requests-table').exists();
|
||||
});
|
||||
|
@ -43,7 +43,7 @@ module('Integration | Component | http-requests-container', function(hooks) {
|
|||
|
||||
test('it filters the data according to the dropdown', async function(assert) {
|
||||
await render(hbs`<HttpRequestsContainer @counters={{counters}}/>`);
|
||||
await fillIn('[data-test-timewindow-select]', '2018');
|
||||
await fillIn('[data-test-select="requests-timewindow"]', '2018');
|
||||
|
||||
assert.dom('.shadow-bars> .bar').exists({ count: 1 }, 'filters the bar chart to the selected year');
|
||||
assert.dom('.start-time').exists({ count: 1 }, 'filters the table to the selected year');
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
const COUNTERS = [
|
||||
{ start_time: '2018-04-01T00:00:00Z', total: 5500 },
|
||||
{ start_time: '2019-05-01T00:00:00Z', total: 4500 },
|
||||
{ start_time: '2019-06-01T00:00:00Z', total: 5000 },
|
||||
];
|
||||
|
||||
module('Integration | Component | http-requests-dropdown', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function() {
|
||||
this.set('counters', COUNTERS);
|
||||
});
|
||||
|
||||
test('it renders with options', async function(assert) {
|
||||
await render(hbs`<HttpRequestsDropdown @counters={{counters}} />`);
|
||||
|
||||
assert.dom('[data-test-date-range]').hasValue('All', 'shows all data by default');
|
||||
|
||||
assert.equal(
|
||||
this.element.querySelector('[data-test-date-range]').options.length,
|
||||
4,
|
||||
'it adds an option for each year in the data set'
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,77 @@
|
|||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render, fillIn } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import sinon from 'sinon';
|
||||
|
||||
const OPTIONS = ['foo', 'bar', 'baz'];
|
||||
const LABEL = 'Boop';
|
||||
|
||||
module('Integration | Component | Select', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function() {
|
||||
this.set('options', OPTIONS);
|
||||
this.set('label', LABEL);
|
||||
this.set('name', 'foo');
|
||||
});
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
await render(hbs`<Select @options={{options}} @label={{label}} @name={{name}}/>`);
|
||||
assert.dom('[data-test-select-label]').hasText('Boop');
|
||||
assert.dom('[data-test-select="foo"]').exists();
|
||||
});
|
||||
|
||||
test('it renders when options is an array of strings', async function(assert) {
|
||||
await render(hbs`<Select @options={{options}} @label={{label}} @name={{name}}/>`);
|
||||
|
||||
assert.dom('[data-test-select="foo"]').hasValue('foo');
|
||||
assert.equal(this.element.querySelector('[data-test-select="foo"]').options.length, 3);
|
||||
});
|
||||
|
||||
test('it renders when options is an array of objects', async function(assert) {
|
||||
const objectOptions = [{ value: 'berry', label: 'Berry' }, { value: 'cherry', label: 'Cherry' }];
|
||||
this.set('options', objectOptions);
|
||||
await render(hbs`<Select @options={{options}} @label={{label}} @name={{name}}/>`);
|
||||
|
||||
assert.dom('[data-test-select="foo"]').hasValue('berry');
|
||||
assert.equal(this.element.querySelector('[data-test-select="foo"]').options.length, 2);
|
||||
});
|
||||
|
||||
test('it renders when options is an array of custom objects', async function(assert) {
|
||||
const objectOptions = [{ day: 'mon', fullDay: 'Monday' }, { day: 'tues', fullDay: 'Tuesday' }];
|
||||
const selectedValue = objectOptions[1].day;
|
||||
this.setProperties({
|
||||
options: objectOptions,
|
||||
valueAttribute: 'day',
|
||||
labelAttribute: 'fullDay',
|
||||
selectedValue: selectedValue,
|
||||
});
|
||||
|
||||
await render(
|
||||
hbs`
|
||||
<Select
|
||||
@options={{options}}
|
||||
@label={{label}}
|
||||
@name={{name}}
|
||||
@valueAttribute={{valueAttribute}}
|
||||
@labelAttribute={{labelAttribute}}
|
||||
@selectedValue={{selectedValue}}/>`
|
||||
);
|
||||
|
||||
assert.dom('[data-test-select="foo"]').hasValue('tues', 'sets selectedValue by default');
|
||||
assert.equal(
|
||||
this.element.querySelector('[data-test-select="foo"]').options[1].textContent.trim(),
|
||||
'Tuesday',
|
||||
'uses the labelAttribute to determine the label'
|
||||
);
|
||||
});
|
||||
|
||||
test('it calls onChange when an item is selected', async function(assert) {
|
||||
this.set('onChange', sinon.spy());
|
||||
await render(hbs`<Select @options={{options}} @name={{name}} @onChange={{onChange}}/>`);
|
||||
await fillIn('[data-test-select="foo"]', 'bar');
|
||||
|
||||
assert.ok(this.onChange.calledOnce);
|
||||
});
|
||||
});
|
|
@ -40,12 +40,12 @@ module('Integration | Component | wrap ttl', function(hooks) {
|
|||
await fillIn('[data-test-wrap-ttl-picker] input', '20');
|
||||
assert.equal(this.lastOnChangeCall, '20m', 'calls onChange correctly on time input');
|
||||
|
||||
await fillIn('#unit', 'h');
|
||||
await blur('#unit');
|
||||
await fillIn('[data-test-select="ttl-unit"]', 'h');
|
||||
await blur('[data-test-select="ttl-unit"]');
|
||||
assert.equal(this.lastOnChangeCall, '20h', 'calls onChange correctly on unit change');
|
||||
|
||||
await fillIn('#unit', 'd');
|
||||
await blur('#unit');
|
||||
await fillIn('[data-test-select="ttl-unit"]', 'd');
|
||||
await blur('[data-test-select="ttl-unit"]');
|
||||
assert.equal(this.lastOnChangeCall, '480h', 'converts days to hours correctly');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ export default {
|
|||
name: text(),
|
||||
link: clickable('[data-test-auth-method-link]'),
|
||||
}),
|
||||
selectMethod: fillable('[data-test-method-select]'),
|
||||
selectMethod: fillable('[data-test-select=auth-method]'),
|
||||
username: fillable('[data-test-username]'),
|
||||
token: fillable('[data-test-token]'),
|
||||
tokenValue: value('[data-test-token]'),
|
||||
|
|
|
@ -9,5 +9,6 @@ export default {
|
|||
hasTitle: isPresent('[data-test-title]'),
|
||||
hasError: isPresent('[data-test-error]'),
|
||||
submit: clickable('[data-test-submit]'),
|
||||
fillInField: fillable('[data-test-field]'),
|
||||
fillInValue: fillable('[data-test-ttl-value]'),
|
||||
fillInUnit: fillable('[data-test-select="ttl-unit"]'),
|
||||
};
|
||||
|
|
|
@ -12,11 +12,11 @@ export default create({
|
|||
certificate: text('[data-test-row-value="Certificate"]'),
|
||||
toggleOptions: clickable('[data-test-toggle-group]'),
|
||||
hasCert: isPresent('[data-test-row-value="Certificate"]'),
|
||||
fillInField: fillable('[data-test-field]'),
|
||||
fillInField: fillable('[data-test-select="ttl-unit"]'),
|
||||
issueCert: async function(commonName) {
|
||||
await this.commonName(commonName)
|
||||
.toggleOptions()
|
||||
.fillInField('unit', 'h')
|
||||
.fillInField('h')
|
||||
.submit();
|
||||
},
|
||||
|
||||
|
@ -24,7 +24,7 @@ export default create({
|
|||
return this.csr(csr)
|
||||
.commonName(commonName)
|
||||
.toggleOptions()
|
||||
.fillInField('unit', 'h')
|
||||
.fillInField('h')
|
||||
.submit();
|
||||
},
|
||||
});
|
||||
|
|
|
@ -6,9 +6,9 @@ export default create({
|
|||
...mountForm,
|
||||
version: fillable('[data-test-input="options.version"]'),
|
||||
maxTTLVal: fillable('[data-test-input="config.maxLeaseTtl"] [data-test-ttl-value]'),
|
||||
maxTTLUnit: fillable('[data-test-input="config.maxLeaseTtl"] [data-test-ttl-unit]'),
|
||||
maxTTLUnit: fillable('[data-test-input="config.maxLeaseTtl"] [data-test-select="ttl-unit"]'),
|
||||
defaultTTLVal: fillable('[data-test-input="config.defaultLeaseTtl"] [data-test-ttl-value]'),
|
||||
defaultTTLUnit: fillable('[data-test-input="config.defaultLeaseTtl"] [data-test-ttl-unit]'),
|
||||
defaultTTLUnit: fillable('[data-test-input="config.defaultLeaseTtl"] [data-test-select="ttl-unit"]'),
|
||||
enable: async function(type, path) {
|
||||
await this.visit();
|
||||
await this.mount(type, path);
|
||||
|
|
Loading…
Reference in New Issue