Skip to content

Commit

Permalink
✅ Rewrite tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wwilsman committed Feb 6, 2024
1 parent 360f8a1 commit 55cfdf6
Show file tree
Hide file tree
Showing 26 changed files with 1,577 additions and 135 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"test": "npm run lint && npm run test:types && npm run test:coverage",
"test:coverage": "nyc npm run test:only",
"test:debug": "npm run test:only -- --debug",
"test:only": "NODE_ENV=test node tests/start.js",
"test:types": "tsc --build tests",
"test:only": "NODE_ENV=test node tests/run.js",
"test:types": "tsc --project tests",
"lint": "eslint --ignore-path .gitignore --ignore-pattern www ."
},
"devDependencies": {
Expand Down
31 changes: 31 additions & 0 deletions tests/actions/blur.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { describe, it, beforeEach } from 'moonshiner';
import { I, assert, fixture } from '../helpers';

describe('Actions | #blur(selector?)', () => {
beforeEach(() => {
fixture(`
<h1 tabindex="0">Foo</h1>
<button>Bar</button>
`);
});

it('blurs the current element', async () => {
let $foo = document.querySelector('h1');
let $bar = document.querySelector('button');

$foo.focus();
await I.blur('Foo');
await assert(document.activeElement !== $foo,
'Expected "Foo" to not be focused');

$bar.focus();
await I.find('Bar').then.blur();
await assert(document.activeElement !== $bar,
'Expected "Bar" to not be focused');
});

it('asserts the element is focused', async () => {
await assert.throws(I.blur('Foo'),
'"Foo" is not focused');
});
});
127 changes: 127 additions & 0 deletions tests/actions/click.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { describe, it } from 'moonshiner';
import { I, assert, fixture, listen } from '../helpers';

describe('Actions | #click(selector?)', () => {
it('clicks the current element', async () => {
fixture('<button>Foo</button>');
let event = listen('button', 'click');

await I.click('Foo');
await assert(event.calls.length === 1,
'Expected to click "Foo"');

await I.find('Foo').then.click();
await assert(event.calls.length === 2,
'Expected to click "Foo" a second time');
});

it('asserts the element is not disabled', async () => {
fixture('<button disabled>Bar</button>');
let event = listen('button', 'click');

await assert.throws(I.click('Bar'),
'"Bar" is disabled');
await assert(event.calls.length === 0,
'Expected "Bar" to not be clicked');
});

it('checks and unchecks checkbox and radio elements', async () => {
fixture(`
<input id="check" type="checkbox" />
<label for="check">Baz</label>
<input name="radios" id="radio-1" type="radio" />
<label for="radio-1">Qux</label>
<input name="radios" id="radio-2" type="radio" />
<label for="radio-2">Xyzzy</label>
`);

await I.click('Baz');
await assert(document.getElementById('check').checked === true,
'Expected "Baz" to be checked');

await I.click('Baz');
await assert(document.getElementById('check').checked === false,
'Expected "Baz" to not be checked');

await I.click('Qux');
await assert(document.getElementById('radio-1').checked === true,
'Expected "Qux" to be checked');
await assert(document.getElementById('radio-2').checked === false,
'Expected "Xyzzy" to not be checked');

await I.click('Xyzzy');
await assert(document.getElementById('radio-1').checked === false,
'Expected "Qux" to not be checked');
await assert(document.getElementById('radio-2').checked === true,
'Expected "Xyzzy" to be checked');
});

it('selects options within select elements', async () => {
fixture(`
<select>
<option disabled>Choose</option>
<option>Foo</option>
<option>Bar</option>
</select>
`);

let input = listen('select', 'input');
let change = listen('select', 'change');

await I.click('Foo');
await assert(input.$.value === 'Foo',
'Expected "Foo" to be selected');

await I.click('Bar');
await assert(input.$.value === 'Bar',
'Expected "Bar" to be selected');

await assert(input.calls.length === 2,
'Expected input events when selecting options');
await assert(change.calls.length === 2,
'Expected change events when selecting options');
});

it('asserts the option select element is not disabled', async () => {
fixture(`
<select disabled>
<option disabled>Choose</option>
<option>Foo</option>
<option>Bar</option>
</select>
`);

let event = listen('select', 'change');

await assert.throws(I.click('Foo'),
'"Foo" select is disabled');
await assert(event.calls.length === 0,
'Expected change event not to be triggered');
});

it('selects and deselects options within multi-select elements', async () => {
fixture(`
<select multiple>
<option>Foo</option>
<option>Bar</option>
</select>
`);

let event = listen('select', 'change');

await I.click('Foo');
await I.click('Bar');

await assert(
event.$.selectedOptions[0].value === 'Foo' &&
event.$.selectedOptions[1].value === 'Bar',
'Expected "Foo" and "Bar" to be selected');

await I.click('Foo');

await assert(
event.$.selectedOptions[0].value === 'Bar' &&
!event.$.selectedOptions[1],
'Expected only "Bar" to be selected');
});
});
30 changes: 30 additions & 0 deletions tests/actions/focus.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, it, beforeEach } from 'moonshiner';
import { I, assert, fixture } from '../helpers';

