ember-cli-page-object
Advanced tools
Comparing version 0.11.1 to 1.0.0-alpha.1
@@ -17,3 +17,5 @@ /*jshint node:true*/ | ||
app.import(app.bowerDirectory + '/ceibo/index.js'); | ||
return app.toTree(); | ||
}; |
10
index.js
@@ -5,3 +5,11 @@ /* jshint node: true */ | ||
module.exports = { | ||
name: 'ember-cli-page-object' | ||
name: 'ember-cli-page-object', | ||
included: function(app) { | ||
this._super.included(app); | ||
if (app.env === 'test') { | ||
app.import(app.bowerDirectory + '/ceibo/index.js'); | ||
} | ||
} | ||
}; |
{ | ||
"name": "ember-cli-page-object", | ||
"version": "0.11.1", | ||
"version": "1.0.0-alpha.1", | ||
"description": "This ember-cli addon eases the construction of page objects on your acceptance tests", | ||
@@ -13,2 +13,3 @@ "homepage": "http://ember-cli-page-object.js.org", | ||
"build": "ember build", | ||
"preversion": "git clean -df && npm test", | ||
"start": "ember server", | ||
@@ -15,0 +16,0 @@ "test": "ember try:testall" |
@@ -29,37 +29,8 @@ # Ember Page Objects | ||
## Usage | ||
## Installation | ||
Install the npm package on your ember-cli project | ||
```sh | ||
npm install --save-dev ember-cli-page-object | ||
ember install ember-cli-page-object | ||
``` | ||
then you can use it from your acceptance tests | ||
```js | ||
import PageObject from '../page-object'; | ||
const { fillable, text, visitable } = PageObject; | ||
const login = PageObject.create({ | ||
visit: visitable('/login'), | ||
userName: fillable('#username'), | ||
password: fillable('#password'), | ||
errorMessage: text('.message') | ||
}); | ||
test('Invalid log in', function(assert) { | ||
login | ||
.visit() | ||
.userName('user@example.com') | ||
.password('secret') | ||
.clickOn('Log in'); | ||
andThen(function() { | ||
assert.equal(login.errorMessage(), 'Invalid credentials!'); | ||
}); | ||
}); | ||
``` | ||
## Blueprints | ||
@@ -82,18 +53,2 @@ | ||
```js | ||
import { test } from 'qunit'; | ||
import moduleForAcceptance from '../helpers/module-for-acceptance'; | ||
import page from '../pages/users'; | ||
moduleForAcceptance(); | ||
test('visiting /users', function(assert) { | ||
page.visit(); | ||
andThen(function() { | ||
assert.equal(currentPath(), 'users'); | ||
}); | ||
}); | ||
``` | ||
## Development | ||
@@ -103,11 +58,9 @@ | ||
* `git clone` this repository | ||
* `npm install` | ||
* `bower install` | ||
```sh | ||
$ git clone https://github.com/san650/ember-cli-page-object.git | ||
$ cd $_ | ||
$ npm install | ||
$ bower install | ||
``` | ||
### Running | ||
* `ember server` | ||
* Visit your app at http://localhost:4200. | ||
### Running Tests | ||
@@ -119,6 +72,2 @@ | ||
### Building | ||
* `ember build` | ||
### Project's health | ||
@@ -125,0 +74,0 @@ |
@@ -1,32 +0,41 @@ | ||
import { | ||
build, | ||
create | ||
} from './page-object/create'; | ||
import { collection } from './page-object/collection'; | ||
import attribute from './page-object/properties/attribute'; | ||
import clickOnText from './page-object/properties/click-on-text'; | ||
import clickable from './page-object/properties/clickable'; | ||
import component from './page-object/properties/component'; | ||
import count from './page-object/properties/count'; | ||
import customHelper from './page-object/properties/custom-helper'; | ||
import fillable from './page-object/properties/fillable'; | ||
import hasClass from './page-object/properties/has-class'; | ||
import isHidden from './page-object/properties/is-hidden'; | ||
import isVisible from './page-object/properties/is-visible'; | ||
import notHasClass from './page-object/properties/not-has-class'; | ||
import text from './page-object/properties/text'; | ||
import textList from './page-object/properties/text-list'; | ||
import value from './page-object/properties/value'; | ||
import visitable from './page-object/properties/visitable'; | ||
import { attribute } from './page-object/properties/attribute'; | ||
import { clickOnText } from './page-object/properties/click-on-text'; | ||
import { clickable } from './page-object/properties/clickable'; | ||
import { collection } from './page-object/properties/collection'; | ||
import { contains } from './page-object/properties/contains'; | ||
import { count } from './page-object/properties/count'; | ||
import { create } from './page-object/create'; | ||
import { fillable } from './page-object/properties/fillable'; | ||
import { hasClass } from './page-object/properties/has-class'; | ||
import { isHidden } from './page-object/properties/is-hidden'; | ||
import { isVisible } from './page-object/properties/is-visible'; | ||
import { notHasClass } from './page-object/properties/not-has-class'; | ||
import { text } from './page-object/properties/text'; | ||
import { value } from './page-object/properties/value'; | ||
import { visitable } from './page-object/properties/visitable'; | ||
export { attribute } from './page-object/properties/attribute'; | ||
export { clickOnText } from './page-object/properties/click-on-text'; | ||
export { clickable } from './page-object/properties/clickable'; | ||
export { collection } from './page-object/properties/collection'; | ||
export { contains } from './page-object/properties/contains'; | ||
export { count } from './page-object/properties/count'; | ||
export { create } from './page-object/create'; | ||
export { fillable, fillable as selectable } from './page-object/properties/fillable'; | ||
export { hasClass } from './page-object/properties/has-class'; | ||
export { isHidden } from './page-object/properties/is-hidden'; | ||
export { isVisible } from './page-object/properties/is-visible'; | ||
export { notHasClass } from './page-object/properties/not-has-class'; | ||
export { text } from './page-object/properties/text'; | ||
export { value } from './page-object/properties/value'; | ||
export { visitable } from './page-object/properties/visitable'; | ||
export default { | ||
attribute, | ||
build, | ||
clickOnText, | ||
clickable, | ||
collection, | ||
component, | ||
contains, | ||
count, | ||
create, | ||
customHelper, | ||
fillable, | ||
@@ -39,5 +48,4 @@ hasClass, | ||
text, | ||
textList, | ||
value, | ||
visitable | ||
}; |
@@ -1,147 +0,75 @@ | ||
/* global wait */ | ||
import Ember from 'ember'; | ||
import isHidden from './properties/is-hidden'; | ||
import isVisible from './properties/is-visible'; | ||
import clickOnText from './properties/click-on-text'; | ||
import clickable from './properties/clickable'; | ||
import contains from './properties/contains'; | ||
import text from './properties/text'; | ||
import Ceibo from 'ceibo'; | ||
import { text } from './properties/text'; | ||
import { isVisible } from './properties/is-visible'; | ||
import { isHidden } from './properties/is-hidden'; | ||
import { clickOnText } from './properties/click-on-text'; | ||
import { clickable } from './properties/clickable'; | ||
import { contains } from './properties/contains'; | ||
function Node() { | ||
this.isHidden = isHidden().propertyFor(this, 'isHidden'); | ||
this.isVisible = isVisible().propertyFor(this, 'isVisible'); | ||
this.clickOn = clickOnText().propertyFor(this, 'clickOn'); | ||
this.click = clickable().propertyFor(this, 'click'); | ||
this.contains = contains().propertyFor(this, 'contains'); | ||
this.text = text().propertyFor(this, 'text'); | ||
} | ||
var { merge } = Ember; | ||
Node.prototype.then = function() { | ||
return wait().then(...arguments); | ||
}; | ||
function plugDefaultProperties(definition) { | ||
if (typeof(definition.isVisible) === 'undefined') { | ||
definition.isVisible = isVisible(); | ||
} | ||
Node.prototype.toFunction = function() { | ||
let tmp = buildPageObject(this); | ||
if (typeof(definition.isHidden) === 'undefined') { | ||
definition.isHidden = isHidden(); | ||
} | ||
return function() { | ||
return tmp; | ||
}; | ||
}; | ||
if (typeof(definition.clickOn) === 'undefined') { | ||
definition.clickOn = clickOnText(); | ||
} | ||
/** | ||
* Converts properties of type `component` to plain objects (`component` is | ||
* mantained for backwards compatibility) | ||
* | ||
* @param [Object] definition - The definition to pre-process | ||
* @return [Object] A new pre-processed representation of definition | ||
*/ | ||
function preProcess(definition) { | ||
let node = {}, | ||
keys = Object.keys(definition); | ||
if (typeof(definition.click) === 'undefined') { | ||
definition.click = clickable(); | ||
} | ||
keys.forEach(function(key) { | ||
let attr = definition[key]; | ||
if (typeof(definition.contains) === 'undefined') { | ||
definition.contains = contains(); | ||
} | ||
if (attr && attr.unfoldPageObjectDefinition) { | ||
attr = attr.unfoldPageObjectDefinition(); | ||
} | ||
if ($.isPlainObject(attr)) { | ||
node[key] = preProcess(attr); | ||
} else { | ||
node[key] = attr; | ||
} | ||
}); | ||
return node; | ||
if (typeof(definition.text) === 'undefined') { | ||
definition.text = text(); | ||
} | ||
} | ||
function setScopes(definition) { | ||
let keys = Object.keys(definition); | ||
keys.forEach(function(key) { | ||
let attr = definition[key]; | ||
if ($.isPlainObject(attr)) { | ||
if (definition.__forceScopeToChildren) { | ||
attr.scope = [definition.scope, attr.scope].join(' '); | ||
} else if (typeof(attr.scope) === 'undefined' && typeof(definition.scope) !== 'undefined') { | ||
attr.scope = definition.scope; | ||
} | ||
setScopes(attr); | ||
} | ||
}); | ||
return definition; | ||
} | ||
/** | ||
* Creates a tree of `Node`s and `Property`s | ||
* | ||
* @param [Object] definition - The definition of the page object | ||
* @return [Node] A new tree representation of the page object | ||
* See https://github.com/san650/ceibo#examples for more info on how Ceibo | ||
* builders work. | ||
*/ | ||
function buildTree(definition) { | ||
let keys = Object.keys(definition), | ||
root = new Node(); | ||
function buildObject(builder, target, key, definition) { | ||
var container = {}; | ||
keys.forEach(function(key) { | ||
let attr = definition[key]; | ||
plugDefaultProperties(definition); | ||
if (typeof attr === 'undefined') { | ||
// continue | ||
} else if (attr.propertyFor) { | ||
root[key] = attr.propertyFor(root, key); | ||
} else if ($.isPlainObject(attr)) { | ||
root[key] = buildTree(attr); | ||
} else { | ||
root[key] = attr; | ||
} | ||
}); | ||
// Create child component | ||
Ceibo.defineProperty(target, key, container); | ||
return root; | ||
// Recursion | ||
builder.processNode(definition, container, target); | ||
} | ||
/** | ||
* Makes everything invokable (toFunction) but keeps a reference to the tree | ||
* structure to allow instrospection. | ||
* Creates a new PageObject | ||
* | ||
* @param [Node] definition - The page object definition | ||
* @return [Node] The representation of the page object | ||
* @example | ||
* | ||
* var page = PageObject.create({ | ||
* title: text('.title') | ||
* }); | ||
* | ||
* assert.equal(page.title, 'Dummy title'); | ||
* | ||
* @param {Object} definition - PageObject definition | ||
* @param {Object} options - [private] Ceibo options. Do not use! | ||
* @return {PageObject} | ||
*/ | ||
function buildPageObject(definition) { | ||
let keys = Object.keys(definition); | ||
export function create(definition, options = {}) { | ||
var builder = { | ||
object: buildObject | ||
}; | ||
keys.forEach(function(key) { | ||
let attr = definition[key]; | ||
if (typeof attr === 'undefined') { | ||
// continue | ||
} else if (attr.toFunction) { | ||
definition[key] = attr.toFunction(); | ||
} else { | ||
definition[key] = attr; | ||
} | ||
}); | ||
return definition; | ||
return Ceibo.create(definition, merge({ builder }, options )); | ||
} | ||
export function create(definition) { | ||
let copy; | ||
copy = preProcess(definition); | ||
copy = setScopes(copy); | ||
copy = buildTree(copy); | ||
copy = buildPageObject(copy); | ||
return copy; | ||
} | ||
export function build(definition) { | ||
Ember.deprecate('`build` is deprecated in favor of `create`.'); | ||
return create(definition); | ||
} |
import Ember from 'ember'; | ||
import Ceibo from 'ceibo'; | ||
export function qualifySelector(...selectors) { | ||
return selectors.filter(item => !!item).join(' '); | ||
var { $, assert } = Ember; | ||
class Selector { | ||
constructor(node, scope, selector, filters) { | ||
this.targetNode = node; | ||
this.targetScope = scope || ''; | ||
this.targetSelector = selector || ''; | ||
this.targetFilters = filters; | ||
} | ||
toString() { | ||
var scope, | ||
filters; | ||
if (this.targetFilters.resetScope) { | ||
scope = this.targetScope; | ||
} else { | ||
scope = this.calculateScope(this.targetNode, this.targetScope); | ||
} | ||
filters = this.calculateFilters(this.targetFilters); | ||
return $.trim(`${scope} ${this.targetSelector}${filters}`); | ||
} | ||
calculateFilters() { | ||
var filters = []; | ||
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) { | ||
var scopes = this.getScopes(node); | ||
scopes.reverse(); | ||
scopes.push(targetScope); | ||
return $.trim(scopes.join(' ')); | ||
} | ||
getScopes(node) { | ||
var scopes = []; | ||
if (node.scope) { | ||
scopes.push(node.scope); | ||
} | ||
if (!node.resetScope && Ceibo.parent(node)) { | ||
scopes = scopes.concat(this.calculateScope(Ceibo.parent(node))); | ||
} | ||
return scopes; | ||
} | ||
} | ||
export function findElementWithAssert(options, target) { | ||
let selector = qualifySelector( | ||
options.scope || target.scope, | ||
indexedSelector(options.selector, options.index) | ||
); | ||
function guardMultiple(items, selector, supportMultiple) { | ||
assert( | ||
`"${selector}" matched more than one element. If this is not an error use { multiple: true }`, | ||
supportMultiple || items.length <= 1 | ||
) | ||
} | ||
/* global findWithAssert */ | ||
return findWithAssert(selector); | ||
/** | ||
* Creates a fully qualified selector | ||
* | ||
* @param {Ceibo} node - Node of the tree | ||
* @param {string} targetSelector - Specific CSS selector | ||
* @param {Object} options - Additional options | ||
* @param {boolean} options.resetScope - Do not use inherited scope | ||
* @param {string} options.contains - Filter by using :contains('foo') pseudo-class | ||
* @param {number} options.at - Filter by index using :eq(x) pseudo-class | ||
* @param {boolean} options.last - Filter by using :last pseudo-class | ||
* @return {string} Full qualified selector | ||
*/ | ||
export function buildSelector(node, targetSelector, options) { | ||
return (new Selector(node, options.scope, targetSelector, options)).toString(); | ||
} | ||
export function findElement(options, target) { | ||
let selector = qualifySelector( | ||
options.scope || target.scope, | ||
indexedSelector(options.selector, options.index) | ||
); | ||
/** | ||
* Return a jQuery element or raise an exception if the element doesn't exist | ||
* | ||
* @param {Ceibo} node - Node of the tree | ||
* @param {string} targetSelector - Specific CSS selector | ||
* @param {Object} options - Additional options | ||
* @param {boolean} options.resetScope - Do not use inherited scope | ||
* @param {string} options.contains - Filter by using :contains('foo') pseudo-class | ||
* @param {number} options.at - Filter by index using :eq(x) pseudo-class | ||
* @param {boolean} options.last - Filter by using :last pseudo-class | ||
* @return {Object} jQuery object | ||
*/ | ||
export function findElementWithAssert(node, targetSelector, options = {}) { | ||
var selector = buildSelector(node, targetSelector, options); | ||
var result = findWithAssert(selector); | ||
/* global find */ | ||
return find(selector); | ||
guardMultiple(result, selector, options.multiple); | ||
return result; | ||
} | ||
/** | ||
* Return a jQuery element (can be an empty jQuery result) | ||
* | ||
* @param {Ceibo} node - Node of the tree | ||
* @param {string} targetSelector - Specific CSS selector | ||
* @param {Object} options - Additional options | ||
* @param {boolean} options.resetScope - Do not use inherited scope | ||
* @param {string} options.contains - Filter by using :contains('foo') pseudo-class | ||
* @param {number} options.at - Filter by index using :eq(x) pseudo-class | ||
* @param {boolean} options.last - Filter by using :last pseudo-class | ||
* @return {Object} jQuery object | ||
*/ | ||
export function findElement(node, targetSelector, options = {}) { | ||
var selector = buildSelector(node, targetSelector, options); | ||
var result = find(selector); | ||
guardMultiple(result, selector, options.multiple); | ||
return result; | ||
} | ||
/** | ||
* Trim whitespaces at both ends and normalize whitespaces inside `text` | ||
@@ -35,16 +142,20 @@ * | ||
*/ | ||
export function trim(text) { | ||
return Ember.$.trim(text).replace(/\n/g, ' ').replace(/\s\s*/g, ' '); | ||
export function normalizeText(text) { | ||
return $.trim(text).replace(/\n/g, ' ').replace(/\s\s*/g, ' '); | ||
} | ||
export function indexedSelector(baseSelector, index) { | ||
let selector; | ||
export function every(jqArray, cb) { | ||
var arr = jqArray.get(); | ||
if ($.isNumeric(index) && index > 0) { | ||
selector = `${baseSelector}:eq(${index - 1})`; | ||
} else { | ||
selector = baseSelector; | ||
} | ||
return Ember.A(arr).every(function(element) { | ||
return cb($(element)); | ||
}); | ||
} | ||
return selector; | ||
export function map(jqArray, cb) { | ||
var arr = jqArray.get(); | ||
return Ember.A(arr).map(function(element) { | ||
return cb($(element)); | ||
}); | ||
} |
@@ -1,3 +0,2 @@ | ||
import Descriptor from '../descriptor'; | ||
import { findElementWithAssert } from '../helpers'; | ||
import { findElementWithAssert, map } from '../helpers'; | ||
@@ -7,20 +6,2 @@ /** | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} selector - CSS selector of the element to check | ||
* @param {string} options.attributeName - Name of the attribute to get | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @return {string} value of the attribute | ||
*/ | ||
function getAttribute(target, key, options) { | ||
let element = findElementWithAssert(options, target); | ||
return element.attr(options.attributeName); | ||
} | ||
/** | ||
* Creates a predicate to get an attribute of an element | ||
* | ||
* @example | ||
@@ -32,3 +13,3 @@ * | ||
* | ||
* assert.equal(page.imageAlternateText(), 'Logo'); | ||
* assert.equal(page.imageAlternateText, 'Logo'); | ||
* | ||
@@ -39,10 +20,21 @@ * @param {string} attributeName - Name of the attribute to get | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index | ||
* @param {boolean} options.multiple - Return an array of values | ||
* @return {Descriptor} | ||
*/ | ||
export default function attribute(attributeName, selector, options = {}) { | ||
options.attributeName = attributeName; | ||
options.selector = selector; | ||
export function attribute(attributeName, selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(getAttribute, options); | ||
get() { | ||
var elements = findElementWithAssert(this, selector, options); | ||
var result; | ||
result = map(elements, function(element) { | ||
return element.attr(attributeName); | ||
}); | ||
return options.multiple ? result : result[0]; | ||
} | ||
}; | ||
} |
@@ -1,30 +0,24 @@ | ||
/* global click */ | ||
import Ember from 'ember'; | ||
import { buildSelector } from '../helpers'; | ||
import Descriptor from '../descriptor'; | ||
import { qualifySelector } from '../helpers'; | ||
/* global wait, find, click */ | ||
/** | ||
* Clicks an element by text | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} options.selector - CSS selector of the container of the element to click | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {string} textToClick - Text to find the element to click | ||
* @return {Object} target component (this allows chaining) | ||
*/ | ||
function doClick(target, key, options, textToClick) { | ||
var { merge } = Ember; | ||
function findChildElement(tree, selector, textToClick, options) { | ||
// Suppose that we have something like `<form><button>Submit</button></form>` | ||
// In this case <form> and <button> elements contains "Submit" text, so, we'll | ||
// want to __always__ click on the __last__ element that contains the text. | ||
let selector = qualifySelector( | ||
options.scope || target.scope, | ||
options.selector, | ||
`:contains("${textToClick}"):last` | ||
); | ||
var selctorWithSpace = (selector || '') + ' '; | ||
var fullSelector = buildSelector(tree, selctorWithSpace, merge({ contains: textToClick, last: true }, options)); | ||
click(selector); | ||
if (find(fullSelector).length) { | ||
return fullSelector; | ||
} | ||
} | ||
return target; | ||
function findElement(tree, selector, textToClick, options) { | ||
var fullSelector = buildSelector(tree, selector, merge({ contains: textToClick }, options)); | ||
return fullSelector; | ||
} | ||
@@ -38,6 +32,6 @@ | ||
* var page = PageObject.create({ | ||
* click: clickOnText('button[type=submit]') | ||
* clickOn: clickOnText('body') | ||
* }); | ||
* | ||
* page.click('Save'); | ||
* page.clickOn('Save'); | ||
* | ||
@@ -47,8 +41,19 @@ * @param {string} selector - CSS selector of the element to click | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index | ||
* @return {Descriptor} | ||
*/ | ||
export default function clickOnText(selector, options = {}) { | ||
options.selector = selector; | ||
export function clickOnText(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doClick, options); | ||
value(textToClick) { | ||
wait().then(() => { | ||
var actualSelector = findChildElement(this, selector, textToClick, options) || findElement(this, selector, textToClick, options); | ||
click(actualSelector); | ||
}); | ||
return this; | ||
} | ||
}; | ||
} |
@@ -1,25 +0,4 @@ | ||
/* global click */ | ||
import { buildSelector } from '../helpers'; | ||
import Descriptor from '../descriptor'; | ||
import { qualifySelector } from '../helpers'; | ||
/** | ||
* Clicks an element | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} options.selector - CSS selector of the element to click | ||
* @param {string} options.scope - Overrides parent scope | ||
* @return {Object} target component (this allows chaining) | ||
*/ | ||
function doClick(target, key, options) { | ||
let selector = qualifySelector(options.scope || target.scope, options.selector); | ||
click(selector); | ||
return target; | ||
} | ||
/** | ||
* Creates an action to click an element | ||
@@ -38,8 +17,17 @@ * | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index | ||
* @param {boolean} options.resetScope - Ignore parent scope | ||
* @return {Descriptor} | ||
*/ | ||
export default function clickable(selector, options = {}) { | ||
options.selector = selector; | ||
export function clickable(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doClick, options); | ||
value() { | ||
/* global click */ | ||
click(buildSelector(this, selector, options)); | ||
return this; | ||
} | ||
}; | ||
} |
@@ -1,23 +0,4 @@ | ||
import Descriptor from '../descriptor'; | ||
import { findElementWithAssert } from '../helpers'; | ||
import { findElementWithAssert, every } from '../helpers'; | ||
/** | ||
* Checks if an element has a subtext | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} options.selector - CSS selector of the element to check | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @param {number} textToSearch - Text to search | ||
* @return {Boolean} true if the element has a subtext | ||
*/ | ||
function doContains(target, key, options, textToSearch) { | ||
let element = findElementWithAssert(options, target); | ||
return element.text().indexOf(textToSearch) >= 0; | ||
} | ||
/** | ||
* Creates a predicate to validate if an element contains a subtext | ||
@@ -40,6 +21,14 @@ * | ||
*/ | ||
export default function contains(selector, options = {}) { | ||
options.selector = selector; | ||
export function contains(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doContains, options); | ||
value(textToSearch) { | ||
let elements = findElementWithAssert(this, selector, options); | ||
return every(elements, function(element) { | ||
return element.text().indexOf(textToSearch) >= 0 | ||
}); | ||
} | ||
}; | ||
} |
@@ -1,24 +0,9 @@ | ||
import Descriptor from '../descriptor'; | ||
import Ember from 'ember'; | ||
import { findElement } from '../helpers'; | ||
var $ = Ember.$; | ||
/** | ||
* Gets the count of matched elements | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} selector - CSS selector of the element to check | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @return {string} value of the attribute | ||
*/ | ||
function getCount(target, key, options) { | ||
let element = findElement(options, target); | ||
return element.length; | ||
} | ||
/** | ||
* Creates a predicate to get the count of matched elements | ||
* | ||
* @example | ||
@@ -34,10 +19,18 @@ * | ||
* @param {Object} options - Additional options | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @param {string} options.scope - Add scope | ||
* @param {boolean} options.resetScope - Ignore parent scope | ||
* @return {Descriptor} | ||
*/ | ||
export default function count(selector, options = {}) { | ||
options.selector = selector; | ||
export function count(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(getCount, options); | ||
get() { | ||
let countOptions = {}; | ||
$.extend(true, countOptions, options, { multiple: true }); | ||
return findElement(this, selector, countOptions).length; | ||
} | ||
}; | ||
} |
@@ -1,26 +0,4 @@ | ||
/* global fillIn */ | ||
import { buildSelector } from '../helpers'; | ||
import Descriptor from '../descriptor'; | ||
import { qualifySelector } from '../helpers'; | ||
/** | ||
* Fills in an input | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} options.selector - CSS selector of the element to fill | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {string} textToUse - Text to use to fill the input | ||
* @return {Object} target component (this allows chaining) | ||
*/ | ||
function doFillIn(target, key, options, textToUse) { | ||
let selector = qualifySelector(options.scope || target.scope, options.selector); | ||
fillIn(selector, textToUse); | ||
return target; | ||
} | ||
/** | ||
* Creates an action to fill in an input | ||
@@ -39,8 +17,17 @@ * | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index | ||
* @param {boolean} options.resetScope - Ignore parent scope | ||
* @return {Descriptor} | ||
*/ | ||
export default function fillable(selector, options = {}) { | ||
options.selector = selector; | ||
export function fillable(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doFillIn, options); | ||
value(textToUse) { | ||
/* global fillIn */ | ||
fillIn(buildSelector(this, selector, options), textToUse); | ||
return this; | ||
} | ||
} | ||
} |
@@ -1,23 +0,4 @@ | ||
import Descriptor from '../descriptor'; | ||
import { findElementWithAssert } from '../helpers'; | ||
import { findElementWithAssert, every } from '../helpers'; | ||
/** | ||
* Checks if an element has the CSS class name | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} selector - CSS selector of the element to check | ||
* @param {string} options.cssClass - Name of the CSS class to look for | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @return {Boolean} true if the element has the CSS class | ||
*/ | ||
function doHasClass(target, key, options) { | ||
let element = findElementWithAssert(options, target); | ||
return element.hasClass(options.cssClass); | ||
} | ||
/** | ||
* Creates a predicate to validate if an element has a given CSS class | ||
@@ -40,7 +21,14 @@ * | ||
*/ | ||
export default function hasClass(cssClass, selector, options = {}) { | ||
options.cssClass = cssClass; | ||
options.selector = selector; | ||
export function hasClass(cssClass, selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doHasClass, options); | ||
get() { | ||
let elements = findElementWithAssert(this, selector, options); | ||
return every(elements, function(element) { | ||
return element.hasClass(cssClass); | ||
}); | ||
} | ||
}; | ||
} |
@@ -1,22 +0,4 @@ |
import Descriptor from '../descriptor'; |
import { findElement } from '../helpers'; |
import { findElement, every } from '../helpers'; |
/** |
* Checks if an element is hidden |
* |
* @param {Object} target - Component that owns the property |
* @param {string} key - Name of the key associated to this property |
* @param {Object} options - Additional options |
* @param {string} selector - CSS selector of the element to check |
* @param {string} options.scope - Overrides parent scope |
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index |
* @return {Boolean} true if the element is hidden |
*/ |
function doIsHidden(target, key, options) { |
let element = findElement(options, target); |
return (element.length > 0) ? element.is(':hidden') : true; |
} |
/** |
* Creates a predicate to validate if an element is hidden |
@@ -35,9 +17,17 @@ * |
* @param {string} options.scope - Overrides parent scope |
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index |
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index |
* @return {Descriptor} |
*/ |
export default function isHidden(selector, options = {}) { |
options.selector = selector; |
export function isHidden(selector, options = {}) { |
return { |
isDescriptor: true, |
return new Descriptor(doIsHidden, options); |
get() { |
let elements = findElement(this, selector, options); |
return every(elements, function(element) { |
return element.is(':hidden'); |
}); |
} |
}; |
} |
@@ -1,22 +0,4 @@ | ||
import Descriptor from '../descriptor'; | ||
import { findElementWithAssert } from '../helpers'; | ||
import { findElement, every } from '../helpers'; | ||
/** | ||
* Checks if an element is visible | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} selector - CSS selector of the element to check | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @return {Boolean} true if the element is visible | ||
*/ | ||
function doIsVisible(target, key, options) { | ||
let element = findElementWithAssert(options, target); | ||
return element.is(':visible'); | ||
} | ||
/** | ||
* Creates a predicate to validate if an element is visible | ||
@@ -35,9 +17,21 @@ * | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index | ||
* @return {Descriptor} | ||
*/ | ||
export default function isVisible(selector, options = {}) { | ||
options.selector = selector; | ||
export function isVisible(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doIsVisible, options); | ||
get() { | ||
let elements = findElement(this, selector, options); | ||
if (elements.length === 0) { | ||
return false; | ||
} | ||
return every(elements, function(element) { | ||
return element.is(':visible'); | ||
}); | ||
} | ||
}; | ||
} |
@@ -1,23 +0,4 @@ | ||
import Descriptor from '../descriptor'; | ||
import { findElementWithAssert } from '../helpers'; | ||
import { findElementWithAssert, every } from '../helpers'; | ||
/** | ||
* Checks if an element doesn't have the CSS class name | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} options.selector - CSS selector of the container of the element to click | ||
* @param {string} options.cssClass - Name of the CSS class to look for | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @return {Boolean} true if the element doesn't have the CSS class | ||
*/ | ||
function doNotHasClass(target, key, options) { | ||
let element = findElementWithAssert(options, target); | ||
return !element.hasClass(options.cssClass); | ||
} | ||
/** | ||
* Creates a predicate to validate if an element doesn't have a given CSS class | ||
@@ -40,7 +21,14 @@ * | ||
*/ | ||
export default function notHasClass(cssClass, selector, options = {}) { | ||
options.cssClass = cssClass; | ||
options.selector = selector; | ||
export function notHasClass(cssClass, selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doNotHasClass, options); | ||
get() { | ||
var elements = findElementWithAssert(this, selector, options); | ||
return every(elements, function(element) { | ||
return !element.hasClass(cssClass); | ||
}); | ||
} | ||
}; | ||
} |
@@ -1,3 +0,2 @@ | ||
import Descriptor from '../descriptor'; | ||
import { findElementWithAssert, trim } from '../helpers'; | ||
import { findElementWithAssert, map, normalizeText } from '../helpers'; | ||
@@ -7,19 +6,2 @@ /** | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} selector - CSS selector of the element to check | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @return {string} value of the attribute | ||
*/ | ||
function getText(target, key, options) { | ||
let element = findElementWithAssert(options, target); | ||
return trim(element.text()); | ||
} | ||
/** | ||
* Creates a predicate to get the text of the matched element | ||
* | ||
* @example | ||
@@ -31,14 +13,33 @@ * | ||
* | ||
* assert.equal(page.title(), 'Page title'); | ||
* assert.equal(page.title, 'Page title'); | ||
* | ||
* var page = PageObject.create({ | ||
* options: text('li', { multiple: true }) | ||
* }); | ||
* | ||
* assert.deepEqual(page.options, ['lorem', 'ipsum']) | ||
* | ||
* @param {string} selector - CSS selector of the element to check | ||
* @param {Object} options - Additional options | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index | ||
* @param {boolean} options.resetScope - Ignore parent scope | ||
* @param {boolean} options.multiple - Return an array of values | ||
* @return {Descriptor} | ||
*/ | ||
export default function text(selector, options = {}) { | ||
options.selector = selector; | ||
export function text(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(getText, options); | ||
get() { | ||
var elements = findElementWithAssert(this, selector, options); | ||
var result; | ||
result = map(elements, function(element) { | ||
return normalizeText(element.text()); | ||
}); | ||
return options.multiple ? result : result[0]; | ||
} | ||
}; | ||
} |
@@ -1,3 +0,2 @@ | ||
import Descriptor from '../descriptor'; | ||
import { findElementWithAssert, trim } from '../helpers'; | ||
import { findElementWithAssert, map } from '../helpers'; | ||
@@ -7,26 +6,9 @@ /** | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {string} selector - CSS selector of the element to check | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @return {string} value of the element | ||
*/ | ||
function getValue(target, key, options) { | ||
let element = findElementWithAssert(options, target); | ||
return trim(element.val()); | ||
} | ||
/** | ||
* Creates a predicate to get the value of the matched element | ||
* | ||
* @example | ||
* | ||
* var page = PageObject.create({ | ||
* name: value('#name') | ||
* search: value('input') | ||
* }); | ||
* | ||
* assert.equal(page.name(), 'John Doe'); | ||
* assert.equal(page.search, 'search term'); | ||
* | ||
@@ -36,9 +18,21 @@ * @param {string} selector - CSS selector of the element to check | ||
* @param {string} options.scope - Overrides parent scope | ||
* @param {number} options.index - Reduce the set of matched elements to the one at the specified index | ||
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index | ||
* @param {boolean} options.resetScope - Ignore parent scope | ||
* @return {Descriptor} | ||
*/ | ||
export default function value(selector, options = {}) { | ||
options.selector = selector; | ||
export function value(selector, options = {}) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(getValue, options); | ||
get() { | ||
var elements = findElementWithAssert(this, selector, options); | ||
var result; | ||
result = map(elements, function(element) { | ||
return element.val(); | ||
}); | ||
return options.multiple ? result : result[0]; | ||
} | ||
}; | ||
} |
@@ -1,6 +0,5 @@ | ||
/* global visit */ | ||
import Ember from 'ember'; | ||
import Descriptor from '../descriptor'; | ||
var { merge, $ } = Ember; | ||
function fillInDynamicSegments(path, params) { | ||
@@ -11,9 +10,13 @@ return path.split('/').map(function(segment) { | ||
if (match) { | ||
let key = match[1]; | ||
let key = match[1], | ||
value = params[key]; | ||
if (!params[key]) { | ||
if (typeof value === 'undefined') { | ||
throw new Error(`Missing parameter for '${key}'`); | ||
} | ||
return params[key]; | ||
// Remove dynamic segment key from params | ||
delete params[key]; | ||
return value; | ||
} | ||
@@ -25,30 +28,12 @@ | ||
/** | ||
* Loads a path | ||
* | ||
* @param {Object} target - Component that owns the property | ||
* @param {string} key - Name of the key associated to this property | ||
* @param {Object} options - Additional options | ||
* @param {Object} params - Key and values to use to replace the dynamic segments | ||
* @param {Object} queryParams - Key and values to use as the Query Params | ||
* @return {Object} target component (this allows chaining) | ||
*/ | ||
function doVisit(target, key, options, params = {}, queryParams = {}) { | ||
let path = options.path; | ||
if (path.indexOf(':') !== -1) { | ||
path = fillInDynamicSegments(path, params); | ||
function appendQueryParams(path, queryParams) { | ||
if (Object.keys(queryParams).length) { | ||
path += "?" + $.param(queryParams); | ||
} | ||
if (Object.keys(queryParams).length > 0) { | ||
path += "?" + Ember.$.param(queryParams); | ||
} | ||
visit(path); | ||
return target; | ||
return path; | ||
} | ||
/** | ||
* Creates an action to load a path | ||
* Creates an action to load a route | ||
* | ||
@@ -58,14 +43,28 @@ * @example | ||
* var page = PageObject.create({ | ||
* visit: visitalbe('/users') | ||
* visit: visitalbe('/users/:user_id') | ||
* }); | ||
* | ||
* page.visit(); | ||
* page.visit({ user_id: 10 }); | ||
* | ||
* @param {string} path - Full path of the route to visit | ||
* @param {Object} dynamicSegments - Key and values to use to replace the dynamic segments | ||
* @param {Object} queryParams - Key and values to use as the Query Params | ||
* @return {Descriptor} | ||
*/ | ||
export default function visitable(path, options = {}) { | ||
options.path = path; | ||
export function visitable(path) { | ||
return { | ||
isDescriptor: true, | ||
return new Descriptor(doVisit, options); | ||
value(dynamicSegmentsAndQueryParams = {}) { | ||
var params = merge({}, dynamicSegmentsAndQueryParams); | ||
var fullPath = fillInDynamicSegments(path, params); | ||
fullPath = appendQueryParams(fullPath, params); | ||
/* global visit */ | ||
visit(fullPath); | ||
return this; | ||
} | ||
}; | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1817106
113
869
83
1