Test coverage for the StepperInput

This commit is contained in:
Michael Lange
2020-06-18 22:07:51 -07:00
parent 6bde0e522a
commit 110f491c98
3 changed files with 215 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
<label class="stepper-input-label">{{yield}}</label>
<label data-test-stepper-label class="stepper-input-label">{{yield}}</label>
<input
data-test-stepper-input
type="number"
min={{min}}
max={{max}}
@@ -8,6 +9,7 @@
onKeyDown={{action "resetTextInput"}}
onChange={{action "setValue"}}>
<button
data-test-stepper-decrement
role="button"
class="stepper-input-stepper button {{class}}"
disabled={{lte internalValue min}}
@@ -15,6 +17,7 @@
{{x-icon "minus-plain"}}
</button>
<button
data-test-stepper-increment
role="button"
class="stepper-input-stepper button {{class}}"
disabled={{gte internalValue max}}

View File

@@ -0,0 +1,167 @@
import { find, render, settled, triggerEvent, waitUntil } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import sinon from 'sinon';
import { create } from 'ember-cli-page-object';
import stepperInput from 'nomad-ui/tests/pages/components/stepper-input';
const StepperInput = create(stepperInput());
const valueChange = () => {
const initial = StepperInput.input.value;
return () => StepperInput.input.value !== initial;
};
module('Integration | Component | stepper input', function(hooks) {
setupRenderingTest(hooks);
const commonProperties = () => ({
min: 0,
max: 10,
value: 5,
label: 'Stepper',
classVariant: 'is-primary',
disabled: false,
onChange: sinon.spy(),
});
const commonTemplate = hbs`
<StepperInput
@debounce=50
@min={{min}}
@max={{max}}
@value={{value}}
@class={{classVariant}}
@disabled={{disabled}}
@onChange={{onChange}}>
{{label}}
</StepperInput>
`;
test('basic appearance includes a label, an input, and two buttons', async function(assert) {
this.setProperties(commonProperties());
await render(commonTemplate);
assert.equal(StepperInput.label, this.label);
assert.equal(StepperInput.input.value, this.value);
assert.ok(StepperInput.decrement.isPresent);
assert.ok(StepperInput.increment.isPresent);
assert.ok(StepperInput.decrement.classNames.split(' ').includes(this.classVariant));
assert.ok(StepperInput.increment.classNames.split(' ').includes(this.classVariant));
});
test('clicking the increment and decrement buttons immediately changes the shown value in the input but debounces the onUpdate call', async function(assert) {
this.setProperties(commonProperties());
const baseValue = this.value;
await render(commonTemplate);
StepperInput.increment.click();
await waitUntil(valueChange());
assert.equal(StepperInput.input.value, baseValue + 1);
assert.notOk(this.onChange.called);
StepperInput.decrement.click();
await waitUntil(valueChange());
assert.equal(StepperInput.input.value, baseValue);
assert.notOk(this.onChange.called);
StepperInput.decrement.click();
await waitUntil(valueChange());
assert.equal(StepperInput.input.value, baseValue - 1);
assert.notOk(this.onChange.called);
await settled();
assert.ok(this.onChange.calledWith(baseValue - 1));
});
test('the increment button is disabled when the internal value is the max value', async function(assert) {
this.setProperties(commonProperties());
this.set('value', this.max);
await render(commonTemplate);
assert.ok(StepperInput.increment.isDisabled);
});
test('the decrement button is disabled when the internal value is the min value', async function(assert) {
this.setProperties(commonProperties());
this.set('value', this.min);
await render(commonTemplate);
assert.ok(StepperInput.decrement.isDisabled);
});
test('the text input does not call the onUpdate function on oninput', async function(assert) {
this.setProperties(commonProperties());
const newValue = 8;
await render(commonTemplate);
const input = find('[data-test-stepper-input]');
input.value = newValue;
assert.equal(StepperInput.input.value, newValue);
assert.notOk(this.onChange.called);
await triggerEvent(input, 'input');
assert.equal(StepperInput.input.value, newValue);
assert.notOk(this.onChange.called);
await triggerEvent(input, 'change');
assert.equal(StepperInput.input.value, newValue);
assert.ok(this.onChange.calledWith(newValue));
});
test('the text input does call the onUpdate function on onchange', async function(assert) {
this.setProperties(commonProperties());
const newValue = 8;
await render(commonTemplate);
await StepperInput.input.fill(newValue);
await settled();
assert.equal(StepperInput.input.value, newValue);
assert.ok(this.onChange.calledWith(newValue));
});
test('text input limits input to the bounds of the min/max range', async function(assert) {
this.setProperties(commonProperties());
let newValue = this.max + 1;
await render(commonTemplate);
await StepperInput.input.fill(newValue);
await settled();
assert.equal(StepperInput.input.value, this.max);
assert.ok(this.onChange.calledWith(this.max));
newValue = this.min - 1;
await StepperInput.input.fill(newValue);
await settled();
assert.equal(StepperInput.input.value, this.min);
assert.ok(this.onChange.calledWith(this.min));
});
test('pressing ESC in the text input reverts the text value back to the current value', async function(assert) {
this.setProperties(commonProperties());
const newValue = 8;
await render(commonTemplate);
const input = find('[data-test-stepper-input]');
input.value = newValue;
assert.equal(StepperInput.input.value, newValue);
await StepperInput.input.esc();
assert.equal(StepperInput.input.value, this.value);
});
});

View File

@@ -0,0 +1,44 @@
import {
attribute,
blurrable,
clickable,
fillable,
focusable,
isPresent,
text,
triggerable,
value,
} from 'ember-cli-page-object';
export default scope => ({
scope,
isPresent: isPresent(),
label: text('[data-test-stepper-label]'),
input: {
scope: '[data-test-stepper-input]',
fill: fillable(),
focus: focusable(),
blur: blurrable(),
value: value(),
esc: triggerable('keydown', '', { eventProperties: { keyCode: 27 } }),
},
decrement: {
scope: '[data-test-stepper-decrement]',
click: clickable(),
isPresent: isPresent(),
isDisabled: attribute('disabled'),
classNames: attribute('class'),
},
increment: {
scope: '[data-test-stepper-increment]',
click: clickable(),
isPresent: isPresent(),
isDisabled: attribute('disabled'),
classNames: attribute('class'),
},
});