san650/ember-cli-page-object

View on GitHub
test-app/tests/unit/-private/action-test.js

Summary

Maintainability
B
6 hrs
Test Coverage
File `action-test.js` has 300 lines of code (exceeds 250 allowed). Consider refactoring.
import { module, test } from 'qunit';
import { create } from 'ember-cli-page-object';
import action from 'ember-cli-page-object/-private/action';
import { isPageObject } from 'ember-cli-page-object/-private/meta';
import { setAdapter, getAdapter } from 'ember-cli-page-object/adapters';
import Adapter from 'ember-cli-page-object/adapter';
 
class DummyAdapter extends Adapter {}
 
function assertThrowsErrorMessage(
assert,
block,
expectedMessage,
asserionMessage
) {
try {
block();
assert.true(false);
} catch (e) {
assert.strictEqual(e.toString(), expectedMessage, asserionMessage);
}
}
 
// Normally it should work with "0".
// However, since Promises are not supported in IE11, for async we rely on "RSVP" library,
// Unfortunatelly, for some of old "ember" versions there are timing lags coming from "RSVP",
// so we use a value larger than "0" to appease out test matrix.
const DEFAULT_NEXT_TICK_TIMEOUT = 20;
 
const next = (timeout = DEFAULT_NEXT_TICK_TIMEOUT) => {
return new Promise((r) => setTimeout(r, timeout));
};
 
class Deferred {
constructor() {
this.promise = new Promise(
function (resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}.bind(this)
);
 
Object.freeze(this);
}
}
 
