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

add match exact text support #488

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
12 changes: 10 additions & 2 deletions addon-test-support/-private/execution_context/acceptance.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { run } from '../action';
import {
guardMultiple,
buildSelector,
findClosestValue
findClosestValue,
getCustomTextFilters
} from '../helpers';
import {
fillElement,
Expand Down Expand Up @@ -86,7 +87,12 @@ AcceptanceExecutionContext.prototype = {

assertElementExists(selector, options) {
/* global find */
let result = find(selector, options.testContainer || findClosestValue(this.pageObjectNode, 'testContainer'));
let result = find(selector, options.testContainer || findClosestValue(this.pageObjectNode, 'testContainer')).toArray();

Object.values(getCustomTextFilters(options))
.forEach(customFilter => {
result = result.filter($ele => customFilter($ele.textContent.trim(), options.contains));
});

if (result.length === 0) {
throwBetterError(
Expand All @@ -96,6 +102,8 @@ AcceptanceExecutionContext.prototype = {
{ selector }
);
}

return result;
},

find(selector, options) {
Expand Down
14 changes: 11 additions & 3 deletions addon-test-support/-private/execution_context/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { run as runAction } from '../action';
import {
guardMultiple,
buildSelector,
findClosestValue
findClosestValue,
getCustomTextFilters
} from '../helpers';
import {
fillElement,
Expand Down Expand Up @@ -100,11 +101,16 @@ IntegrationExecutionContext.prototype = {
let container = options.testContainer || findClosestValue(this.pageObjectNode, 'testContainer');

if (container) {
result = $(selector, container);
result = $(selector, container).toArray();
} else {
result = this.testContext.$(selector);
result = this.testContext.$(selector).toArray();
}

Object.values(getCustomTextFilters(options))
.forEach(customFilter => {
result = result.filter($ele => customFilter($ele.textContent.trim(), options.contains));
});

if (result.length === 0) {
throwBetterError(
this.pageObjectNode,
Expand All @@ -113,6 +119,8 @@ IntegrationExecutionContext.prototype = {
{ selector }
);
}

return result;
},

find(selector, options) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { run } from '../action';
import {
guardMultiple,
buildSelector,
findClosestValue
findClosestValue,
getCustomTextFilters
} from '../helpers';
import {
fillElement,
Expand Down Expand Up @@ -114,7 +115,12 @@ ExecutionContext.prototype = {
assertElementExists(selector, options) {
let container = options.testContainer || findClosestValue(this.pageObjectNode, 'testContainer');

let result = this.$(selector, container);
let result = this.$(selector, container).toArray();

Object.values(getCustomTextFilters(options))
.forEach(customFilter => {
result = result.filter($ele => customFilter($ele.textContent.trim(), options.contains));
});

if (result.length === 0) {
throwBetterError(
Expand All @@ -124,6 +130,8 @@ ExecutionContext.prototype = {
{ selector }
);
}

return result;
},

find(selector, options) {
Expand Down
10 changes: 9 additions & 1 deletion addon-test-support/-private/execution_context/rfc268.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
guardMultiple,
buildSelector,
findClosestValue,
getCustomTextFilters
} from '../helpers';
import {
getRootElement,
Expand Down Expand Up @@ -62,7 +63,12 @@ ExecutionContext.prototype = {
},

assertElementExists(selector, options) {
let result = this.getElements(selector, options);
let result = this.getElements(selector, options).toArray();

Object.values(getCustomTextFilters(options))
.forEach(customFilter => {
result = result.filter($ele => customFilter($ele.textContent.trim(), options.contains));
});

if (result.length === 0) {
throwBetterError(
Expand All @@ -72,6 +78,8 @@ ExecutionContext.prototype = {
{ selector }
);
}

return result;
},

find(selector, options) {
Expand Down
19 changes: 19 additions & 0 deletions addon-test-support/-private/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,22 @@ export function getPageObjectDefinition(node){
export function storePageObjectDefinition(node, definition){
Ceibo.meta(node).__poDef__ = definition;
}

export function getCustomTextFilters(obj) {
const requestedCustomFilters = {};

Object.keys(obj)
.forEach(filter => {
if (customTextFilters[filter]) {
requestedCustomFilters[filter] = customTextFilters[filter];
}
});

return requestedCustomFilters;
}

const customTextFilters = {
exact: (a, b) => a === b
}

export { customTextFilters };
4 changes: 2 additions & 2 deletions addon-test-support/properties/click-on-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ export function clickOnText(selector, userOptions = {}) {
let fullSelector = buildSelector(this, context, selector, options);
let container = options.testContainer || findClosestValue(this, 'testContainer');

context.assertElementExists(fullSelector, options);
const $ele = context.assertElementExists(fullSelector, options);

return context.click(fullSelector, container, options);
return context.click($ele[0], container, options);
Copy link
Collaborator

@ro0gr ro0gr Apr 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically a breaking change, unfortunatelly. At the moment execution contexts are a bit inconsistent. Some of them(RFC268, NativeEvents), do make sure they do only operate with a single element,
while the rest(Acceptance, Integration) just accept a selector and then pass it to a certain action helper.
you can compare it by looking at

const el = this.$(selector, container)[0];
click(el);

and

While I believe actions against multiple elements is bad, I think we can't just break this behavior w/o major version bump. And that's one of the primary point for v2(#479).

At the moment, the best way I can think of to achieve that behavior in v1 may be to introduce a new click(clickElement?) method for each execution context, which would accept just an element. It would also require a special code path in the click-on-text itself for matchExact only. And that all would be removed in favour of a more concise handling of matchExact in v2.

thoughts?

});
};
}
Expand Down
29 changes: 29 additions & 0 deletions tests/unit/-private/properties/click-on-text-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,33 @@ moduleForProperty('clickOnText', function(test) {
return page.foo('Click me');
}, /page\.foo/, 'Element not found');
});

test('should click on element matching exact text', async function(assert) {
assert.expect(2);

let page = create({
foo: clickOnText('button', { exact: true })
});

await this.adapter.createTemplate(this, page, `
<button>foo</button>
<button>foobar</button>
<button>foobarbaz</button>
`);

this.adapter.$('button:contains("foo")').one('click', function() {
assert.ok(true);
});

this.adapter.$('button:contains("foobar")').one('click', function() {
assert.ok(true);
});

await this.adapter.await(page.foo('foo'));


await this.adapter.throws(assert, function() {
return page.foo('fooobar');
}, /page\.foo/, 'Element not found');
});
});
7 changes: 6 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ declare module 'ember-cli-page-object' {
Definition,
FindOptions,
TriggerOptions,
ClickOnTextOptions,
GetterDescriptor,
MethodDescriptor,
DSL
Expand All @@ -31,7 +32,7 @@ declare module 'ember-cli-page-object' {

// Actions
function clickable(scope?: string, userOptions?: FindOptions): MethodDescriptor<<T>(this: T) => T>;
function clickOnText(scope?: string, userOptions?: FindOptions): MethodDescriptor<<T>(this: T, text: string) => T>;
function clickOnText(scope?: string, userOptions?: ClickOnTextOptions): MethodDescriptor<<T>(this: T, text: string) => T>;
function fillable(scope?: string, userOptions?: FindOptions): MethodDescriptor<<T>(this: T, clueOrContent: string, content?: string) => T>;
function selectable(scope?: string, userOptions?: FindOptions): MethodDescriptor<<T>(this: T, clueOrContent: string, content?: string) => T>;
function triggerable(event: string, scope?: string, eventOptions?: TriggerOptions, options?: FindOptions): MethodDescriptor<<T>(this: T, options?: {}) => T>;
Expand Down Expand Up @@ -162,4 +163,8 @@ declare module 'ember-cli-page-object/-private' {
resetScope?: boolean;
testContainer?: string|HTMLElement|JQuery;
}

interface ClickOnTextOptions extends FindOptions {
exact?: boolean
}
}