Ability to send keypress events to component element
Hi, I have the need to drive an ember-power-select component during acceptance tests, to simulate it's fuzzy searching capabilities. Using the triggerable property is very cumbersome, and it's input element doesn't respond to simple fillable value changes.
Ideally, I would like to do something like this:
modal: {
scope: '[data-test-modal]',
name: fillable('[data-test-name] input'),
clickAddEmails: clickable('[data-test-add-email]'),
addEmailInput: keypress( '.ember-power-select-trigger-multiple-input'),
emails: collection({
itemScope: '.ember-power-select-option',
item: {
email: text(),
click: clickable()
}
}),
cancel: clickable('[data-test-cancel]'),
submit: clickable('[data-test-submit]')
},
from the acceptance test:
it('can add an entry, with emails', () => {
page.visit();
andThen(() => {
page.clickAddEntry();
});
const modal = page.modal;
modal.name('Acceptance Test Entry');
modal.clickAddEmails();
andThen(() => {
modal.addEmailInput('@gmail');
const email1 = modal.emails(0);
})
});
using the keypress property would send keypress events to the element.
I could always hack around it with jQuery, but a declarative property on the page object would be a lot cleaner.
P.S., I tried making my own property function using extend, but had trouble using getCurrentContext, which is private.
ember-power-select provides its own test helpers that make interacting with it possible from page-objects. Here is my current power-select page:
import { clickable, text, attribute} from 'ember-cli-page-object';
import { buildSelector } from 'ember-cli-page-object/extend';
import { assign } from '@ember/polyfills';
import { getExecutionContext } from 'ember-cli-page-object/test-support/-private/execution_context';
import { typeInSearch, clickTrigger as _clickTrigger, findContains as _findContains, selectChoose as _selectChoose } from 'ember-power-select/test-support/helpers';
import { assert } from '@ember/debug';
export default function (scope) {
return {
scope: scope || '.ui-filter-multi-select',
select: selectChoose(),
clickTrigger: clickTrigger(),
find: findContains(),
typeInSearch(text) {
typeInSearch(text);
return this;
},
placeholder: text('.ember-power-select-placeholder'),
selected: text('.ember-power-select-selected-item'),
clear: clickable('.ember-power-select-clear-btn'),
currentSearchValue: currentSearchValue(),
isOpen: attribute('aria-expanded', '.ember-power-select-trigger')
};
}
export var clickTrigger = function (selector, userOptions = {}) {
return {
isDescriptor: true,
get(key) {
return function () {
let executionContext = getExecutionContext(this);
let options = assign({ pageObjectKey: `${key}()` }, userOptions);
return executionContext.runAsync(() => {
let fullSelector = buildSelector(this, selector, options);
return _clickTrigger(fullSelector);
});
};
}
}
};
export var selectChoose = function (selector, userOptions = {}) {
return {
isDescriptor: true,
get(key) {
return function(value){
let executionContext = getExecutionContext(this);
let options = assign({ pageObjectKey: `${key}()` }, userOptions);
return executionContext.runAsync(() => {
let fullSelector = buildSelector(this, selector, options);
return _selectChoose(fullSelector, value);
});
}
}
};
};
export var findContains = function(selector, userOptions = {}) {
return {
isDescriptor: true,
get(key) {
return function(text){
let executionContext = getExecutionContext(this);
let options = assign({ pageObjectKey: `${key}()` }, userOptions);
return executionContext.runAsync(() => {
let fullSelector = buildSelector(this, selector, options);
return _findContains(fullSelector, text);
});
}
}
};
};
export var currentSearchValue = function() {
return {
isDescriptor: true,
get() {
// TODO: get this merged into ember-power-select
let selectors = [
'.ember-power-select-search-input',
'.ember-power-select-search input',
'.ember-power-select-trigger-multiple-input',
'input[type="search"]'
].map((selector) => `${selector}`).join(', ');
let searchInput = document.querySelector(selectors);
assert("power-select search exists", searchInput);
return searchInput.value;
}
};
};
A test that required selecting an item would look like
await page.clickTrigger()
.typeInSearch("Foo")
.select("Foo")
This works both for acceptance and integration tests.
@ro0gr is there anyway to have done this without relying on the private API for getExecutionContext?
I think integrating of the new @ember/test-helpers typeIn helper should resolve the issue.
@mistahenry there is no public way to define a full featured custom action yet. You can keep using public APIs only, but w/o chaining support at least.
I'm currently working on decoupling of actions from the execution context, which, I think, would make us closer to the custom actions goal.