module('Unit | action', function (hooks) {
let initialAdapter;
 
hooks.beforeEach(function () {
initialAdapter = getAdapter();
 
setAdapter(new DummyAdapter());
});
 
hooks.afterEach(function () {
setAdapter(initialAdapter);
});
 
let invoked, finished, node;
 
const testable = (query) => {
return action(query, function (id, deferred) {
invoked.push(id);
node = this;
 
return deferred.promise.then(() => {
finished.push(id);
});
});
};
 
hooks.beforeEach(function () {
invoked = [];
finished = [];
node = null;
});
 
test('it works', async function (assert) {
const p = create({
scope: 'it works',
 
run: testable({ selector: '.Selector' }),
});
 
const d1 = new Deferred();
p.run(1, d1);
 
assert.true(typeof node === 'object' && node !== null);
assert.equal(node, p, '');
 
assert.deepEqual(invoked, [1]);
assert.deepEqual(finished, []);
 
await d1.resolve();
 
assert.deepEqual(invoked, [1]);
assert.deepEqual(finished, [1]);
});
 
test('fails without arguments', async function (assert) {
try {
action();
assert.false(true, 'throws an exception for no argument');
} catch (e) {
assert.strictEqual(
e?.toString(),
'Error: `action()` expects a function argument.'
);
}
});
 
test('fails without an action callback', async function (assert) {
try {
action({});
assert.false(true, 'throws an exception for a single object argument');
} catch (e) {
assert.strictEqual(
e?.toString(),
'Error: `action()` expects a function argument.'
);
}
});
 
test('it handles sync errors', async function (assert) {
const p = create({
scope: '.Scope',
 
run: action({ selector: '.Selector' }, function () {
throw new Error('it was so fast!');
}),
});
 
assertThrowsErrorMessage(
assert,
() => p.run(1),
`Error: it was so fast!
 
PageObject: 'page.run("1")'
Selector: '.Scope .Selector'`
);
});
 
test('it handles sync errors w/o query', async function (assert) {
const p = create({
scope: '.Scope',
 
run: action(function () {
throw new Error('it was so fast!');
}),
});
 
assertThrowsErrorMessage(
assert,
() => p.run(1),
`Error: it was so fast!
 
PageObject: 'page.run("1")'
Selector: '.Scope'`
);
});
 
test('it handles async errors', async function (assert) {
Similar blocks of code found in 2 locations. Consider refactoring.
const p = create({
scope: '.Scope',
 
run: action({ selector: '.Selector' }, function () {
return next().then(() => {
throw new Error('bed time');
});
}),
});
 
Similar blocks of code found in 2 locations. Consider refactoring.
return p.run(1).then(
() => {
assert.true(false);
},
(e) => {
assert.strictEqual(
e.toString(),
`Error: bed time
 
PageObject: 'page.run("1")'\n Selector: '.Scope .Selector'`
);
}
);
});
 
module('chainability', function () {
test('it works', async function (assert) {
const p = create({
scope: '.root',
 
run: testable({ selector: '.Selector1' }),
 
child: {
scope: '.child',
 
run: testable({ selector: '.Selector2' }),
},
});
 
const d1 = new Deferred();
const running1 = p.run(1, d1);
assert.equal(isPageObject(running1), true);
assert.notStrictEqual(running1, p);
assert.equal(running1.scope, '.root');
assert.deepEqual(invoked, [1]);
assert.deepEqual(finished, []);
 
const d2 = new Deferred();
const running2 = running1.run(2, d2);
assert.strictEqual(running1, running2);
assert.deepEqual(invoked, [1]);
assert.deepEqual(finished, []);
 
const d3 = new Deferred();
const running3 = running2.child.run(3, d3);
assert.equal(isPageObject(running3), true);
assert.notStrictEqual(running1, running3);
assert.equal(running3.scope, '.child');
assert.deepEqual(invoked, [1]);
assert.deepEqual(finished, []);
 
d1.resolve();
await next();
 
assert.deepEqual(invoked, [1, 2]);
assert.deepEqual(finished, [1]);
 
d2.resolve();
await next();
 
assert.deepEqual(invoked, [1, 2, 3]);
assert.deepEqual(finished, [1, 2]);
 
await d3.resolve();
assert.deepEqual(invoked, [1, 2, 3]);
assert.deepEqual(finished, [1, 2, 3]);
});
 
test('concurrent from same root', async function (assert) {
const p = create({
scope: '.root',
 
run: testable({ selector: '.Selector1' }),
});
 
const d1 = new Deferred();
const running1 = p.run('1', d1);
assert.equal(isPageObject(running1), true);
assert.notStrictEqual(running1, p);
assert.equal(running1.scope, '.root');
assert.deepEqual(invoked, ['1']);
assert.deepEqual(finished, []);
 
const d11 = new Deferred();
const running11 = p.run('1.1', d11);
assert.strictEqual(running1, running11);
assert.deepEqual(invoked, ['1', '1.1']);
assert.deepEqual(finished, []);
 
const d12 = new Deferred();
const running12 = p.run('1.2', d12);
assert.strictEqual(running1, running12);
assert.deepEqual(invoked, ['1', '1.1', '1.2']);
assert.deepEqual(finished, []);
 
d1.resolve();
assert.deepEqual(invoked, ['1', '1.1', '1.2']);
assert.deepEqual(finished, []);
 
await next();
assert.deepEqual(finished, ['1']);
 
d12.resolve();
assert.deepEqual(finished, ['1']);
 
await next();
assert.deepEqual(finished, ['1', '1.2']);
 
d11.resolve();
assert.deepEqual(finished, ['1', '1.2']);
 
await next();
assert.deepEqual(finished, ['1', '1.2', '1.1']);
});
 
test('concurrent from same chain root', async function (assert) {
const p = create({
scope: '.root',
 
run: testable({ selector: '.Selector1' }),
});
 
const d1 = new Deferred();
const running1 = p.run('1', d1);
assert.equal(isPageObject(running1), true);
assert.notStrictEqual(running1, p);
assert.equal(running1.scope, '.root');
assert.deepEqual(invoked, ['1']);
assert.deepEqual(finished, []);
 
const d11 = new Deferred();
const running11 = running1.run('1.1', d11);
assert.strictEqual(running1, running11);
assert.deepEqual(invoked, ['1']);
assert.deepEqual(finished, []);
 
const d12 = new Deferred();
const running12 = running1.run('1.2', d12);
assert.strictEqual(running1, running12);
assert.deepEqual(invoked, ['1']);
assert.deepEqual(finished, []);
 
d1.resolve();
assert.deepEqual(invoked, ['1']);
assert.deepEqual(finished, []);
 
await next();
assert.deepEqual(invoked, ['1', '1.1']);
assert.deepEqual(finished, ['1']);
 
await next();
assert.deepEqual(invoked, ['1', '1.1']);
assert.deepEqual(finished, ['1']);
 
d12.resolve();
assert.deepEqual(invoked, ['1', '1.1']);
assert.deepEqual(finished, ['1']);
 
await next();
assert.deepEqual(invoked, ['1', '1.1']);
assert.deepEqual(finished, ['1']);
 
d11.resolve();
assert.deepEqual(invoked, ['1', '1.1']);
assert.deepEqual(finished, ['1']);
 
await next();
assert.deepEqual(invoked, ['1', '1.1', '1.2']);
assert.deepEqual(finished, ['1', '1.1', '1.2']);
});
 
test('it handles errors', async function (assert) {
const p = create({
scope: '.root',
 
emptyRun: action({ selector: '.Selector1' }, () => {}),
 
Similar blocks of code found in 2 locations. Consider refactoring.
child: {
scope: '.child',
 
run: action({ selector: '.Selector2' }, function () {
return next().then(() => {
throw new Error('bed time');
});
}),
},
});
 
Similar blocks of code found in 2 locations. Consider refactoring.
return p
.emptyRun()
.child.run(1)
.then(
() => {
assert.true(false);
},
(e) => {
assert.strictEqual(
e.toString(),
`Error: bed time
 
PageObject: 'page.child.run("1")'\n Selector: '.root .child .Selector2'`
);
}
);
});
});
});