describe('Actions | #focus(selector?)', () => {
beforeEach(() => {
fixture(`
<h1 tabindex="0">Foo</h1>
<button>Bar</button>
<label>Baz</label>
`);
});

it('focuses the current element', async () => {
let $foo = document.querySelector('h1');
let $bar = document.querySelector('button');

await I.focus('Foo');
await assert(document.activeElement === $foo,
'Expected "Foo" to have focus');

await I.find('Bar').then.focus();
await assert(document.activeElement === $bar,
'Expected "Bar" to have focus');
});

it('asserts the element is focusable', async () => {
await assert.throws(I.focus('Baz'),
'"Baz" is not focusable');
});
});
150 changes: 150 additions & 0 deletions tests/actions/press.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { describe, it } from 'moonshiner';
import { I, assert, fixture, listen } from '../helpers';

describe('Actions | #press(keys, options?)', () => {
it('triggers keyboard events for the current element', async () => {
fixture('<div class="foo">Foo</div>');

let events = {
keydown: listen('.foo', 'keydown'),
beforeinput: listen('.foo', 'beforeinput'),
input: listen('.foo', 'input'),
keyup: listen('.foo', 'keyup')
};

await I.find('Foo')
.then.press('Delete');

for (let event in events) {
if (event === 'keydown' || event === 'keyup') {
await assert(
events[event].calls.length === 1 &&
events[event].calls[0][0].key === 'Delete',
`Expected \`${event}\` event for "Delete"`);
} else {
await assert(events[event].calls.length === 0,
`Unexpected \`${event}\` event for "Delete"`);
}
}
});

it('triggers input events for the current input element', async () => {
fixture('<input placeholder="Bar" />');

let events = {
keydown: listen('input', 'keydown'),
beforeinput: listen('input', 'beforeinput', e => {
if (e.key === 'C') e.preventDefault();
}),
input: listen('input', 'input'),
keyup: listen('input', 'keyup')
};

await I.find('Bar')
.then.press('B');

for (let event in events) {
await assert(
events[event].calls.length === 1 &&
events[event].calls[0][0].key === 'B',
`Expected \`${event}\` event for "B"`);
}

await I.find('Bar')
.then.press('C');

await assert(events.beforeinput.calls.length === 2,
'Expected a second beforeinput event');
await assert(events.input.calls.length === 1,
'Expected second input event to be canceled');
});

it('does not accept arbitrary key names', async () => {
await assert.throws(() => I.press('KeyFoo'),
'Unknown key `KeyFoo`');
});

it('can insert or replace text within relevant elements', async () => {
fixture('<div contenteditable>Fo</div>');
let $ = document.querySelector('[contenteditable]');

await I.find($)
.then.press('KeyO');

await assert($.innerText === 'Foo',
'Expected content editable text to be "Foo"');

await I.find($)
.then.press('!', { replace: true });

await assert($.innerText === '!',
'Expected content editable text to be "!"');

$.innerText = 'Bar';

await I.find($)
.then.press('z', { range: [2, 3] });

await assert($.innerText === 'Baz',
'Expected content editable text to be "Baz"');
});

it('replaces any existing text selection', async () => {
fixture('<div contenteditable>Qoox</div>');
let $ = document.querySelector('[contenteditable]');

let range = document.createRange();
range.setStart($.firstChild, 1);
range.setEnd($.firstChild, 3);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

await I.find($)
.then.press('u');

await assert($.innerText === 'Qux',
'Expected content editable text to be "Qux"');
});

it('can delete text within relevant elements', async () => {
fixture('<input placeholder="Foo" value="FFooo" />');

await I.find('Foo')
.then.press('Backspace')
.then.press('Delete', { range: 0 });

await assert(document.querySelector('input').value === 'Foo',
'Expected "Foo" value to be "Foo"');
});

it('can hold a key in an interaction until the next press', async () => {
fixture('<input placeholder="Baz" />');

await I.find('Baz')
.then.press('Shift', { hold: true })
.then.press('KeyB')
.then.press('Shift')
.then.press(['KeyA', 'KeyZ'])
.then.press(['Shift', 'Digit1']);

await assert(document.querySelector('input').value === 'Baz!',
'Expected "Baz" to have a value of "Baz!"');
});

it('retains any custom value descriptors for relevant elements', async () => {
fixture('<input placeholder="Qux" />');
let $input = document.querySelector('input');
let value = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');

Object.defineProperty($input, 'value', {
...value, get: () => value.get.apply($input) + 'oo'
});

await I.find('Qux')
.then.press('KeyF');

await assert($input.value === 'foo',
'Expected "Qux" value to be "foo"');
});
});
33 changes: 33 additions & 0 deletions tests/actions/trigger.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, it, beforeEach } from 'moonshiner';
import { I, assert, fixture, listen } from '../helpers';

describe('Actions | #trigger(eventName, options?)', () => {
beforeEach(() => {
fixture('<div class="foo">Foo</div>');
});

it('triggers an arbitrary event on the current element', async () => {
let event = listen('.foo', 'foobar');

await I.find('Foo')
.then.trigger('foobar');

await assert(event.calls.length === 1,
'Expected "foobar" event to be triggered');
});

it('bubbles and is cancelable by default', async () => {
let event = listen('.foo', 'xyzzy');

await I.find('Foo')
.then.trigger('xyzzy', { foo: 'bar' })
.then.trigger('xyzzy', { bubbles: null, cancelable: false });

await assert(event.calls[0][0].foo === 'bar',
'Expected "xyzzy" event to include event properties');
await assert(event.calls[0][0].bubbles && event.calls[0][0].cancelable,
'Expected "xyzzy" event to bubble and be cancelable');
await assert(!event.calls[1][0].bubbles && !event.calls[1][0].cancelable,
'Expected "xyzzy" event to not bubble and not be cancelable');
});
});
Loading

0 comments on commit 55cfdf6

Please sign in to comment.