2019-08-31 20:51:14 -07:00
|
|
|
import { module, test } from 'qunit';
|
|
|
|
import { setupRenderingTest } from 'ember-qunit';
|
2020-10-20 10:26:02 -07:00
|
|
|
import { render, findAll, triggerEvent, click } from '@ember/test-helpers';
|
2019-08-31 20:51:14 -07:00
|
|
|
import hbs from 'htmlbars-inline-precompile';
|
2020-10-20 10:26:02 -07:00
|
|
|
import EmberObject from '@ember/object';
|
2019-08-31 20:51:14 -07:00
|
|
|
|
2020-08-26 15:44:50 -07:00
|
|
|
module('Integration | Component | radio-button-composer', function(hooks): void {
|
2019-08-31 20:51:14 -07:00
|
|
|
setupRenderingTest(hooks);
|
|
|
|
|
2020-10-20 10:26:02 -07:00
|
|
|
class Person extends EmberObject {
|
|
|
|
ssn?: string;
|
|
|
|
isEqual(other: Person): boolean {
|
|
|
|
return this.ssn === other.ssn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const matchingSSN = '123-45-6789';
|
|
|
|
const alice = Person.create({ name: 'Alice', ssn: matchingSSN });
|
|
|
|
const alice2 = Person.create({ name: 'Alice 2', ssn: matchingSSN });
|
|
|
|
const bob = Person.create({ name: 'Bob', ssn: '999-99-9999' });
|
|
|
|
|
2019-08-31 20:51:14 -07:00
|
|
|
const disabledClass = 'paralyzed-pikachu';
|
|
|
|
|
2020-08-26 15:44:50 -07:00
|
|
|
test('decorated properties behave as expected', async function(assert): Promise<void> {
|
2019-08-31 20:51:14 -07:00
|
|
|
this.setProperties({
|
|
|
|
disabledClass,
|
|
|
|
value: 'electrify',
|
|
|
|
mouseEnter() {
|
|
|
|
assert.ok(true, 'Function got called on mouseEnter');
|
|
|
|
}
|
|
|
|
});
|
2020-10-11 11:40:32 -07:00
|
|
|
await render(hbs`<RadioButtonComposer
|
|
|
|
@disabledClass={{this.disabledClass}}
|
|
|
|
@name="testA"
|
|
|
|
@groupValue="groupA"
|
|
|
|
@value={{this.value}}
|
|
|
|
@onMouseEnter={{this.mouseEnter}}
|
|
|
|
>
|
|
|
|
{{value}}
|
|
|
|
</RadioButtonComposer>`);
|
2019-08-31 20:51:14 -07:00
|
|
|
|
|
|
|
// Ensures the function assert was called.
|
2020-10-11 11:40:32 -07:00
|
|
|
assert.expect(5);
|
2020-08-26 15:44:50 -07:00
|
|
|
assert.equal(this.element.textContent?.trim(), 'electrify', 'renders expected value');
|
2019-08-31 20:51:14 -07:00
|
|
|
assert.equal(findAll(`.${disabledClass}`).length, 0, 'Does not disable when not supposed to');
|
|
|
|
|
2020-10-11 11:40:32 -07:00
|
|
|
await triggerEvent('span', 'mouseenter');
|
2019-08-31 20:51:14 -07:00
|
|
|
|
2020-10-11 11:40:32 -07:00
|
|
|
await render(hbs`<RadioButtonComposer
|
|
|
|
@disabledClass={{this.disabledClass}}
|
|
|
|
@name="testB"
|
|
|
|
@groupValue="groupB"
|
|
|
|
@value={{this.value}}
|
|
|
|
@onMouseEnter={{this.mouseEnter}}
|
|
|
|
@disabled={{true}} />`);
|
2019-08-31 20:51:14 -07:00
|
|
|
|
|
|
|
assert.equal(findAll(`.${disabledClass}`).length, 1, 'Renders the disabled class');
|
2020-10-11 11:40:32 -07:00
|
|
|
await triggerEvent('span', 'mouseenter');
|
2019-08-31 20:51:14 -07:00
|
|
|
});
|
2020-10-20 10:26:02 -07:00
|
|
|
|
|
|
|
test('begins checked when groupValue matches value', async function(assert) {
|
|
|
|
assert.expect(1);
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue='chosen-value'
|
|
|
|
@value='chosen-value'
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, true);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('either @class or class work fine', async function(assert) {
|
|
|
|
assert.expect(2);
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue='chosen-value'
|
|
|
|
@value='chosen-value'
|
|
|
|
@class='myclass'
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.dom('.myclass').exists();
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue='chosen-value'
|
|
|
|
@value='chosen-value'
|
|
|
|
class='myclass'
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.dom('.myclass').exists();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it updates when clicked, and triggers the `changed` action', async function(assert) {
|
|
|
|
assert.expect(5);
|
|
|
|
|
|
|
|
let changedActionCallCount = 0;
|
|
|
|
this.set('changed', (value: string) => {
|
|
|
|
changedActionCallCount++;
|
|
|
|
this.set('groupValue', value);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.set('groupValue', 'initial-group-value');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue={{this.groupValue}}
|
|
|
|
@value='component-value'
|
|
|
|
@onChange={{fn this.changed}}
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.equal(changedActionCallCount, 0);
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, false);
|
|
|
|
|
|
|
|
await click('input');
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, true, 'updates element property');
|
|
|
|
assert.equal(this.get('groupValue'), 'component-value', 'updates groupValue');
|
|
|
|
|
|
|
|
assert.equal(changedActionCallCount, 1);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('when no action is passed, updating does not error', async function(assert) {
|
|
|
|
assert.expect(2);
|
|
|
|
|
|
|
|
this.set('groupValue', 'initial-group-value');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue={{this.groupValue}}
|
|
|
|
@value='component-value'
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, false, 'starts unchecked');
|
|
|
|
|
|
|
|
await click('input');
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, true, 'updates element property');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it updates when the browser change event is fired', async function(assert) {
|
|
|
|
let changedActionCallCount = 0;
|
|
|
|
this.set('changed', (value: string) => {
|
|
|
|
changedActionCallCount++;
|
|
|
|
this.set('groupValue', value);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.set('groupValue', 'initial-group-value');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue={{this.groupValue}}
|
|
|
|
@value='component-value'
|
|
|
|
@onChange={{fn this.changed}}
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.equal(changedActionCallCount, 0);
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, false);
|
|
|
|
|
|
|
|
await triggerEvent('input', 'change');
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, true, 'updates DOM property');
|
|
|
|
assert.equal(this.get('groupValue'), 'component-value', 'updates groupValue');
|
|
|
|
assert.equal(changedActionCallCount, 1);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it gives the label of a wrapped checkbox a `checked` className', async function(assert) {
|
|
|
|
assert.expect(4);
|
|
|
|
|
|
|
|
this.set('groupValue', 'initial-group-value');
|
|
|
|
this.set('value', 'component-value');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue={{this.groupValue}}
|
|
|
|
@value={{this.value}}
|
|
|
|
class='blue-radio'
|
|
|
|
>
|
|
|
|
Blue
|
|
|
|
</RadioButtonComposer>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.dom('label').doesNotHaveClass('checked');
|
|
|
|
|
|
|
|
this.set('value', 'initial-group-value');
|
|
|
|
|
|
|
|
assert.dom('label').hasClass('checked', 'has class `checked`');
|
|
|
|
assert.dom('label').hasClass('ember-radio-button', 'has class `ember-radio-button`');
|
|
|
|
assert.dom('label').hasClass('blue-radio', 'has class `blue-radio`');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('providing `checkedClass` gives the label a custom classname when the radio is checked', async function(assert) {
|
|
|
|
assert.expect(5);
|
|
|
|
|
|
|
|
this.set('groupValue', 'initial-group-value');
|
|
|
|
this.set('value', 'component-value');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue={{this.groupValue}}
|
|
|
|
@value={{this.value}}
|
|
|
|
@checkedClass="my-custom-class"
|
|
|
|
class='blue-radio'
|
|
|
|
>
|
|
|
|
Blue
|
|
|
|
</RadioButtonComposer>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.dom('label').doesNotHaveClass('my-custom-class', 'does not have user-provided checkedClass');
|
|
|
|
|
|
|
|
this.set('value', 'initial-group-value');
|
|
|
|
|
|
|
|
assert.dom('label').doesNotHaveClass('checked', 'does not have the `checked` class');
|
|
|
|
assert.dom('label').hasClass('my-custom-class', 'has user-provided checkedClass');
|
|
|
|
assert.dom('label').hasClass('ember-radio-button', 'has class `ember-radio-button`');
|
|
|
|
assert.dom('label').hasClass('blue-radio', 'has class `blue-radio`');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it updates when setting `value`', async function(assert) {
|
|
|
|
assert.expect(3);
|
|
|
|
|
|
|
|
this.set('groupValue', 'initial-group-value');
|
|
|
|
this.set('value', 'component-value');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue={{this.groupValue}}
|
|
|
|
@value={{this.value}}
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, false);
|
|
|
|
|
|
|
|
this.set('value', 'initial-group-value');
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, true);
|
|
|
|
|
|
|
|
this.set('value', 'component-value');
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, false);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('begins disabled when disabled is true', async function(assert) {
|
|
|
|
assert.expect(1);
|
|
|
|
|
|
|
|
await render(hbs`<RadioButtonComposer
|
|
|
|
@disabled={{true}}
|
|
|
|
/>`);
|
|
|
|
|
|
|
|
assert.dom('input').isDisabled();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updates disabled when the disabled attribute changes', async function(assert) {
|
|
|
|
this.set('isDisabled', false);
|
|
|
|
|
|
|
|
await render(hbs`<RadioButtonComposer
|
|
|
|
@disabled={{this.isDisabled}}
|
|
|
|
/>`);
|
|
|
|
|
|
|
|
assert.dom('input').isNotDisabled();
|
|
|
|
|
|
|
|
this.set('isDisabled', true);
|
|
|
|
|
|
|
|
assert.dom('input').isDisabled();
|
|
|
|
|
|
|
|
this.set('isDisabled', false);
|
|
|
|
|
|
|
|
assert.dom('input').isNotDisabled();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('begins with the `required` and `name` attributes when specified', async function(assert) {
|
|
|
|
await render(hbs`<RadioButtonComposer
|
|
|
|
required={{true}}
|
|
|
|
name='colors'
|
|
|
|
/>`);
|
|
|
|
|
|
|
|
assert.dom('input').hasAttribute('required');
|
|
|
|
assert.dom('input').hasAttribute('name', 'colors');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updates the `required` attribute when the property changes', async function(assert) {
|
|
|
|
this.set('isRequired', false);
|
|
|
|
await render(hbs`<RadioButtonComposer
|
|
|
|
required={{this.isRequired}}
|
|
|
|
/>`);
|
|
|
|
|
|
|
|
assert.dom('input').isNotRequired();
|
|
|
|
|
|
|
|
this.set('isRequired', true);
|
|
|
|
|
|
|
|
assert.dom('input').isRequired();
|
|
|
|
|
|
|
|
this.set('isRequired', false);
|
|
|
|
|
|
|
|
assert.dom('input').isNotRequired();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updates the `name` attribute when the property changes', async function(assert) {
|
|
|
|
this.set('name', undefined);
|
|
|
|
await render(hbs`<RadioButtonComposer
|
|
|
|
name={{this.name}}
|
|
|
|
/>`);
|
|
|
|
|
|
|
|
assert.dom('input').doesNotHaveAttribute('name');
|
|
|
|
|
|
|
|
this.set('name', 'colors');
|
|
|
|
|
|
|
|
assert.dom('input').hasAttribute('name', 'colors');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('uses a layout, tagName=label, when given a template', async function(assert) {
|
|
|
|
await render(hbs`<RadioButtonComposer>Red</RadioButtonComposer>`);
|
|
|
|
assert.dom('label').containsText('Red');
|
|
|
|
assert.dom('input[type=radio]').exists();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it checks the input when the label is clicked and has a `for` attribute', async function(assert) {
|
|
|
|
assert.expect(2);
|
|
|
|
|
|
|
|
this.set('value', 'component-value');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@radioId='green-0'
|
|
|
|
@radioClass='my-radio-class'
|
|
|
|
@groupValue='initial-group-value'
|
|
|
|
@value={{value}}
|
|
|
|
>
|
|
|
|
Green
|
|
|
|
</RadioButtonComposer>
|
|
|
|
`);
|
|
|
|
|
|
|
|
await click('label');
|
|
|
|
|
|
|
|
assert.dom('label').hasAttribute('for', 'green-0');
|
|
|
|
assert.dom('input').hasAttribute('id', 'green-0');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it updates when setting `value` with isEqual', async function(assert) {
|
|
|
|
assert.expect(3);
|
|
|
|
|
|
|
|
this.set('groupValue', alice);
|
|
|
|
this.set('value', bob);
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue={{this.groupValue}}
|
|
|
|
@value={{this.value}}
|
|
|
|
/>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, false);
|
|
|
|
|
|
|
|
this.set('value', alice2);
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, true);
|
|
|
|
|
|
|
|
this.set('value', bob);
|
|
|
|
|
|
|
|
assert.equal(this.element.querySelector('input')?.checked, false);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it binds `aria-labelledby` when specified', async function(assert) {
|
|
|
|
assert.expect(2);
|
|
|
|
|
|
|
|
this.set('ariaLabelledby', 'green-label');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue='initial-group-value'
|
|
|
|
@value='value'
|
|
|
|
aria-labelledby={{this.ariaLabelledby}}
|
|
|
|
>
|
|
|
|
Green
|
|
|
|
</RadioButtonComposer>
|
|
|
|
`);
|
|
|
|
|
|
|
|
assert.dom('input').hasAttribute('aria-labelledby', 'green-label');
|
|
|
|
assert.dom('input[value="value"]').hasAttribute('aria-labelledby', 'green-label');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('it binds `aria-describedby` when specified', async function(assert) {
|
|
|
|
assert.expect(1);
|
|
|
|
|
|
|
|
this.set('ariaDescribedby', 'green-label');
|
|
|
|
|
|
|
|
await render(hbs`
|
|
|
|
<RadioButtonComposer
|
|
|
|
@groupValue='initial-group-value'
|
|
|
|
@value='value'
|
|
|
|
aria-describedby={{this.ariaDescribedby}}
|
|
|
|
>
|
|
|
|
Green
|
|
|
|
</RadioButtonComposer>
|
|
|
|
`);
|
|
|
|
assert.dom('input').hasAttribute('aria-describedby', 'green-label');
|
|
|
|
});
|
2019-08-31 20:51:14 -07:00
|
|
|
});
|