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

Query #580

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft

Query #580

Show file tree
Hide file tree
Changes from all 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
92 changes: 53 additions & 39 deletions addon/src/-private/finders.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
import { buildSelector, findClosestValue, guardMultiple } from './helpers';
import { getAdapter } from '../adapters/index';
import { $ } from './jquery';
import { guardMultiple } from './helpers';
import { $ } from './query/selectors/jquery';
import { throwBetterError, ELEMENT_NOT_FOUND } from './better-errors';

function getContainer(pageObjectNode, options) {
return (
options.testContainer ||
findClosestValue(pageObjectNode, 'testContainer') ||
getAdapter().testContainer
);
}
import { Query } from './query';

/**
* Finds a single element, otherwise fails
*
* @private
*/
export function findOne(pageObjectNode, targetSelector, options = {}) {
const selector = buildSelector(pageObjectNode, targetSelector, options);
const container = getContainer(pageObjectNode, options);
export function findOne(pageObjectNode, selector, options = {}) {
const query = new Query(
pageObjectNode,
normalizeOptions({
...options,
selector,
})
);

const elements = $(selector, container).toArray();
const elements = query.all();

guardMultiple(elements, selector);
guardMultiple(elements, query);

if (elements.length === 0) {
throwBetterError(pageObjectNode, options.pageObjectKey, ELEMENT_NOT_FOUND, {
selector,
selector: query.toString(),
});
}

Expand All @@ -38,49 +35,66 @@ export function findOne(pageObjectNode, targetSelector, options = {}) {
*
* @private
*/
export function findMany(pageObjectNode, targetSelector, options = {}) {
const selector = buildSelector(pageObjectNode, targetSelector, options);
const container = getContainer(pageObjectNode, options);
export function findMany(pageObjectNode, selector, options = {}) {
const query = new Query(
pageObjectNode,
normalizeOptions({
...options,
selector,
})
);

return $(selector, container).toArray();
return query.all();
}

/**
* @private
* @deprecated
*/
export function findElementWithAssert(
pageObjectNode,
targetSelector,
options = {}
) {
const selector = buildSelector(pageObjectNode, targetSelector, options);
const container = getContainer(pageObjectNode, options);
export function findElementWithAssert(pageObjectNode, selector, options = {}) {
const query = new Query(
pageObjectNode,
normalizeOptions({
...options,
selector,
})
);

let $elements = $(selector, container);
let elements = query.all();

guardMultiple($elements, selector, options.multiple);
guardMultiple(elements, query, options.multiple);

if ($elements.length === 0) {
if (elements.length === 0) {
throwBetterError(pageObjectNode, options.pageObjectKey, ELEMENT_NOT_FOUND, {
selector,
selector: query.toString(),
});
}

return $elements;
return $(elements);
}

/**
* @private
* @deprecated
*/
export function findElement(pageObjectNode, targetSelector, options = {}) {
const selector = buildSelector(pageObjectNode, targetSelector, options);
const container = getContainer(pageObjectNode, options);
export function findElement(pageObjectNode, selector, options = {}) {
const elements = findMany(pageObjectNode, selector, options);

let $elements = $(selector, container);
return $(elements);
}

function normalizeOptions(options) {
if (options && options.scope) {
// TODO: deprecate options.scope
const selector = [options.scope, options.selector]
.filter(Boolean)
.join(' ');

guardMultiple($elements, selector, options.multiple);
return {
...options,
selector,
};
}

return $elements;
return options;
}
132 changes: 8 additions & 124 deletions addon/src/-private/helpers.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,5 @@
import Ceibo from '@ro0gr/ceibo';
function isPresent(value) {
return typeof value !== 'undefined';
}

class Selector {
constructor(node, scope, selector, filters) {
this.targetNode = node;
this.targetScope = scope || '';
this.targetSelector = selector || '';
this.targetFilters = filters;
}

toString() {
let scope;
let filters;

if (this.targetFilters.resetScope) {
scope = this.targetScope;
} else {
scope = this.calculateScope(this.targetNode, this.targetScope);
}

if (`${scope} ${this.targetSelector}`.indexOf(',') > -1) {
throw new Error(
'Usage of comma separated selectors is not supported. Please make sure your selector targets a single selector.'
);
}

filters = this.calculateFilters(this.targetFilters);

let selector = `${scope} ${this.targetSelector}${filters}`.trim();

if (!selector.length) {
// When an empty selector is resolved take the first direct child of the
// testing container.
selector = ':first';
}

return selector;
}

calculateFilters() {
let filters = [];

if (this.targetFilters.visible) {
filters.push(`:visible`);
}

if (this.targetFilters.contains) {
filters.push(`:contains("${this.targetFilters.contains}")`);
}

if (typeof this.targetFilters.at === 'number') {
filters.push(`:eq(${this.targetFilters.at})`);
} else if (this.targetFilters.last) {
filters.push(':last');
}

return filters.join('');
}

calculateScope(node, targetScope) {
let scopes = this.getScopes(node);

scopes.reverse();
scopes.push(targetScope);

return scopes.join(' ').trim();
}

getScopes(node) {
let scopes = [];

if (node.scope) {
scopes.push(node.scope);
}

if (!node.resetScope && Ceibo.parent(node)) {
scopes = scopes.concat(this.calculateScope(Ceibo.parent(node)));
}

return scopes;
}
}
import { Query } from './query';

export function guardMultiple(items, selector, supportMultiple) {
if (items.length > 1 && !supportMultiple) {
Expand Down Expand Up @@ -136,7 +53,11 @@ export function guardMultiple(items, selector, supportMultiple) {
* @return {string} Fully qualified selector
*/
export function buildSelector(node, targetSelector, options) {
return new Selector(node, options.scope, targetSelector, options).toString();
return new Query(
node,
[options.scope, targetSelector].filter(Boolean).join(' '),
options
).toString();
}

/**
Expand All @@ -159,21 +80,6 @@ export function getRoot(node) {
return root;
}

function getAllValuesForProperty(node, property) {
let iterator = node;
let values = [];

while (isPresent(iterator)) {
if (isPresent(iterator[property])) {
values.push(iterator[property]);
}

iterator = Ceibo.parent(iterator);
}

return values;
}

/**
* @public
*
Expand All @@ -183,31 +89,9 @@ function getAllValuesForProperty(node, property) {
* @return {string} Full scope of node
*/
export function fullScope(node) {
let scopes = getAllValuesForProperty(node, 'scope');

return scopes.reverse().join(' ');
}
const q = new Query(node);

/**
* @public
*
* Returns the value of property defined on the closest ancestor of given
* node.
*
* @param {Ceibo} node - Node of the tree
* @param {string} property - Property to look for
* @return {?Object} The value of property on closest node to the given node
*/
export function findClosestValue(node, property) {
if (isPresent(node[property])) {
return node[property];
}

let parent = Ceibo.parent(node);

if (isPresent(parent)) {
return findClosestValue(parent, property);
}
return q.toString();
}

export function assignDescriptors(target, source) {
Expand Down
12 changes: 0 additions & 12 deletions addon/src/-private/jquery.js

This file was deleted.

Loading
Loading