Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isValid assertion #741

Merged
merged 3 commits into from
Jun 22, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions lib/__tests__/is-valid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/* eslint-env jest */
import TestAssertions from '../helpers/test-assertions';

describe('assert.dom(...).isValid()', () => {
let assert: TestAssertions;

beforeEach(() => {
assert = new TestAssertions();
});

describe('invalid', () => {
test('with no custom message', () => {
document.body.innerHTML = '<input type="text" required>';

assert.dom('input').isValid();
expect(assert.results).toEqual([
{
actual: 'not valid',
expected: 'valid',
message: 'Element input is not valid',
result: false,
},
]);
});

test('with custom message', () => {
document.body.innerHTML = '<input type="text" required>';

assert.dom('input').isValid('custom message');
expect(assert.results).toEqual([
{
actual: 'not valid',
expected: 'valid',
message: 'custom message',
result: false,
},
]);
});
});

describe('valid', () => {
test('with no custom message', () => {
document.body.innerHTML = '<input type="text" value="foo" required>';

assert.dom('input').isValid();
expect(assert.results).toEqual([
{
actual: 'valid',
expected: 'valid',
message: 'Element input is valid',
result: true,
},
]);
});
});

describe('with HTMLElement', () => {
let element: HTMLInputElement;

beforeEach(() => {
document.body.innerHTML = '<input type="text" value="foo" required>';
element = document.querySelector('input');
});

test('succeeds if element is valid', () => {
assert.dom(element).isValid();

expect(assert.results).toEqual([
{
actual: 'valid',
expected: 'valid',
message: 'Element input[type="text"][value="foo"][required] is valid',
result: true,
},
]);
});

test('passes if element is not required', () => {
element.required = false;
assert.dom(element).isValid();

expect(assert.results).toEqual([
{
actual: 'valid',
expected: 'valid',
message: 'Element input[type="text"][value="foo"] is valid',
result: true,
},
]);
});

test('fails for missing element', () => {
assert.dom(null).isValid();

expect(assert.results).toEqual([
{
message: 'Element <unknown> should exist',
result: false,
},
]);
});
});

describe('with selector', () => {
beforeEach(() => {
document.body.innerHTML = '<input type="text" value="foo" required>';
});

test('succeeds if element is required', () => {
assert.dom('input').isValid();

expect(assert.results).toEqual([
{
actual: 'valid',
expected: 'valid',
message: 'Element input is valid',
result: true,
},
]);
});

test('succeeds if element is not required', () => {
document.querySelector('input').required = false;
assert.dom('input').isValid();

expect(assert.results).toEqual([
{
actual: 'valid',
expected: 'valid',
message: 'Element input is valid',
result: true,
},
]);
});

test('fails for missing element', () => {
assert.dom('input[type="password"]').isValid();

expect(assert.results).toEqual([
{
message: 'Element input[type="password"] should exist',
result: false,
},
]);
});
});

test('throws for unexpected parameter types', () => {
//@ts-ignore -- These assertions are for JavaScript users who don't have type checking
expect(() => assert.dom(5).isValid()).toThrow('Unexpected Parameter: 5');
//@ts-ignore
expect(() => assert.dom(true).isValid()).toThrow('Unexpected Parameter: true');
expect(() => assert.dom(undefined).isValid()).toThrow('Unexpected Parameter: undefined');
//@ts-ignore
expect(() => assert.dom({}).isValid()).toThrow('Unexpected Parameter: [object Object]');
//@ts-ignore
expect(() => assert.dom(document).isValid()).toThrow('Unexpected Parameter: [object Document]');
expect(() => assert.dom(document.createElement('div')).isValid()).toThrow(
'Unexpected Element Type: [object HTMLDivElement]'
);
});

test('supports chaining', () => {
document.body.innerHTML = '<input type="text" required/>';

assert.dom('input').isValid().isValid();

expect(assert.results.length).toEqual(2);
});
});
20 changes: 20 additions & 0 deletions lib/assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import isChecked from './assertions/is-checked';
import isNotChecked from './assertions/is-not-checked';
import isRequired from './assertions/is-required';
import isNotRequired from './assertions/is-not-required';
import isValid from './assertions/is-valid';
import isVisible from './assertions/is-visible';
import isDisabled from './assertions/is-disabled';
import matchesSelector from './assertions/matches-selector';
Expand Down Expand Up @@ -193,6 +194,25 @@ export default class DOMAssertions {
return this;
}

/**
* Assert that the {@link HTMLElement} passes validation
*
* Validity is determined by asserting that:
*
* - `element.reportValidity() === true`
*
* @param {string?} message
*
* @example
* assert.dom('.input').isValid();
*
* @see {@link #isValid}
*/
isValid(message?: string): DOMAssertions {
isValid.call(this, message);
return this;
}

/**
* Assert that the {@link HTMLElement} or an {@link HTMLElement} matching the
* `selector` exists and is visible.
Expand Down
29 changes: 29 additions & 0 deletions lib/assertions/is-valid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import elementToString from '../helpers/element-to-string';

export default function isValid(message?: string) {
let element = this.findTargetElement();
if (!element) return;

if (
!(
element instanceof HTMLFormElement ||
element instanceof HTMLInputElement ||
element instanceof HTMLTextAreaElement ||
element instanceof HTMLButtonElement ||
element instanceof HTMLOutputElement ||
element instanceof HTMLSelectElement
)
) {
throw new TypeError(`Unexpected Element Type: ${element.toString()}`);
}

let result = element.reportValidity() === true;
let actual = result ? 'valid' : 'not valid';
let expected = 'valid';

if (!message) {
message = `Element ${elementToString(this.target)} is ${actual}`;
}

this.pushResult({ result, actual, expected, message });
}