Files
xod/packages/xod-client-electron/test-func/pageObject.js

412 lines
12 KiB
JavaScript

const R = require('ramda');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const { assert } = chai;
//-----------------------------------------------------------------------------
// Func utils
//-----------------------------------------------------------------------------
const hasClass = R.curry((className, element) =>
R.composeP(R.contains(className), R.split(' '), el =>
el.getAttribute('class')
)(element)
);
//-----------------------------------------------------------------------------
// General Utils
//-----------------------------------------------------------------------------
function scrollTo(client, containerSelector, childSelector) {
return client.execute(
(contSel, chldSel) => {
const container = document.querySelector(contSel);
const child = document.querySelector(chldSel);
container.scrollTop = child.offsetTop;
},
containerSelector,
childSelector
);
}
function rendered(client) {
return assert.eventually.isTrue(client.waitForExist('.Editor', 5000));
}
// -----------------------------------------------------------------------------
// Popup dialogs
//-----------------------------------------------------------------------------
function findPopup(client) {
return client.element('.PopupPrompt');
}
function assertPopupShown(client, title) {
return Promise.all([
assert.eventually.isTrue(findPopup(client).isVisible()),
assert.eventually.strictEqual(findPopup(client).getText('h2'), title),
]);
}
function assertNoPopups(client) {
return assert.eventually.isFalse(findPopup(client).isVisible());
}
function confirmPopup(client) {
return findPopup(client).click('button.Button--primary');
}
function getCodeboxValue(client) {
return client.getValue('.Codebox');
}
function closePopup(client) {
return client.element('.skylight-close-button').click();
}
//-----------------------------------------------------------------------------
// Project browser
//-----------------------------------------------------------------------------
const getSelectorForPatchInProjectBrowser = nodeName =>
`.PatchGroupItem[data-id="${nodeName}"]`;
function findProjectBrowser(client) {
return client.element('.ProjectBrowser');
}
function assertProjectIsOpened(client, projectName) {
const selector = `.PatchGroup__trigger.my .patch-group-trigger[data-id="${projectName}"`;
return assert.eventually.isTrue(client.waitForExist(selector, 15000));
}
function clickAddPatch(client) {
return findProjectBrowser(client).click('button[title="Add patch"]');
}
function findPatchGroup(client, groupTitle) {
const selector = `.PatchGroup=${groupTitle}`;
return findProjectBrowser(client)
.waitForExist(selector, 5000)
.then(() => client.element(selector));
}
function findPatchGroupItem(client, name) {
const selector = getSelectorForPatchInProjectBrowser(name);
return findProjectBrowser(client)
.waitForExist(selector, 5000)
.then(() => client.element(selector));
}
function assertPatchGroupCollapsed(client, groupTitle) {
return assert.eventually.include(
findPatchGroup(client, groupTitle).getAttribute('class'),
'is-closed',
`Expected patch group "${groupTitle}" to be collapsed, but it's expanded`
);
}
function assertPatchGroupExpanded(client, groupTitle) {
return assert.eventually.include(
findPatchGroup(client, groupTitle).getAttribute('class'),
'is-open',
`Expected patch group "${groupTitle}" to be expanded, but it's collapsed`
);
}
function assertNodeAvailableInProjectBrowser(client, nodeName) {
return assert.eventually.isTrue(
findProjectBrowser(client).isVisible(
getSelectorForPatchInProjectBrowser(nodeName)
),
`Expected node "${nodeName}" to be available in the project browser`
);
}
function assertNodeUnavailableInProjectBrowser(client, nodeName) {
return assert.eventually.isFalse(
findProjectBrowser(client).isVisible(
getSelectorForPatchInProjectBrowser(nodeName)
),
`Expected node "${nodeName}" to be unavailable in the project browser`
);
}
function scrollToPatchInProjectBrowser(client, name) {
return scrollTo(
client,
'.ProjectBrowser',
getSelectorForPatchInProjectBrowser(name)
);
}
function selectPatchInProjectBrowser(client, name) {
const patch = findPatchGroupItem(client, name);
return hasClass('isSelected', patch).then(
selected =>
selected
? Promise.resolve()
: client.click(getSelectorForPatchInProjectBrowser(name))
);
}
function openProjectBrowserPatchContextMenu(client, name) {
const selector = getSelectorForPatchInProjectBrowser(name);
return selectPatchInProjectBrowser(client, name)
.then(() => client.waitForVisible(`${selector} .contextmenu`))
.then(() => findPatchGroupItem(client, name).rightClick('.contextmenu'));
}
function findProjectBrowserPatchContextMenu(client) {
return client.element('.ContextMenu--PatchGroupItem');
}
function openPatchFromProjectBrowser(client, name) {
return client.doubleClick(getSelectorForPatchInProjectBrowser(name));
}
function clickDeletePatchButton(client, name) {
return openProjectBrowserPatchContextMenu(client, name).then(() =>
findProjectBrowserPatchContextMenu(client).click(
'.react-contextmenu-item[data-id="delete"]'
)
);
}
function assertPatchSelected(client, name) {
return assert.eventually.include(
client
.element(getSelectorForPatchInProjectBrowser(name))
.getAttribute('class'),
'isSelected'
);
}
function clickAddNodeButton(client, name) {
return openProjectBrowserPatchContextMenu(client, name).then(() =>
findProjectBrowserPatchContextMenu(client).click(
'.react-contextmenu-item[data-id="place"]'
)
);
}
function expandPatchGroup(client, groupTitle) {
return hasClass('is-open', findPatchGroup(client, groupTitle)).then(
opened =>
opened ? Promise.resolve() : findPatchGroup(client, groupTitle).click()
);
}
//-----------------------------------------------------------------------------
// LibSuggester
//-----------------------------------------------------------------------------
function findLibSuggester(client) {
return client.element('.Suggester-libs');
}
function assertLibSuggesterShown(client) {
return assert.eventually.isTrue(findLibSuggester(client).isVisible());
}
function assertLibsNotFound(client) {
return assert.eventually.isTrue(
findLibSuggester(client).waitForExist('.error', 30000)
);
}
function assertLibraryFound(client) {
return assert.eventually.isTrue(
findLibSuggester(client).waitForExist('.Suggester-item--library', 30000)
);
}
function installLibrary(client) {
return findLibSuggester(client).doubleClick('.Suggester-item--library');
}
function assertLibSuggesterHidden(client) {
return assert.eventually.isFalse(client.isExisting('.Suggester-libs'));
}
function assertProjectBrowserHasInstallingLib(client, libName) {
const selector = '.PatchGroup--installing';
return assert.eventually.equal(
client
.waitForExist(selector, 10000)
.then(() => client.element('.PatchGroup--installing').getText('.name')),
libName
);
}
//-----------------------------------------------------------------------------
// Patch
//-----------------------------------------------------------------------------
function findNode(client, nodeType) {
return client.element(`.Node[data-label="${nodeType}"]`);
}
function dragNode(client, nodeType, dx, dy) {
return client
.moveToObject(`.Node[data-label="${nodeType}"]`)
.buttonDown()
.moveTo(null, dx, dy)
.buttonUp()
.then(() => findNode(client, nodeType)); // for easy chaining
}
function findPin(client, nodeType, pinLabel) {
return client.element(
`.NodePinsOverlay[data-label="${nodeType}"] .PinOverlay[data-label="${pinLabel}"]`
);
}
function findLink(client, type) {
return client.element(`.Link.${type}`);
}
function addNode(client, type, dragX, dragY) {
return scrollToPatchInProjectBrowser(client, type)
.then(() => selectPatchInProjectBrowser(client, type))
.then(() => clickAddNodeButton(client, type))
.then(() => dragNode(client, type, dragX, dragY));
}
function deletePatch(client, type) {
return client
.waitForVisible(getSelectorForPatchInProjectBrowser(type))
.then(() => scrollToPatchInProjectBrowser(client, type))
.then(() => clickDeletePatchButton(client, type))
.then(() =>
findProjectBrowser(client).click('.PopupConfirm button.Button--primary')
);
}
function assertPinIsSelected(client, nodeType, pinLabel) {
return assert.eventually.include(
findPin(client, nodeType, pinLabel).getAttribute('class'),
'is-selected'
);
}
function assertPinIsAcceptingLinks(client, nodeType, pinLabel) {
return assert.eventually.include(
findPin(client, nodeType, pinLabel).getAttribute('class'),
'is-accepting-links'
);
}
//-----------------------------------------------------------------------------
// Inspector
//-----------------------------------------------------------------------------
function findInspectorWidget(client, name) {
return client.element(`.Widget[title=${name}] input`);
}
function bindValue(client, nodeType, pinLabel, value) {
return findNode(client, nodeType)
.click()
.then(() =>
findInspectorWidget(client, pinLabel)
.setValue(value)
.keys('Enter')
);
}
//-----------------------------------------------------------------------------
// Tabs
//-----------------------------------------------------------------------------
function assertActiveTabHasTitle(client, expectedTitle) {
return assert.eventually.strictEqual(
client.getText('.TabsContainer .TabsItem.is-active .tab-name'),
expectedTitle
);
}
function assertTabWithTitleDoesNotExist(client, expectedTitle) {
return assert.eventually.isFalse(
client.isExisting(`.tab-name=${expectedTitle}`)
);
}
function assertNoPatchesAreOpen(client) {
return assert.eventually.isTrue(client.isVisible('.NoPatch'));
}
//-----------------------------------------------------------------------------
// Messages
//-----------------------------------------------------------------------------
function waitUntilProjectSaved(client) {
return client.waitForExist('.SnackBarMessage*=Saved', 5000);
}
function waitUntilLibraryInstalled(client) {
return client.waitForExist('.SnackBarMessage*=Installed', 10000);
}
//-----------------------------------------------------------------------------
// API
//-----------------------------------------------------------------------------
// Public API (in alphabetical order)
const API = {
rendered,
addNode,
assertActiveTabHasTitle,
assertTabWithTitleDoesNotExist,
assertNoPatchesAreOpen,
assertNoPopups,
assertNodeAvailableInProjectBrowser,
assertNodeUnavailableInProjectBrowser,
assertPatchGroupCollapsed,
assertPatchGroupExpanded,
assertPatchSelected,
assertPinIsAcceptingLinks,
assertPinIsSelected,
assertPopupShown,
assertProjectIsOpened,
bindValue,
clickAddNodeButton,
clickAddPatch,
confirmPopup,
closePopup,
dragNode,
findInspectorWidget,
findLink,
findNode,
findPatchGroup,
findPatchGroupItem,
findPin,
findPopup,
getCodeboxValue,
scrollTo,
scrollToPatchInProjectBrowser,
selectPatchInProjectBrowser,
openPatchFromProjectBrowser,
openProjectBrowserPatchContextMenu,
deletePatch,
expandPatchGroup,
// LibSuggester
findLibSuggester,
assertLibSuggesterShown,
assertLibsNotFound,
assertLibraryFound,
installLibrary,
assertLibSuggesterHidden,
assertProjectBrowserHasInstallingLib,
// Messages
waitUntilProjectSaved,
waitUntilLibraryInstalled,
};
/**
* Creates an object to interact with the page. It would contain all available
* API methods with `client` already bound.
*/
function createPageObject(client) {
return R.map(fn => R.partial(fn, [client]))(API);
}
module.exports = {
createPageObject,
API,
};