remove explicit timeouts from tests for selectors

- gets rid of the waitAndQuery vs query distinction,
  all queries now wait if needed (called query and queryAll)
- remove explicit timeouts,
  as they depend on the speed of the machine the tests run on
This commit is contained in:
Bruno Windels 2019-04-16 15:35:31 +02:00
parent c40f7f6a3c
commit 48c1d46aa7
12 changed files with 57 additions and 59 deletions

View file

@ -19,6 +19,8 @@ const Logger = require('./logger');
const LogBuffer = require('./logbuffer'); const LogBuffer = require('./logbuffer');
const {delay} = require('./util'); const {delay} = require('./util');
const DEFAULT_TIMEOUT = 20000;
module.exports = class RiotSession { module.exports = class RiotSession {
constructor(browser, page, username, riotserver, hsUrl) { constructor(browser, page, username, riotserver, hsUrl) {
this.browser = browser; this.browser = browser;
@ -113,23 +115,18 @@ module.exports = class RiotSession {
} }
query(selector) { query(selector) {
return this.page.$(selector); const timeout = DEFAULT_TIMEOUT;
}
waitAndQuery(selector, timeout = 5000) {
return this.page.waitForSelector(selector, {visible: true, timeout}); return this.page.waitForSelector(selector, {visible: true, timeout});
} }
queryAll(selector) { async queryAll(selector) {
return this.page.$$(selector); const timeout = DEFAULT_TIMEOUT;
await this.query(selector, timeout);
return await this.page.$$(selector);
} }
async waitAndQueryAll(selector, timeout = 5000) { waitForReload() {
await this.waitAndQuery(selector, timeout); const timeout = DEFAULT_TIMEOUT;
return await this.queryAll(selector);
}
waitForReload(timeout = 10000) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const timeoutHandle = setTimeout(() => { const timeoutHandle = setTimeout(() => {
this.browser.removeEventListener('domcontentloaded', callback); this.browser.removeEventListener('domcontentloaded', callback);
@ -145,7 +142,8 @@ module.exports = class RiotSession {
}); });
} }
waitForNewPage(timeout = 5000) { waitForNewPage() {
const timeout = DEFAULT_TIMEOUT;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const timeoutHandle = setTimeout(() => { const timeoutHandle = setTimeout(() => {
this.browser.removeListener('targetcreated', callback); this.browser.removeListener('targetcreated', callback);

View file

@ -20,7 +20,7 @@ const {acceptDialogMaybe} = require('./dialog');
module.exports = async function acceptInvite(session, name) { module.exports = async function acceptInvite(session, name) {
session.log.step(`accepts "${name}" invite`); session.log.step(`accepts "${name}" invite`);
//TODO: brittle selector //TODO: brittle selector
const invitesHandles = await session.waitAndQueryAll('.mx_RoomTile_name.mx_RoomTile_invite'); const invitesHandles = await session.queryAll('.mx_RoomTile_name.mx_RoomTile_invite');
const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => { const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => {
const text = await session.innerText(inviteHandle); const text = await session.innerText(inviteHandle);
return {inviteHandle, text}; return {inviteHandle, text};
@ -31,7 +31,7 @@ module.exports = async function acceptInvite(session, name) {
await inviteHandle.click(); await inviteHandle.click();
const acceptInvitationLink = await session.waitAndQuery(".mx_RoomPreviewBar_join_text a:first-child"); const acceptInvitationLink = await session.query(".mx_RoomPreviewBar_join_text a:first-child");
await acceptInvitationLink.click(); await acceptInvitationLink.click();
session.log.done(); session.log.done();

View file

@ -31,16 +31,16 @@ async function openRoomDirectory(session) {
async function createRoom(session, roomName) { async function createRoom(session, roomName) {
session.log.step(`creates room "${roomName}"`); session.log.step(`creates room "${roomName}"`);
await openRoomDirectory(session); await openRoomDirectory(session);
const createRoomButton = await session.waitAndQuery('.mx_RoomDirectory_createRoom'); const createRoomButton = await session.query('.mx_RoomDirectory_createRoom');
await createRoomButton.click(); await createRoomButton.click();
const roomNameInput = await session.waitAndQuery('.mx_CreateRoomDialog_input'); const roomNameInput = await session.query('.mx_CreateRoomDialog_input');
await session.replaceInputText(roomNameInput, roomName); await session.replaceInputText(roomNameInput, roomName);
const createButton = await session.waitAndQuery('.mx_Dialog_primary'); const createButton = await session.query('.mx_Dialog_primary');
await createButton.click(); await createButton.click();
await session.waitAndQuery('.mx_MessageComposer'); await session.query('.mx_MessageComposer');
session.log.done(); session.log.done();
} }

View file

@ -17,7 +17,7 @@ limitations under the License.
const assert = require('assert'); const assert = require('assert');
async function assertDialog(session, expectedTitle) { async function assertDialog(session, expectedTitle) {
const titleElement = await session.waitAndQuery(".mx_Dialog .mx_Dialog_title"); const titleElement = await session.query(".mx_Dialog .mx_Dialog_title");
const dialogHeader = await session.innerText(titleElement); const dialogHeader = await session.innerText(titleElement);
assert(dialogHeader, expectedTitle); assert(dialogHeader, expectedTitle);
} }
@ -32,7 +32,7 @@ async function acceptDialog(session, expectedTitle) {
async function acceptDialogMaybe(session, expectedTitle) { async function acceptDialogMaybe(session, expectedTitle) {
let primaryButton = null; let primaryButton = null;
try { try {
primaryButton = await session.waitAndQuery(".mx_Dialog .mx_Dialog_primary", 100); primaryButton = await session.query(".mx_Dialog .mx_Dialog_primary");
} catch(err) { } catch(err) {
return false; return false;
} }

View file

@ -19,9 +19,9 @@ const assert = require('assert');
module.exports = async function invite(session, userId) { module.exports = async function invite(session, userId) {
session.log.step(`invites "${userId}" to room`); session.log.step(`invites "${userId}" to room`);
await session.delay(1000); await session.delay(1000);
const inviteButton = await session.waitAndQuery(".mx_MemberList_invite"); const inviteButton = await session.query(".mx_MemberList_invite");
await inviteButton.click(); await inviteButton.click();
const inviteTextArea = await session.waitAndQuery(".mx_AddressPickerDialog textarea"); const inviteTextArea = await session.query(".mx_AddressPickerDialog textarea");
await inviteTextArea.type(userId); await inviteTextArea.type(userId);
await inviteTextArea.press("Enter"); await inviteTextArea.press("Enter");
const confirmButton = await session.query(".mx_Dialog_primary"); const confirmButton = await session.query(".mx_Dialog_primary");

View file

@ -20,15 +20,15 @@ const {openRoomDirectory} = require('./create-room');
module.exports = async function join(session, roomName) { module.exports = async function join(session, roomName) {
session.log.step(`joins room "${roomName}"`); session.log.step(`joins room "${roomName}"`);
await openRoomDirectory(session); await openRoomDirectory(session);
const roomInput = await session.waitAndQuery('.mx_DirectorySearchBox input'); const roomInput = await session.query('.mx_DirectorySearchBox input');
await session.replaceInputText(roomInput, roomName); await session.replaceInputText(roomInput, roomName);
const firstRoomLabel = await session.waitAndQuery('.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child', 1000); const firstRoomLabel = await session.query('.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child');
await firstRoomLabel.click(); await firstRoomLabel.click();
const joinLink = await session.waitAndQuery('.mx_RoomPreviewBar_join_text a'); const joinLink = await session.query('.mx_RoomPreviewBar_join_text a');
await joinLink.click(); await joinLink.click();
await session.waitAndQuery('.mx_MessageComposer'); await session.query('.mx_MessageComposer');
session.log.done(); session.log.done();
} }

View file

@ -34,20 +34,20 @@ module.exports.verifyDeviceForUser = async function(session, name, expectedDevic
}).map((m) => m.label)[0]; }).map((m) => m.label)[0];
await matchingLabel.click(); await matchingLabel.click();
// click verify in member info // click verify in member info
const firstVerifyButton = await session.waitAndQuery(".mx_MemberDeviceInfo_verify"); const firstVerifyButton = await session.query(".mx_MemberDeviceInfo_verify");
await firstVerifyButton.click(); await firstVerifyButton.click();
// expect "Verify device" dialog and click "Begin Verification" // expect "Verify device" dialog and click "Begin Verification"
const dialogHeader = await session.innerText(await session.waitAndQuery(".mx_Dialog .mx_Dialog_title")); const dialogHeader = await session.innerText(await session.query(".mx_Dialog .mx_Dialog_title"));
assert(dialogHeader, "Verify device"); assert(dialogHeader, "Verify device");
const beginVerificationButton = await session.waitAndQuery(".mx_Dialog .mx_Dialog_primary") const beginVerificationButton = await session.query(".mx_Dialog .mx_Dialog_primary")
await beginVerificationButton.click(); await beginVerificationButton.click();
// get emoji SAS labels // get emoji SAS labels
const sasLabelElements = await session.waitAndQueryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label"); const sasLabelElements = await session.queryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label");
const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e))); const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e)));
console.log("my sas labels", sasLabels); console.log("my sas labels", sasLabels);
const dialogCodeFields = await session.waitAndQueryAll(".mx_QuestionDialog code"); const dialogCodeFields = await session.queryAll(".mx_QuestionDialog code");
assert.equal(dialogCodeFields.length, 2); assert.equal(dialogCodeFields.length, 2);
const deviceId = await session.innerText(dialogCodeFields[0]); const deviceId = await session.innerText(dialogCodeFields[0]);
const deviceKey = await session.innerText(dialogCodeFields[1]); const deviceKey = await session.innerText(dialogCodeFields[1]);
@ -61,7 +61,7 @@ module.exports.verifyDeviceForUser = async function(session, name, expectedDevic
} }
async function getMembersInMemberlist(session) { async function getMembersInMemberlist(session) {
const memberNameElements = await session.waitAndQueryAll(".mx_MemberList .mx_EntityTile_name"); const memberNameElements = await session.queryAll(".mx_MemberList .mx_EntityTile_name");
return Promise.all(memberNameElements.map(async (el) => { return Promise.all(memberNameElements.map(async (el) => {
return {label: el, displayName: await session.innerText(el)}; return {label: el, displayName: await session.innerText(el)};
})); }));

View file

@ -37,11 +37,11 @@ module.exports = async function changeRoomSettings(session, settings) {
const settingsButton = await session.query(".mx_RoomHeader .mx_AccessibleButton[title=Settings]"); const settingsButton = await session.query(".mx_RoomHeader .mx_AccessibleButton[title=Settings]");
await settingsButton.click(); await settingsButton.click();
//find tabs //find tabs
const tabButtons = await session.waitAndQueryAll(".mx_RoomSettingsDialog .mx_TabbedView_tabLabel"); const tabButtons = await session.queryAll(".mx_RoomSettingsDialog .mx_TabbedView_tabLabel");
const tabLabels = await Promise.all(tabButtons.map(t => session.innerText(t))); const tabLabels = await Promise.all(tabButtons.map(t => session.innerText(t)));
const securityTabButton = tabButtons[tabLabels.findIndex(l => l.toLowerCase().includes("security"))]; const securityTabButton = tabButtons[tabLabels.findIndex(l => l.toLowerCase().includes("security"))];
const generalSwitches = await session.waitAndQueryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch"); const generalSwitches = await session.queryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch");
const isDirectory = generalSwitches[0]; const isDirectory = generalSwitches[0];
if (typeof settings.directory === "boolean") { if (typeof settings.directory === "boolean") {
@ -51,9 +51,9 @@ module.exports = async function changeRoomSettings(session, settings) {
if (settings.alias) { if (settings.alias) {
session.log.step(`sets alias to ${settings.alias}`); session.log.step(`sets alias to ${settings.alias}`);
const aliasField = await session.waitAndQuery(".mx_RoomSettingsDialog .mx_AliasSettings input[type=text]"); const aliasField = await session.query(".mx_RoomSettingsDialog .mx_AliasSettings input[type=text]");
await session.replaceInputText(aliasField, settings.alias); await session.replaceInputText(aliasField, settings.alias);
const addButton = await session.waitAndQuery(".mx_RoomSettingsDialog .mx_AliasSettings .mx_AccessibleButton"); const addButton = await session.query(".mx_RoomSettingsDialog .mx_AliasSettings .mx_AccessibleButton");
await addButton.click(); await addButton.click();
session.log.done(); session.log.done();
} }
@ -74,7 +74,7 @@ module.exports = async function changeRoomSettings(session, settings) {
if (settings.visibility) { if (settings.visibility) {
session.log.step(`sets visibility to ${settings.visibility}`); session.log.step(`sets visibility to ${settings.visibility}`);
const radios = await session.waitAndQueryAll(".mx_RoomSettingsDialog input[type=radio]"); const radios = await session.queryAll(".mx_RoomSettingsDialog input[type=radio]");
assert.equal(radios.length, 7); assert.equal(radios.length, 7);
const inviteOnly = radios[0]; const inviteOnly = radios[0];
const publicNoGuests = radios[1]; const publicNoGuests = radios[1];

View file

@ -20,7 +20,7 @@ module.exports = async function sendMessage(session, message) {
session.log.step(`writes "${message}" in room`); session.log.step(`writes "${message}" in room`);
// this selector needs to be the element that has contenteditable=true, // this selector needs to be the element that has contenteditable=true,
// not any if its parents, otherwise it behaves flaky at best. // not any if its parents, otherwise it behaves flaky at best.
const composer = await session.waitAndQuery('.mx_MessageComposer_editor'); const composer = await session.query('.mx_MessageComposer_editor');
// sometimes the focus that type() does internally doesn't seem to work // sometimes the focus that type() does internally doesn't seem to work
// and calling click before seems to fix it 🤷 // and calling click before seems to fix it 🤷
await composer.click(); await composer.click();
@ -29,6 +29,6 @@ module.exports = async function sendMessage(session, message) {
assert.equal(text.trim(), message.trim()); assert.equal(text.trim(), message.trim());
await composer.press("Enter"); await composer.press("Enter");
// wait for the message to appear sent // wait for the message to appear sent
await session.waitAndQuery(".mx_EventTile_last:not(.mx_EventTile_sending)"); await session.query(".mx_EventTile_last:not(.mx_EventTile_sending)");
session.log.done(); session.log.done();
} }

View file

@ -19,10 +19,10 @@ const assert = require('assert');
async function openSettings(session, section) { async function openSettings(session, section) {
const menuButton = await session.query(".mx_TopLeftMenuButton_name"); const menuButton = await session.query(".mx_TopLeftMenuButton_name");
await menuButton.click(); await menuButton.click();
const settingsItem = await session.waitAndQuery(".mx_TopLeftMenu_icon_settings"); const settingsItem = await session.query(".mx_TopLeftMenu_icon_settings");
await settingsItem.click(); await settingsItem.click();
if (section) { if (section) {
const sectionButton = await session.waitAndQuery(`.mx_UserSettingsDialog .mx_TabbedView_tabLabels .mx_UserSettingsDialog_${section}Icon`); const sectionButton = await session.query(`.mx_UserSettingsDialog .mx_TabbedView_tabLabels .mx_UserSettingsDialog_${section}Icon`);
await sectionButton.click(); await sectionButton.click();
} }
} }
@ -31,10 +31,10 @@ module.exports.enableLazyLoading = async function(session) {
session.log.step(`enables lazy loading of members in the lab settings`); session.log.step(`enables lazy loading of members in the lab settings`);
const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); const settingsButton = await session.query('.mx_BottomLeftMenu_settings');
await settingsButton.click(); await settingsButton.click();
const llCheckbox = await session.waitAndQuery("#feature_lazyloading"); const llCheckbox = await session.query("#feature_lazyloading");
await llCheckbox.click(); await llCheckbox.click();
await session.waitForReload(); await session.waitForReload();
const closeButton = await session.waitAndQuery(".mx_RoomHeader_cancelButton"); const closeButton = await session.query(".mx_RoomHeader_cancelButton");
await closeButton.click(); await closeButton.click();
session.log.done(); session.log.done();
} }
@ -42,7 +42,7 @@ module.exports.enableLazyLoading = async function(session) {
module.exports.getE2EDeviceFromSettings = async function(session) { module.exports.getE2EDeviceFromSettings = async function(session) {
session.log.step(`gets e2e device/key from settings`); session.log.step(`gets e2e device/key from settings`);
await openSettings(session, "security"); await openSettings(session, "security");
const deviceAndKey = await session.waitAndQueryAll(".mx_SettingsTab_section .mx_SecurityUserSettingsTab_deviceInfo code"); const deviceAndKey = await session.queryAll(".mx_SettingsTab_section .mx_SecurityUserSettingsTab_deviceInfo code");
assert.equal(deviceAndKey.length, 2); assert.equal(deviceAndKey.length, 2);
const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue(); const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue();
const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue(); const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue();

View file

@ -21,17 +21,17 @@ module.exports = async function signup(session, username, password, homeserver)
await session.goto(session.url('/#/register')); await session.goto(session.url('/#/register'));
// change the homeserver by clicking the "Change" link. // change the homeserver by clicking the "Change" link.
if (homeserver) { if (homeserver) {
const changeServerDetailsLink = await session.waitAndQuery('.mx_AuthBody_editServerDetails'); const changeServerDetailsLink = await session.query('.mx_AuthBody_editServerDetails');
await changeServerDetailsLink.click(); await changeServerDetailsLink.click();
const hsInputField = await session.waitAndQuery('#mx_ServerConfig_hsUrl'); const hsInputField = await session.query('#mx_ServerConfig_hsUrl');
await session.replaceInputText(hsInputField, homeserver); await session.replaceInputText(hsInputField, homeserver);
const nextButton = await session.waitAndQuery('.mx_Login_submit'); const nextButton = await session.query('.mx_Login_submit');
await nextButton.click(); await nextButton.click();
} }
//fill out form //fill out form
const usernameField = await session.waitAndQuery("#mx_RegistrationForm_username"); const usernameField = await session.query("#mx_RegistrationForm_username");
const passwordField = await session.waitAndQuery("#mx_RegistrationForm_password"); const passwordField = await session.query("#mx_RegistrationForm_password");
const passwordRepeatField = await session.waitAndQuery("#mx_RegistrationForm_passwordConfirm"); const passwordRepeatField = await session.query("#mx_RegistrationForm_passwordConfirm");
await session.replaceInputText(usernameField, username); await session.replaceInputText(usernameField, username);
await session.replaceInputText(passwordField, password); await session.replaceInputText(passwordField, password);
await session.replaceInputText(passwordRepeatField, password); await session.replaceInputText(passwordRepeatField, password);
@ -41,7 +41,7 @@ module.exports = async function signup(session, username, password, homeserver)
await session.delay(300); await session.delay(300);
/// focus on the button to make sure error validation /// focus on the button to make sure error validation
/// has happened before checking the form is good to go /// has happened before checking the form is good to go
const registerButton = await session.waitAndQuery('.mx_Login_submit'); const registerButton = await session.query('.mx_Login_submit');
await registerButton.focus(); await registerButton.focus();
//check no errors //check no errors
const error_text = await session.tryGetInnertext('.mx_Login_error'); const error_text = await session.tryGetInnertext('.mx_Login_error');
@ -51,15 +51,15 @@ module.exports = async function signup(session, username, password, homeserver)
await registerButton.click(); await registerButton.click();
//confirm dialog saying you cant log back in without e-mail //confirm dialog saying you cant log back in without e-mail
const continueButton = await session.waitAndQuery('.mx_QuestionDialog button.mx_Dialog_primary'); const continueButton = await session.query('.mx_QuestionDialog button.mx_Dialog_primary');
await continueButton.click(); await continueButton.click();
//find the privacy policy checkbox and check it //find the privacy policy checkbox and check it
const policyCheckbox = await session.waitAndQuery('.mx_InteractiveAuthEntryComponents_termsPolicy input'); const policyCheckbox = await session.query('.mx_InteractiveAuthEntryComponents_termsPolicy input');
await policyCheckbox.click(); await policyCheckbox.click();
//now click the 'Accept' button to agree to the privacy policy //now click the 'Accept' button to agree to the privacy policy
const acceptButton = await session.waitAndQuery('.mx_InteractiveAuthEntryComponents_termsSubmit'); const acceptButton = await session.query('.mx_InteractiveAuthEntryComponents_termsSubmit');
await acceptButton.click(); await acceptButton.click();
//wait for registration to finish so the hash gets set //wait for registration to finish so the hash gets set

View file

@ -19,19 +19,19 @@ const {openMemberInfo} = require("./memberlist");
const {assertDialog, acceptDialog} = require("./dialog"); const {assertDialog, acceptDialog} = require("./dialog");
async function assertVerified(session) { async function assertVerified(session) {
const dialogSubTitle = await session.innerText(await session.waitAndQuery(".mx_Dialog h2")); const dialogSubTitle = await session.innerText(await session.query(".mx_Dialog h2"));
assert(dialogSubTitle, "Verified!"); assert(dialogSubTitle, "Verified!");
} }
async function startVerification(session, name) { async function startVerification(session, name) {
await openMemberInfo(session, name); await openMemberInfo(session, name);
// click verify in member info // click verify in member info
const firstVerifyButton = await session.waitAndQuery(".mx_MemberDeviceInfo_verify"); const firstVerifyButton = await session.query(".mx_MemberDeviceInfo_verify");
await firstVerifyButton.click(); await firstVerifyButton.click();
} }
async function getSasCodes(session) { async function getSasCodes(session) {
const sasLabelElements = await session.waitAndQueryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label"); const sasLabelElements = await session.queryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label");
const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e))); const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e)));
return sasLabels; return sasLabels;
} }
@ -53,7 +53,7 @@ module.exports.startSasVerifcation = async function(session, name) {
module.exports.acceptSasVerification = async function(session, name) { module.exports.acceptSasVerification = async function(session, name) {
await assertDialog(session, "Incoming Verification Request"); await assertDialog(session, "Incoming Verification Request");
const opponentLabelElement = await session.waitAndQuery(".mx_IncomingSasDialog_opponentProfile h2"); const opponentLabelElement = await session.query(".mx_IncomingSasDialog_opponentProfile h2");
const opponentLabel = await session.innerText(opponentLabelElement); const opponentLabel = await session.innerText(opponentLabelElement);
assert(opponentLabel, name); assert(opponentLabel, name);
// click "Continue" button // click "Continue" button