From e196071c80f1dab4a3749c1c602cf1a95912437a Mon Sep 17 00:00:00 2001 From: Matthew Hartstonge Date: Wed, 13 Nov 2024 13:53:02 +1300 Subject: [PATCH] feat(addon/components/paper-form)!: yield self as parent, so that child components can migrate to consuming the parent to enable expected form validation/submission. --- addon/components/paper-form.hbs | 1 + .../integration/components/paper-form-test.js | 248 ++++++++++++------ 2 files changed, 167 insertions(+), 82 deletions(-) diff --git a/addon/components/paper-form.hbs b/addon/components/paper-form.hbs index 85bb0b6f6..ece5a1034 100644 --- a/addon/components/paper-form.hbs +++ b/addon/components/paper-form.hbs @@ -22,6 +22,7 @@ onValidityChange=this.localOnValidityChange ) onSubmit=this.localOnSubmit + parent=this ) }} \ No newline at end of file diff --git a/tests/integration/components/paper-form-test.js b/tests/integration/components/paper-form-test.js index 8e1d95844..04c6b2f1e 100644 --- a/tests/integration/components/paper-form-test.js +++ b/tests/integration/components/paper-form-test.js @@ -1,14 +1,14 @@ -/* eslint-disable ember/no-classic-components, prettier/prettier */ +/* eslint-disable ember/no-classic-components */ import Component from '@ember/component'; -import { module, test } from 'qunit'; +import { module, test, skip } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { render, triggerEvent, click } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; -module('Integration | Component | paper form', function(hooks) { +module('Integration | Component | paper form', function (hooks) { setupRenderingTest(hooks); - test('`isInvalid` and `isValid` work as expected', async function(assert) { + test('`isInvalid` and `isValid` work as expected', async function (assert) { assert.expect(4); await render(hbs` @@ -29,19 +29,22 @@ module('Integration | Component | paper form', function(hooks) { assert.dom('.invalid-div').doesNotExist(); assert.dom('.valid-div').exists({ count: 1 }); - this.set('errors', [{ - message: 'foo should be a number.', - attribute: 'foo' - }, { - message: 'foo should be smaller than 12.', - attribute: 'foo' - }]); + this.set('errors', [ + { + message: 'foo should be a number.', + attribute: 'foo', + }, + { + message: 'foo should be smaller than 12.', + attribute: 'foo', + }, + ]); assert.dom('.invalid-div').exists({ count: 1 }); assert.dom('.valid-div').doesNotExist(); }); - test('form `onSubmit` action is invoked and `onInvalid` is not', async function(assert) { + test('form `onSubmit` action is invoked and `onInvalid` is not', async function (assert) { assert.expect(1); this.set('onSubmit', () => { @@ -65,7 +68,7 @@ module('Integration | Component | paper form', function(hooks) { await click('button'); }); - test('form `onInvalid` action is invoked and `onSubmit` is not when the form is not valid', async function(assert) { + test('form `onInvalid` action is invoked and `onSubmit` is not when the form is not valid', async function (assert) { assert.expect(1); this.set('onSubmit', () => { @@ -87,7 +90,7 @@ module('Integration | Component | paper form', function(hooks) { await click('button[type=submit]'); }); - test('form `onValidityChange` action is invoked', async function(assert) { + test('form `onValidityChange` action is invoked', async function (assert) { // paper-input triggers `onValidityChange` on render // so we expect two runs: one on render and another on validity change assert.expect(9); @@ -119,17 +122,19 @@ module('Integration | Component | paper form', function(hooks) { assert.ok(isInvalidAndTouched); }); - this.set('errors', [{ - message: 'foo should be a number.', - attribute: 'foo' - }, { - message: 'foo should be smaller than 12.', - attribute: 'foo' - }]); - + this.set('errors', [ + { + message: 'foo should be a number.', + attribute: 'foo', + }, + { + message: 'foo should be smaller than 12.', + attribute: 'foo', + }, + ]); }); - test('form is reset after submit action is invoked', async function(assert) { + test('form is reset after submit action is invoked', async function (assert) { assert.expect(3); await render(hbs` @@ -155,7 +160,7 @@ module('Integration | Component | paper form', function(hooks) { assert.dom('.ng-dirty').doesNotExist('inputs were reset'); }); - test('works without using contextual components', async function(assert) { + skip('works without using contextual components', async function (assert) { assert.expect(4); await render(hbs` @@ -176,19 +181,58 @@ module('Integration | Component | paper form', function(hooks) { assert.dom('.invalid-div').doesNotExist(); assert.dom('.valid-div').exists({ count: 1 }); - this.set('errors', [{ - message: 'foo should be a number.', - attribute: 'foo' - }, { - message: 'foo should be smaller than 12.', - attribute: 'foo' - }]); + this.set('errors', [ + { + message: 'foo should be a number.', + attribute: 'foo', + }, + { + message: 'foo should be smaller than 12.', + attribute: 'foo', + }, + ]); + + assert.dom('.invalid-div').exists({ count: 1 }); + assert.dom('.valid-div').doesNotExist(); + }); + + test('works without using contextual components by binding in the yielded parent', async function (assert) { + assert.expect(4); + + await render(hbs` + {{#paper-form as |form|}} + {{paper-input parentComponent=form.parent value=foo onChange=(action (mut foo)) label="Foo"}} + {{paper-input parentComponent=form.parent value=bar onChange=(action (mut bar)) label="Bar" errors=errors}} + + {{#if form.isInvalid}} +
Form is invalid!
+ {{/if}} + {{#if form.isValid}} +
Form is valid!
+ {{/if}} + + {{/paper-form}} + `); + + assert.dom('.invalid-div').doesNotExist(); + assert.dom('.valid-div').exists({ count: 1 }); + + this.set('errors', [ + { + message: 'foo should be a number.', + attribute: 'foo', + }, + { + message: 'foo should be smaller than 12.', + attribute: 'foo', + }, + ]); assert.dom('.invalid-div').exists({ count: 1 }); assert.dom('.valid-div').doesNotExist(); }); - test('form submit button renders', async function(assert) { + test('form submit button renders', async function (assert) { assert.expect(1); await render(hbs` @@ -200,7 +244,7 @@ module('Integration | Component | paper form', function(hooks) { assert.dom('button').exists({ count: 1 }); }); - test('form submit button calls form onSubmit action', async function(assert) { + test('form submit button calls form onSubmit action', async function (assert) { assert.expect(1); this.set('onSubmit', () => { @@ -216,7 +260,7 @@ module('Integration | Component | paper form', function(hooks) { await click('button'); }); - test('form submit button is of type submit', async function(assert) { + test('form submit button is of type submit', async function (assert) { assert.expect(1); await render(hbs` @@ -228,12 +272,15 @@ module('Integration | Component | paper form', function(hooks) { assert.dom('button').hasAttribute('type', 'submit'); }); - test('form submit button component can be customized by passing `submitButtonComponent`', async function(assert) { + test('form submit button component can be customized by passing `submitButtonComponent`', async function (assert) { assert.expect(1); - this.owner.register('component:custom-submit-button', Component.extend({ - classNames: ['custom-submit-button'] - })); + this.owner.register( + 'component:custom-submit-button', + Component.extend({ + classNames: ['custom-submit-button'], + }) + ); await render(hbs` {{#paper-form submitButtonComponent="custom-submit-button" as |form|}} @@ -241,11 +288,12 @@ module('Integration | Component | paper form', function(hooks) { {{/paper-form}} `); - assert.dom('.custom-submit-button') + assert + .dom('.custom-submit-button') .exists({ count: 1 }, 'custom submit button is displayed'); }); - test('form `onSubmit` action is invoked when form element is submitted', async function(assert) { + test('form `onSubmit` action is invoked when form element is submitted', async function (assert) { assert.expect(1); this.set('onSubmit', () => { @@ -265,12 +313,15 @@ module('Integration | Component | paper form', function(hooks) { await click('input[type=submit]'); }); - test('yielded form.input renders the `paper-input`-component', async function(assert) { + test('yielded form.input renders the `paper-input`-component', async function (assert) { assert.expect(1); - this.owner.register('component:paper-input', Component.extend({ - classNames: ['paper-input'] - })); + this.owner.register( + 'component:paper-input', + Component.extend({ + classNames: ['paper-input'], + }) + ); await render(hbs` {{#paper-form as |form|}} @@ -278,20 +329,27 @@ module('Integration | Component | paper form', function(hooks) { {{/paper-form}} `); - assert.dom('.paper-input') + assert + .dom('.paper-input') .exists({ count: 1 }, 'paper-input component displayed'); }); - test('yielded form.input can be customized by passing `inputComponent`', async function(assert) { + test('yielded form.input can be customized by passing `inputComponent`', async function (assert) { assert.expect(2); - this.owner.register('component:paper-input', Component.extend({ - classNames: ['paper-input'] - })); + this.owner.register( + 'component:paper-input', + Component.extend({ + classNames: ['paper-input'], + }) + ); - this.owner.register('component:custom-input', Component.extend({ - classNames: ['custom-input'] - })); + this.owner.register( + 'component:custom-input', + Component.extend({ + classNames: ['custom-input'], + }) + ); await render(hbs` {{#paper-form inputComponent="custom-input" as |form|}} @@ -299,18 +357,23 @@ module('Integration | Component | paper form', function(hooks) { {{/paper-form}} `); - assert.dom('.paper-input') + assert + .dom('.paper-input') .doesNotExist('paper-input component is not displayed'); - assert.dom('.custom-input') + assert + .dom('.custom-input') .exists({ count: 1 }, 'custom input-component is displayed'); }); - test('yielded form.select renders `paper-select`-component', async function(assert) { + test('yielded form.select renders `paper-select`-component', async function (assert) { assert.expect(1); - this.owner.register('component:paper-select', Component.extend({ - classNames: ['paper-select'] - })); + this.owner.register( + 'component:paper-select', + Component.extend({ + classNames: ['paper-select'], + }) + ); await render(hbs` {{#paper-form as |form|}} @@ -318,20 +381,27 @@ module('Integration | Component | paper form', function(hooks) { {{/paper-form}} `); - assert.dom('.paper-select') + assert + .dom('.paper-select') .exists({ count: 1 }, 'paper-select is displayed'); }); - test('yielded form.select can be customized by passing `selectComponent`', async function(assert) { + test('yielded form.select can be customized by passing `selectComponent`', async function (assert) { assert.expect(2); - this.owner.register('component:paper-select', Component.extend({ - classNames: ['paper-select'] - })); + this.owner.register( + 'component:paper-select', + Component.extend({ + classNames: ['paper-select'], + }) + ); - this.owner.register('component:custom-select', Component.extend({ - classNames: ['custom-select'] - })); + this.owner.register( + 'component:custom-select', + Component.extend({ + classNames: ['custom-select'], + }) + ); await render(hbs` {{#paper-form selectComponent="custom-select" as |form|}} @@ -339,18 +409,23 @@ module('Integration | Component | paper form', function(hooks) { {{/paper-form}} `); - assert.dom('.paper-select') + assert + .dom('.paper-select') .doesNotExist('paper-select component is not displayed'); - assert.dom('.custom-select') + assert + .dom('.custom-select') .exists({ count: 1 }, 'custom select-component is displayed'); }); - test('yielded form.autocomplete renders `paper-autocomplete`-component', async function(assert) { + test('yielded form.autocomplete renders `paper-autocomplete`-component', async function (assert) { assert.expect(1); - this.owner.register('component:paper-autocomplete', Component.extend({ - classNames: ['paper-autocomplete'] - })); + this.owner.register( + 'component:paper-autocomplete', + Component.extend({ + classNames: ['paper-autocomplete'], + }) + ); await render(hbs` {{#paper-form as |form|}} @@ -358,20 +433,27 @@ module('Integration | Component | paper form', function(hooks) { {{/paper-form}} `); - assert.dom('.paper-autocomplete') + assert + .dom('.paper-autocomplete') .exists({ count: 1 }, 'paper-autocomplete is displayed'); }); - test('yielded form.autocomplete can be customized by passing `autocompleteComponent`', async function(assert) { + test('yielded form.autocomplete can be customized by passing `autocompleteComponent`', async function (assert) { assert.expect(2); - this.owner.register('component:paper-autocomplete', Component.extend({ - classNames: ['paper-autocomplete'] - })); + this.owner.register( + 'component:paper-autocomplete', + Component.extend({ + classNames: ['paper-autocomplete'], + }) + ); - this.owner.register('component:custom-autocomplete', Component.extend({ - classNames: ['custom-autocomplete'] - })); + this.owner.register( + 'component:custom-autocomplete', + Component.extend({ + classNames: ['custom-autocomplete'], + }) + ); await render(hbs` {{#paper-form autocompleteComponent="custom-autocomplete" as |form|}} @@ -379,9 +461,11 @@ module('Integration | Component | paper form', function(hooks) { {{/paper-form}} `); - assert.dom('.paper-autocomplete') + assert + .dom('.paper-autocomplete') .doesNotExist('paper-autocomplete component is not displayed'); - assert.dom('.custom-autocomplete') + assert + .dom('.custom-autocomplete') .exists({ count: 1 }, 'custom autocomplete-component is displayed'); }); });