san650/ember-cli-page-object

View on GitHub
test-app/tests/unit/-private/composition-test.ts

Summary

Maintainability
A
2 hrs
Test Coverage
File `composition-test.ts` has 256 lines of code (exceeds 250 allowed). Consider refactoring.
import { setupRenderingTest } from '../../helpers';
import { test, module } from 'qunit';
import {
isPageObject,
getPageObjectDefinition,
// @ts-expect-error no types for import path are provided
} from 'ember-cli-page-object/-private/meta';
import { render, find } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import {
create,
triggerable,
collection,
isVisible,
text,
value,
} from 'ember-cli-page-object';
 
import { alias, getter } from 'ember-cli-page-object/macros';
 
module('Unit | composition', function () {
test('each page object node stores its definition', function (assert) {
const definition = {
foo: {
bar: {
get baz() {
return 'prop';
},
},
},
};
 
const page = create(definition);
const storedDef = getPageObjectDefinition(page);
assert.ok(storedDef);
assert.deepEqual(storedDef, definition);
 
const fooDef = getPageObjectDefinition(page.foo);
assert.ok(fooDef);
assert.deepEqual(fooDef, definition.foo);
 
const barDef = getPageObjectDefinition(page.foo.bar);
assert.ok(barDef);
assert.deepEqual(barDef, definition.foo.bar);
});
 
test('page objects can be composed from other page objects', function (assert) {
const definition = {
foo: {
bar: {
baz: 1,
},
},
};
 
const page = create(definition);
const pageComposer = create({
somePage: page,
});
assert.ok(pageComposer);
assert.ok(pageComposer.somePage);
 
const pageComposerDef = getPageObjectDefinition(pageComposer);
assert.ok(pageComposerDef);
assert.ok(isPageObject(pageComposerDef.somePage));
// we cant deep equal the definition since it contains a page object so we check the keys instead
assert.deepEqual(Object.keys(pageComposerDef), ['somePage']);
const somePageStoredDef = getPageObjectDefinition(pageComposerDef.somePage);
assert.deepEqual(somePageStoredDef, definition);
});
 
test('page objects can be used as the definition to create', function (assert) {
const definition = {
foo: 1,
};
 
const page = create(definition);
 
const pageComposer = create(page);
assert.ok(pageComposer);
assert.ok(pageComposer.foo);
 
assert.deepEqual(getPageObjectDefinition(pageComposer), definition);
});
 
test('page object composition supports many levels deep', function (assert) {
const definition = {
foo: {
bar: {
get baz() {
return 'prop';
},
},
},
};
 
const page = create(definition);
 
const pageComposer = create({
bar: {
baz: page,
},
});
assert.ok(pageComposer);
assert.ok(pageComposer.bar.baz);
 
// test that the definition is stored "as is"
const pageComposerDef = getPageObjectDefinition(pageComposer);
assert.ok(pageComposerDef);
assert.ok(pageComposerDef.bar);
assert.notOk(isPageObject(pageComposerDef.bar));
assert.ok(pageComposer.bar.baz);
assert.ok(isPageObject(pageComposerDef.bar.baz));
 
const bazDefiniton = getPageObjectDefinition(pageComposerDef.bar.baz);
assert.ok(bazDefiniton);
pageComposerDef.bar.baz = bazDefiniton;
// cant do a true deep equal without firing of page object selectors
assert.deepEqual(Object.keys(pageComposerDef), ['bar']);
assert.deepEqual(bazDefiniton, definition);
});
 
test('can compose from page object nested within another page object', function (assert) {
const { foo } = create({
foo: {
scope: '.foo',
},
});
 
assert.ok(foo);
assert.deepEqual(
getPageObjectDefinition(foo),
{ scope: '.foo' },
'nested stores definition'
);
 
const bar = create({ foo });
assert.ok(bar);
 
const barDefinition = getPageObjectDefinition(bar);
assert.ok(barDefinition);
assert.ok(barDefinition.foo);
assert.ok(isPageObject(barDefinition.foo));
 
const fooDefFromBar = getPageObjectDefinition(bar.foo);
assert.ok(fooDefFromBar);
 
// cannot do a true deep equal since foo is a page object
assert.deepEqual(Object.keys(barDefinition), ['foo']);
assert.deepEqual(fooDefFromBar, {
scope: '.foo',
});
});
 
test('getPageObjectDefinition errors if node is not a page object', function (assert) {
try {
getPageObjectDefinition({});
assert.true(false);
} catch (e) {
assert.strictEqual(
e?.toString(),
'Error: cannot get the page object definition from a node that is not a page object'
);
}
});
 
module('all properties via composition', function (hooks) {
setupRenderingTest(hooks);
 
test('can alias through composition', async function (assert) {
assert.expect(1);
 
const aliasPage = create({
isButtonVisible: isVisible('button'),
aliasedIsButtonVisible: alias('isButtonVisible'),
});
 
const page = create({
scope: '.container',
aliasPage: aliasPage,
});
await render(
hbs`<div class="container"><button type="button">Look at me</button></div>`
);
 
assert.ok(page.aliasPage.aliasedIsButtonVisible);
});
 
test('new pages can be composed from pages containing collections', async function (assert) {
const collectionPage = create({
foo: collection('span', {
text: text(),
}),
});
 
const page = create({
scope: '.container',
collectionPage: collectionPage,
});
await render(hbs`
<div class="container">
<span>Lorem</span>
<span>Ipsum</span>
</div>
`);
assert.equal(page.collectionPage.foo.objectAt(0).text, 'Lorem');
assert.equal(page.collectionPage.foo.objectAt(1).text, 'Ipsum');
});
 
test('collection supports taking a page object directly as its definition', async function (assert) {
const textPage = create({
spanText: text('span'),
});
const page = create({
scope: '.container',
collection: collection('li', textPage),
});
 
await render(hbs`
<ul class="container">
<li>Text <span>Lorem</span></li>
<li>Text <span>Ipsum</span></li>
</ul>
`);
 
assert.equal(page.collection.objectAt(0).spanText, 'Lorem');
assert.equal(page.collection.objectAt(1).spanText, 'Ipsum');
});
 
test('the collection definition can be composed from page objects', async function (assert) {
const textPage = create({
spanText: text('span'),
});
const page = create({
scope: '.container',
collection: collection('li', {
textPage: textPage,
}),
});
await render(hbs`
<ul class="container">
<li>Text <span>Lorem</span></li>
<li>Text <span>Ipsum</span></li>
</ul>
`);
 
assert.equal(page.collection.objectAt(0).textPage.spanText, 'Lorem');
assert.equal(page.collection.objectAt(1).textPage.spanText, 'Ipsum');
});
 
test("the composition of pages containing 'action' based descriptors is supported", async function (assert) {
assert.expect(1);
 
const expectedSelector = 'input';
const triggerPage = create({
foo: triggerable('focus', expectedSelector),
});
 
const page = create({
scope: '.container',
triggerPage: triggerPage,
});
await render(hbs`<div class="container"><input /></div>`);
 
find(expectedSelector)?.addEventListener('focus', () => {
assert.ok(1);
});
 
await page.triggerPage.foo();
});
 
test('new pages can be composed from pages containing custom getters', function (assert) {
assert.expect(2);
 
const getterPage = create({
foo: getter(function () {
return 'lorem';
}),
bar: getter(function () {
return 'ipsum';
}),
});
const page = create({
scope: '.container',
getterPage: getterPage,
});
assert.equal(page.getterPage.foo, 'lorem');
assert.equal(page.getterPage.bar, 'ipsum');
});
 
test('the composition of pages containing a getter based attribute is supported', async function (assert) {
const inputPage = create({
foo: value('input'),
});
 
const page = create({
scope: '.container',
input: inputPage,
});
await render(
hbs`<div class="container"><input value="Lorem ipsum"></div>`
);
 
assert.equal(page.input.foo, 'Lorem ipsum');
});
});
});