Skip to content

Commit

Permalink
Query
Browse files Browse the repository at this point in the history
use Query directly in finders in order to get rid of build selector
  • Loading branch information
ro0gr committed Feb 4, 2024
1 parent 0a398c3 commit 8e53e1d
Show file tree
Hide file tree
Showing 18 changed files with 3,984 additions and 2,958 deletions.
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

0 comments on commit 8e53e1d

Please sign in to comment.