Skip to content

Commit

Permalink
Add tests for @validateOn="change"
Browse files Browse the repository at this point in the history
  • Loading branch information
simonihmig committed Jan 27, 2023
1 parent 2ee44c1 commit f7a640c
Showing 1 changed file with 246 additions and 128 deletions.
374 changes: 246 additions & 128 deletions test-app/tests/integration/components/headless-form-validation-test.gts
Original file line number Diff line number Diff line change
Expand Up @@ -846,146 +846,264 @@ module('Integration Component HeadlessForm > Validation', function (hooks) {
);
});

module('@validateOn="blur"', function () {
test('form validation callback is called on blur', async function (assert) {
const data: TestFormData = { firstName: 'Tony', lastName: 'Ward' };
const validateCallback = sinon.spy();

await render(<template>
<HeadlessForm
@data={{data}}
@validateOn="blur"
@validate={{validateCallback}}
as |form|
>
<form.field @name="firstName" as |field|>
<field.label>First Name</field.label>
<field.input data-test-first-name />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

await fillIn('[data-test-first-name]', 'Foo');

assert.false(
validateCallback.called,
'@validate is not called while typing'
);

await blur('[data-test-first-name]');

assert.true(
validateCallback.calledWith({ ...data, firstName: 'Foo' }),
'@validate is called with form data'
);
});

test('field validation callback is called on blur', async function (assert) {
const data: TestFormData = { firstName: 'Tony', lastName: 'Ward' };
const validateCallback = sinon.spy();

await render(<template>
<HeadlessForm @data={{data}} @validateOn="blur" as |form|>
<form.field
@name="firstName"
module(`@validateOn`, function () {
module('blur', function () {
test('form validation callback is called on blur', async function (assert) {
const data: TestFormData = { firstName: 'Tony', lastName: 'Ward' };
const validateCallback = sinon.spy();

await render(<template>
<HeadlessForm
@data={{data}}
@validateOn="blur"
@validate={{validateCallback}}
as |field|
as |form|
>
<field.label>First Name</field.label>
<field.input data-test-first-name />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

await fillIn('[data-test-first-name]', 'Foo');

assert.false(
validateCallback.called,
'@validate is not called while typing'
);

await blur('[data-test-first-name]');

assert.true(
validateCallback.calledWith('Foo', 'firstName', {
...data,
firstName: 'Foo',
}),
'@validate is called with form data'
);
});

test('validation errors are exposed as field.errors on blur', async function (assert) {
const data: TestFormData = { firstName: 'Foo', lastName: 'Foo' };

await render(<template>
<HeadlessForm
@data={{data}}
@validateOn="blur"
@validate={{validateFormCallbackSync}}
as |form|
>
<form.field @name="firstName" as |field|>
<field.label>First Name</field.label>
<field.input data-test-first-name />
<field.errors data-test-first-name-errors />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
<field.errors data-test-last-name-errors />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

assert
.dom('[data-test-first-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
<form.field @name="firstName" as |field|>
<field.label>First Name</field.label>
<field.input data-test-first-name />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

await fillIn('[data-test-first-name]', 'Foo');

assert.false(
validateCallback.called,
'@validate is not called while typing'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'

await blur('[data-test-first-name]');

assert.true(
validateCallback.calledWith({ ...data, firstName: 'Foo' }),
'@validate is called with form data'
);
});

await fillIn('[data-test-first-name]', 'Foo');
test('field validation callback is called on blur', async function (assert) {
const data: TestFormData = { firstName: 'Tony', lastName: 'Ward' };
const validateCallback = sinon.spy();

assert
.dom('[data-test-first-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
await render(<template>
<HeadlessForm @data={{data}} @validateOn="blur" as |form|>
<form.field
@name="firstName"
@validate={{validateCallback}}
as |field|
>
<field.label>First Name</field.label>
<field.input data-test-first-name />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

await fillIn('[data-test-first-name]', 'Foo');

assert.false(
validateCallback.called,
'@validate is not called while typing'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'

await blur('[data-test-first-name]');

assert.true(
validateCallback.calledWith('Foo', 'firstName', {
...data,
firstName: 'Foo',
}),
'@validate is called with form data'
);
});

test('validation errors are exposed as field.errors on blur', async function (assert) {
const data: TestFormData = { firstName: 'Foo', lastName: 'Foo' };

await render(<template>
<HeadlessForm
@data={{data}}
@validateOn="blur"
@validate={{validateFormCallbackSync}}
as |form|
>
<form.field @name="firstName" as |field|>
<field.label>First Name</field.label>
<field.input data-test-first-name />
<field.errors data-test-first-name-errors />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
<field.errors data-test-last-name-errors />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

assert
.dom('[data-test-first-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
);

await fillIn('[data-test-first-name]', 'Foo');

assert
.dom('[data-test-first-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
);

await blur('[data-test-first-name]');

await blur('[data-test-first-name]');
assert
.dom('[data-test-first-name-errors]')
.exists(
{ count: 1 },
'validation errors appear on blur when validation fails'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered for untouched fields'
);
});
});

module('change', function () {
test('form validation callback is called on change', async function (assert) {
const data: TestFormData = { firstName: 'Tony', lastName: 'Ward' };
const validateCallback = sinon.spy();

assert
.dom('[data-test-first-name-errors]')
.exists(
{ count: 1 },
'validation errors appear on blur when validation fails'
await render(<template>
<HeadlessForm
@data={{data}}
@validateOn="change"
@validate={{validateCallback}}
as |form|
>
<form.field @name="firstName" as |field|>
<field.label>First Name</field.label>
<field.input data-test-first-name />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

await fillIn('[data-test-first-name]', 'Foo');

assert.true(
validateCallback.calledWith({ ...data, firstName: 'Foo' }),
'@validate is called with form data'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered for untouched fields'
});

test('field validation callback is called on change', async function (assert) {
const data: TestFormData = { firstName: 'Tony', lastName: 'Ward' };
const validateCallback = sinon.spy();

await render(<template>
<HeadlessForm @data={{data}} @validateOn="change" as |form|>
<form.field
@name="firstName"
@validate={{validateCallback}}
as |field|
>
<field.label>First Name</field.label>
<field.input data-test-first-name />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

await fillIn('[data-test-first-name]', 'Foo');

assert.true(
validateCallback.calledWith('Foo', 'firstName', {
...data,
firstName: 'Foo',
}),
'@validate is called with form data'
);
});

test('validation errors are exposed as field.errors on change', async function (assert) {
const data: TestFormData = { firstName: 'Foo', lastName: 'Foo' };

await render(<template>
<HeadlessForm
@data={{data}}
@validateOn="change"
@validate={{validateFormCallbackSync}}
as |form|
>
<form.field @name="firstName" as |field|>
<field.label>First Name</field.label>
<field.input data-test-first-name />
<field.errors data-test-first-name-errors />
</form.field>
<form.field @name="lastName" as |field|>
<field.label>Last Name</field.label>
<field.input data-test-last-name />
<field.errors data-test-last-name-errors />
</form.field>
<button type="submit" data-test-submit>Submit</button>
</HeadlessForm>
</template>);

assert
.dom('[data-test-first-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered before validation happens'
);

await fillIn('[data-test-first-name]', 'Foo');

assert
.dom('[data-test-first-name-errors]')
.exists(
{ count: 1 },
'validation errors appear on blur when validation fails'
);
assert
.dom('[data-test-last-name-errors]')
.doesNotExist(
'validation errors are not rendered for untouched fields'
);
});
});
});
});

0 comments on commit f7a640c

Please sign in to comment.