diff --git a/helpers.js b/helpers.js deleted file mode 100644 index e830824e7c..0000000000 --- a/helpers.js +++ /dev/null @@ -1,149 +0,0 @@ -/* -Copyright 2018 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// puppeteer helpers - -// TODO: rename to queryAndInnertext? -async function tryGetInnertext(page, selector) { - const field = await page.$(selector); - if (field != null) { - const text_handle = await field.getProperty('innerText'); - return await text_handle.jsonValue(); - } - return null; -} - -async function innerText(page, field) { - const text_handle = await field.getProperty('innerText'); - return await text_handle.jsonValue(); -} - -async function newPage() { - const page = await browser.newPage(); - await page.setViewport({ - width: 1280, - height: 800 - }); - return page; -} - -function logConsole(page) { - let buffer = ""; - page.on('console', msg => { - buffer += msg.text() + '\n'; - }); - return { - logs() { - return buffer; - } - } -} - -function logXHRRequests(page) { - let buffer = ""; - page.on('requestfinished', async (req) => { - const type = req.resourceType(); - const response = await req.response(); - //if (type === 'xhr' || type === 'fetch') { - buffer += `${type} ${response.status()} ${req.method()} ${req.url()} \n`; - // if (req.method() === "POST") { - // buffer += " Post data: " + req.postData(); - // } - //} - }); - return { - logs() { - return buffer; - } - } -} - -async function getOuterHTML(element_handle) { - const html_handle = await element_handle.getProperty('outerHTML'); - return await html_handle.jsonValue(); -} - -async function printElements(label, elements) { - console.log(label, await Promise.all(elements.map(getOuterHTML))); -} - -async function replaceInputText(input, text) { - // click 3 times to select all text - await input.click({clickCount: 3}); - // then remove it with backspace - await input.press('Backspace'); - // and type the new text - await input.type(text); -} - -// TODO: rename to waitAndQuery(Single)? -async function waitAndQuerySelector(page, selector, timeout = 500) { - await page.waitForSelector(selector, {visible: true, timeout}); - return await page.$(selector); -} - -async function waitAndQueryAll(page, selector, timeout = 500) { - await page.waitForSelector(selector, {visible: true, timeout}); - return await page.$$(selector); -} - -function waitForNewPage(timeout = 500) { - return new Promise((resolve, reject) => { - const timeoutHandle = setTimeout(() => { - browser.removeEventListener('targetcreated', callback); - reject(new Error(`timeout of ${timeout}ms for waitForNewPage elapsed`)); - }, timeout); - - const callback = async (target) => { - clearTimeout(timeoutHandle); - const page = await target.page(); - resolve(page); - }; - - browser.once('targetcreated', callback); - }); -} - -// other helpers - -function randomInt(max) { - return Math.ceil(Math.random()*max); -} - -function riotUrl(path) { - return riotserver + path; -} - -function delay(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -module.exports = { - tryGetInnertext, - innerText, - newPage, - logConsole, - logXHRRequests, - getOuterHTML, - printElements, - replaceInputText, - waitAndQuerySelector, - waitAndQueryAll, - waitForNewPage, - randomInt, - riotUrl, - delay, -} \ No newline at end of file diff --git a/riot/config-template/config.json b/riot/config-template/config.json index 39bbd6490a..6277e567fc 100644 --- a/riot/config-template/config.json +++ b/riot/config-template/config.json @@ -1,5 +1,5 @@ { - "default_hs_url": "http://localhost:8008", + "default_hs_url": "http://localhost:5005", "default_is_url": "https://vector.im", "disable_custom_urls": false, "disable_guests": false, @@ -18,12 +18,12 @@ "default_theme": "light", "roomDirectory": { "servers": [ - "localhost:8008" + "localhost:5005" ] }, "piwik": { "url": "https://piwik.riot.im/", - "whitelistedHSUrls": ["http://localhost:8008"], + "whitelistedHSUrls": ["http://localhost:5005"], "whitelistedISUrls": ["https://vector.im", "https://matrix.org"], "siteId": 1 }, diff --git a/src/scenario.js b/src/scenario.js new file mode 100644 index 0000000000..f035e94c35 --- /dev/null +++ b/src/scenario.js @@ -0,0 +1,57 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +const signup = require('./tests/signup'); +const join = require('./tests/join'); +const sendMessage = require('./tests/send-message'); +const receiveMessage = require('./tests/receive-message'); +const createRoom = require('./tests/create-room'); +const changeRoomSettings = require('./tests/room-settings'); +const acceptServerNoticesInviteAndConsent = require('./tests/server-notices-consent'); + +module.exports = async function scenario(createSession) { + async function createUser(username) { + const session = await createSession(username); + await signup(session, session.username, 'testtest'); + const noticesName = "Server Notices"; + await acceptServerNoticesInviteAndConsent(session, noticesName); + return session; + } + + const alice = await createUser("alice"); + const bob = await createUser("bob"); + + await createDirectoryRoomAndTalk(alice, bob); +} + +async function createDirectoryRoomAndTalk(alice, bob) { + console.log(" creating a public room and join through directory:"); + const room = 'test'; + const message = "hi Alice!"; + await createRoom(alice, room); + await changeRoomSettings(alice, {directory: true, visibility: "public_no_guests"}); + await join(bob, room); + await sendMessage(bob, message); + await receiveMessage(alice, {sender: "bob", body: message}); +} + +async function createE2ERoomAndTalk(alice, bob) { + await createRoom(bob, "secrets"); + await changeRoomSettings(bob, {encryption: true}); + await invite(bob, "@alice:localhost"); + await acceptInvite(alice, "secrets"); +} \ No newline at end of file diff --git a/src/session.js b/src/session.js new file mode 100644 index 0000000000..4f6e04584f --- /dev/null +++ b/src/session.js @@ -0,0 +1,196 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const puppeteer = require('puppeteer'); + +class LogBuffer { + constructor(page, eventName, eventMapper, reduceAsync=false, initialValue = "") { + this.buffer = initialValue; + page.on(eventName, (arg) => { + const result = eventMapper(arg); + if (reduceAsync) { + result.then((r) => this.buffer += r); + } + else { + this.buffer += result; + } + }); + } +} + +class Logger { + constructor(username) { + this.indent = 0; + this.username = username; + } + + startGroup(description) { + const indent = " ".repeat(this.indent * 2); + console.log(`${indent} * ${this.username} ${description}:`); + this.indent += 1; + } + + endGroup() { + this.indent -= 1; + } + + step(description) { + const indent = " ".repeat(this.indent * 2); + process.stdout.write(`${indent} * ${this.username} ${description} ... `); + } + + done(status = "done") { + process.stdout.write(status + "\n"); + } +} + +module.exports = class RiotSession { + constructor(browser, page, username, riotserver) { + this.browser = browser; + this.page = page; + this.riotserver = riotserver; + this.username = username; + this.consoleLog = new LogBuffer(page, "console", (msg) => `${msg.text()}\n`); + this.networkLog = new LogBuffer(page, "requestfinished", async (req) => { + const type = req.resourceType(); + const response = await req.response(); + return `${type} ${response.status()} ${req.method()} ${req.url()} \n`; + }, true); + this.log = new Logger(this.username); + } + + static async create(username, puppeteerOptions, riotserver) { + const browser = await puppeteer.launch(puppeteerOptions); + const page = await browser.newPage(); + await page.setViewport({ + width: 1280, + height: 800 + }); + return new RiotSession(browser, page, username, riotserver); + } + + async tryGetInnertext(selector) { + const field = await this.page.$(selector); + if (field != null) { + const text_handle = await field.getProperty('innerText'); + return await text_handle.jsonValue(); + } + return null; + } + + async getElementProperty(handle, property) { + const propHandle = await handle.getProperty(property); + return await propHandle.jsonValue(); + } + + innerText(field) { + return this.getElementProperty(field, 'innerText'); + } + + getOuterHTML(element_handle) { + return this.getElementProperty(field, 'outerHTML'); + } + + consoleLogs() { + return this.consoleLog.buffer; + } + + networkLogs() { + return this.networkLog.buffer; + } + + logXHRRequests() { + let buffer = ""; + this.page.on('requestfinished', async (req) => { + const type = req.resourceType(); + const response = await req.response(); + //if (type === 'xhr' || type === 'fetch') { + buffer += `${type} ${response.status()} ${req.method()} ${req.url()} \n`; + // if (req.method() === "POST") { + // buffer += " Post data: " + req.postData(); + // } + //} + }); + return { + logs() { + return buffer; + } + } + } + + async printElements(label, elements) { + console.log(label, await Promise.all(elements.map(getOuterHTML))); + } + + async replaceInputText(input, text) { + // click 3 times to select all text + await input.click({clickCount: 3}); + // then remove it with backspace + await input.press('Backspace'); + // and type the new text + await input.type(text); + } + + query(selector) { + return this.page.$(selector); + } + + waitAndQuery(selector, timeout = 500) { + return this.page.waitForSelector(selector, {visible: true, timeout}); + } + + queryAll(selector) { + return this.page.$$(selector); + } + + async waitAndQueryAll(selector, timeout = 500) { + await this.waitAndQuery(selector, timeout); + return await this.queryAll(selector); + } + + waitForNewPage(timeout = 500) { + return new Promise((resolve, reject) => { + const timeoutHandle = setTimeout(() => { + this.browser.removeEventListener('targetcreated', callback); + reject(new Error(`timeout of ${timeout}ms for waitForNewPage elapsed`)); + }, timeout); + + const callback = async (target) => { + clearTimeout(timeoutHandle); + const page = await target.page(); + resolve(page); + }; + + this.browser.once('targetcreated', callback); + }); + } + + goto(url) { + return this.page.goto(url); + } + + url(path) { + return this.riotserver + path; + } + + delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + close() { + return this.browser.close(); + } +} diff --git a/tests/consent.js b/src/tests/consent.js similarity index 70% rename from tests/consent.js rename to src/tests/consent.js index 3c8ada9a5e..cd3d51c1b6 100644 --- a/tests/consent.js +++ b/src/tests/consent.js @@ -14,15 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -const helpers = require('../helpers'); const assert = require('assert'); -module.exports = async function acceptTerms(page) { - const reviewTermsButton = await helpers.waitAndQuerySelector(page, '.mx_QuestionDialog button.mx_Dialog_primary', 5000); - const termsPagePromise = helpers.waitForNewPage(); +module.exports = async function acceptTerms(session) { + const reviewTermsButton = await session.waitAndQuery('.mx_QuestionDialog button.mx_Dialog_primary', 5000); + const termsPagePromise = session.waitForNewPage(); await reviewTermsButton.click(); const termsPage = await termsPagePromise; const acceptButton = await termsPage.$('input[type=submit]'); await acceptButton.click(); - await helpers.delay(500); //TODO yuck, timers + await session.delay(500); //TODO yuck, timers } \ No newline at end of file diff --git a/tests/create-room.js b/src/tests/create-room.js similarity index 57% rename from tests/create-room.js rename to src/tests/create-room.js index 4c9004bcaf..8f5b5c9e85 100644 --- a/tests/create-room.js +++ b/src/tests/create-room.js @@ -14,19 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -const helpers = require('../helpers'); const assert = require('assert'); -module.exports = async function createRoom(page, roomName) { +module.exports = async function createRoom(session, roomName) { + session.log.step(`creates room ${roomName}`); //TODO: brittle selector - const createRoomButton = await helpers.waitAndQuerySelector(page, '.mx_RoleButton[aria-label="Create new room"]'); + const createRoomButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Create new room"]'); await createRoomButton.click(); - const roomNameInput = await helpers.waitAndQuerySelector(page, '.mx_CreateRoomDialog_input'); - await helpers.replaceInputText(roomNameInput, roomName); + const roomNameInput = await session.waitAndQuery('.mx_CreateRoomDialog_input'); + await session.replaceInputText(roomNameInput, roomName); - const createButton = await helpers.waitAndQuerySelector(page, '.mx_Dialog_primary'); + const createButton = await session.waitAndQuery('.mx_Dialog_primary'); await createButton.click(); - await page.waitForSelector('.mx_MessageComposer'); + await session.waitAndQuery('.mx_MessageComposer'); + session.log.done(); } \ No newline at end of file diff --git a/tests/join.js b/src/tests/join.js similarity index 53% rename from tests/join.js rename to src/tests/join.js index ea16a93936..3c76ad2c67 100644 --- a/tests/join.js +++ b/src/tests/join.js @@ -14,22 +14,23 @@ See the License for the specific language governing permissions and limitations under the License. */ -const helpers = require('../helpers'); const assert = require('assert'); -module.exports = async function join(page, roomName) { +module.exports = async function join(session, roomName) { + session.log.step(`joins room ${roomName}`); //TODO: brittle selector - const directoryButton = await helpers.waitAndQuerySelector(page, '.mx_RoleButton[aria-label="Room directory"]'); + const directoryButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Room directory"]'); await directoryButton.click(); - const roomInput = await helpers.waitAndQuerySelector(page, '.mx_DirectorySearchBox_input'); - await helpers.replaceInputText(roomInput, roomName); + const roomInput = await session.waitAndQuery('.mx_DirectorySearchBox_input'); + await session.replaceInputText(roomInput, roomName); - const firstRoomLabel = await helpers.waitAndQuerySelector(page, '.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child'); + const firstRoomLabel = await session.waitAndQuery('.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child', 1000); await firstRoomLabel.click(); - const joinLink = await helpers.waitAndQuerySelector(page, '.mx_RoomPreviewBar_join_text a'); + const joinLink = await session.waitAndQuery('.mx_RoomPreviewBar_join_text a'); await joinLink.click(); - await page.waitForSelector('.mx_MessageComposer'); + await session.waitAndQuery('.mx_MessageComposer'); + session.log.done(); } \ No newline at end of file diff --git a/src/tests/receive-message.js b/src/tests/receive-message.js new file mode 100644 index 0000000000..c84aefcbfd --- /dev/null +++ b/src/tests/receive-message.js @@ -0,0 +1,42 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const assert = require('assert'); + + +async function getMessageFromTile(eventTile) { +} + +module.exports = async function receiveMessage(session, message) { + session.log.step(`receives message "${message.body}" from ${message.sender} in room`); + // wait for a response to come in that contains the message + // crude, but effective + await session.page.waitForResponse(async (response) => { + const body = await response.text(); + return body.indexOf(message.body) !== -1; + }); + // wait a bit for the incoming event to be rendered + await session.delay(100); + let lastTile = await session.query(".mx_EventTile_last"); + const senderElement = await lastTile.$(".mx_SenderProfile_name"); + const bodyElement = await lastTile.$(".mx_EventTile_body"); + const sender = await(await senderElement.getProperty("innerText")).jsonValue(); + const body = await(await bodyElement.getProperty("innerText")).jsonValue(); + + assert.equal(body, message.body); + assert.equal(sender, message.sender); + session.log.done(); +} \ No newline at end of file diff --git a/src/tests/room-settings.js b/src/tests/room-settings.js new file mode 100644 index 0000000000..6001d14d34 --- /dev/null +++ b/src/tests/room-settings.js @@ -0,0 +1,67 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const assert = require('assert'); + +module.exports = async function changeRoomSettings(session, settings) { + session.log.startGroup(`changes the room settings`); + /// XXX delay is needed here, possible because the header is being rerendered + /// click doesn't do anything otherwise + await session.delay(500); + const settingsButton = await session.query(".mx_RoomHeader .mx_AccessibleButton[title=Settings]"); + await settingsButton.click(); + const checks = await session.waitAndQueryAll(".mx_RoomSettings_settings input[type=checkbox]"); + assert.equal(checks.length, 3); + const e2eEncryptionCheck = checks[0]; + const sendToUnverifiedDevices = checks[1]; + const isDirectory = checks[2]; + + if (typeof settings.directory === "boolean") { + session.log.step(`sets directory listing to ${settings.directory}`); + const checked = await session.getElementProperty(isDirectory, "checked"); + assert.equal(typeof checked, "boolean"); + if (checked !== settings.directory) { + await isDirectory.click(); + session.log.done(); + } else { + session.log.done("already set"); + } + } + + if (settings.visibility) { + session.log.step(`sets visibility to ${settings.visibility}`); + const radios = await session.waitAndQueryAll(".mx_RoomSettings_settings input[type=radio]"); + assert.equal(radios.length, 7); + const inviteOnly = radios[0]; + const publicNoGuests = radios[1]; + const publicWithGuests = radios[2]; + + if (settings.visibility === "invite_only") { + await inviteOnly.click(); + } else if (settings.visibility === "public_no_guests") { + await publicNoGuests.click(); + } else if (settings.visibility === "public_with_guests") { + await publicWithGuests.click(); + } else { + throw new Error(`unrecognized room visibility setting: ${settings.visibility}`); + } + session.log.done(); + } + + const saveButton = await session.query(".mx_RoomHeader_wrapper .mx_RoomHeader_textButton"); + await saveButton.click(); + session.log.endGroup(); +} \ No newline at end of file diff --git a/src/tests/send-message.js b/src/tests/send-message.js new file mode 100644 index 0000000000..8a61a15e94 --- /dev/null +++ b/src/tests/send-message.js @@ -0,0 +1,25 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const assert = require('assert'); + +module.exports = async function sendMessage(session, message) { + session.log.step(`writes "${message}" in room`); + const composer = await session.waitAndQuery('.mx_MessageComposer'); + await composer.type(message); + await composer.press("Enter"); + session.log.done(); +} \ No newline at end of file diff --git a/tests/server-notices-consent.js b/src/tests/server-notices-consent.js similarity index 64% rename from tests/server-notices-consent.js rename to src/tests/server-notices-consent.js index 2689036a96..def21d04c3 100644 --- a/tests/server-notices-consent.js +++ b/src/tests/server-notices-consent.js @@ -14,31 +14,33 @@ See the License for the specific language governing permissions and limitations under the License. */ -const helpers = require('../helpers'); const assert = require('assert'); -module.exports = async function acceptServerNoticesInviteAndConsent(page, name) { +module.exports = async function acceptServerNoticesInviteAndConsent(session, noticesName) { + session.log.step(`accepts "${noticesName}" invite and accepting terms & conditions`); //TODO: brittle selector - const invitesHandles = await helpers.waitAndQueryAll(page, '.mx_RoomTile_name.mx_RoomTile_invite'); + const invitesHandles = await session.waitAndQueryAll('.mx_RoomTile_name.mx_RoomTile_invite'); const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => { - const text = await helpers.innerText(page, inviteHandle); + const text = await session.innerText(inviteHandle); return {inviteHandle, text}; })); const inviteHandle = invitesWithText.find(({inviteHandle, text}) => { - return text.trim() === name; + return text.trim() === noticesName; }).inviteHandle; await inviteHandle.click(); - const acceptInvitationLink = await helpers.waitAndQuerySelector(page, ".mx_RoomPreviewBar_join_text a:first-child"); + const acceptInvitationLink = await session.waitAndQuery(".mx_RoomPreviewBar_join_text a:first-child"); await acceptInvitationLink.click(); - const consentLink = await helpers.waitAndQuerySelector(page, ".mx_EventTile_body a", 1000); + const consentLink = await session.waitAndQuery(".mx_EventTile_body a", 1000); - const termsPagePromise = helpers.waitForNewPage(); + const termsPagePromise = session.waitForNewPage(); await consentLink.click(); const termsPage = await termsPagePromise; const acceptButton = await termsPage.$('input[type=submit]'); await acceptButton.click(); - await helpers.delay(500); //TODO yuck, timers -} \ No newline at end of file + await session.delay(500); //TODO yuck, timers + await termsPage.close(); + session.log.done(); +} \ No newline at end of file diff --git a/tests/signup.js b/src/tests/signup.js similarity index 60% rename from tests/signup.js rename to src/tests/signup.js index 70c478aed1..434083cbb6 100644 --- a/tests/signup.js +++ b/src/tests/signup.js @@ -14,55 +14,56 @@ See the License for the specific language governing permissions and limitations under the License. */ -const helpers = require('../helpers'); const acceptTerms = require('./consent'); const assert = require('assert'); -module.exports = async function signup(page, username, password, homeserver) { - await page.goto(helpers.riotUrl('/#/register')); +module.exports = async function signup(session, username, password, homeserver) { + session.log.step("signs up"); + await session.goto(session.url('/#/register')); //click 'Custom server' radio button if (homeserver) { - const advancedRadioButton = await helpers.waitAndQuerySelector(page, '#advanced'); + const advancedRadioButton = await session.waitAndQuery('#advanced'); await advancedRadioButton.click(); } // wait until register button is visible - await page.waitForSelector('.mx_Login_submit[value=Register]', {visible: true, timeout: 500}); + await session.waitAndQuery('.mx_Login_submit[value=Register]'); //fill out form - const loginFields = await page.$$('.mx_Login_field'); + const loginFields = await session.queryAll('.mx_Login_field'); assert.strictEqual(loginFields.length, 7); const usernameField = loginFields[2]; const passwordField = loginFields[3]; const passwordRepeatField = loginFields[4]; const hsurlField = loginFields[5]; - await helpers.replaceInputText(usernameField, username); - await helpers.replaceInputText(passwordField, password); - await helpers.replaceInputText(passwordRepeatField, password); + await session.replaceInputText(usernameField, username); + await session.replaceInputText(passwordField, password); + await session.replaceInputText(passwordRepeatField, password); if (homeserver) { - await page.waitForSelector('.mx_ServerConfig', {visible: true, timeout: 500}); - await helpers.replaceInputText(hsurlField, homeserver); + await session.waitAndQuery('.mx_ServerConfig'); + await session.replaceInputText(hsurlField, homeserver); } //wait over a second because Registration/ServerConfig have a 1000ms //delay to internally set the homeserver url //see Registration::render and ServerConfig::props::delayTimeMs - await helpers.delay(1200); + await session.delay(1200); /// focus on the button to make sure error validation /// has happened before checking the form is good to go - const registerButton = await page.$('.mx_Login_submit'); + const registerButton = await session.query('.mx_Login_submit'); await registerButton.focus(); //check no errors - const error_text = await helpers.tryGetInnertext(page, '.mx_Login_error'); + const error_text = await session.tryGetInnertext('.mx_Login_error'); assert.strictEqual(!!error_text, false); //submit form //await page.screenshot({path: "beforesubmit.png", fullPage: true}); await registerButton.click(); //confirm dialog saying you cant log back in without e-mail - const continueButton = await helpers.waitAndQuerySelector(page, '.mx_QuestionDialog button.mx_Dialog_primary'); + const continueButton = await session.waitAndQuery('.mx_QuestionDialog button.mx_Dialog_primary'); await continueButton.click(); //wait for registration to finish so the hash gets set //onhashchange better? - await helpers.delay(2000); + await session.delay(2000); - const url = page.url(); - assert.strictEqual(url, helpers.riotUrl('/#/home')); + const url = session.page.url(); + assert.strictEqual(url, session.url('/#/home')); + session.log.done(); } diff --git a/start.js b/start.js index 4912f901c1..11dbe8d2fa 100644 --- a/start.js +++ b/start.js @@ -14,78 +14,60 @@ See the License for the specific language governing permissions and limitations under the License. */ -const puppeteer = require('puppeteer'); -const helpers = require('./helpers'); const assert = require('assert'); +const RiotSession = require('./src/session'); +const scenario = require('./src/scenario'); -const signup = require('./tests/signup'); -const join = require('./tests/join'); -const createRoom = require('./tests/create-room'); -const acceptServerNoticesInviteAndConsent = require('./tests/server-notices-consent'); - -const homeserver = 'http://localhost:8008'; - -global.riotserver = 'http://localhost:5000'; -global.browser = null; - -let consoleLogs = null; -let xhrLogs = null; -let globalPage = null; +const riotserver = 'http://localhost:5000'; async function runTests() { + let sessions = []; + console.log("running tests ..."); const options = {}; + // options.headless = false; if (process.env.CHROME_PATH) { const path = process.env.CHROME_PATH; console.log(`(using external chrome/chromium at ${path}, make sure it's compatible with puppeteer)`); options.executablePath = path; } - global.browser = await puppeteer.launch(options); - const page = await helpers.newPage(); - globalPage = page; - consoleLogs = helpers.logConsole(page); - xhrLogs = helpers.logXHRRequests(page); - - const username = 'user-' + helpers.randomInt(10000); - const password = 'testtest'; - process.stdout.write(`* signing up as ${username} ... `); - await signup(page, username, password); - process.stdout.write('done\n'); - - const noticesName = "Server Notices"; - process.stdout.write(`* accepting "${noticesName}" and accepting terms & conditions ... `); - await acceptServerNoticesInviteAndConsent(page, noticesName); - process.stdout.write('done\n'); - - const room = 'test'; - process.stdout.write(`* creating room ${room} ... `); - await createRoom(page, room); - process.stdout.write('done\n'); - - await browser.close(); -} - -function onSuccess() { - console.log('all tests finished successfully'); -} - -async function onFailure(err) { - - let documentHtml = "no page"; - if (globalPage) { - documentHtml = await globalPage.content(); + async function createSession(username) { + const session = await RiotSession.create(username, options, riotserver); + sessions.push(session); + return session; } - console.log('failure: ', err); - console.log('console.log output:'); - console.log(consoleLogs.logs()); - console.log('XHR requests:'); - console.log(xhrLogs.logs()); - console.log('document html:'); - console.log(documentHtml); - - process.exit(-1); + let failure = false; + try { + await scenario(createSession); + } catch(err) { + failure = true; + console.log('failure: ', err); + for(let i = 0; i < sessions.length; ++i) { + const session = sessions[i]; + documentHtml = await session.page.content(); + console.log(`---------------- START OF ${session.username} LOGS ----------------`); + console.log('---------------- console.log output:'); + console.log(session.consoleLogs()); + console.log('---------------- network requests:'); + console.log(session.networkLogs()); + console.log('---------------- document html:'); + console.log(documentHtml); + console.log(`---------------- END OF ${session.username} LOGS ----------------`); + } + } + + await Promise.all(sessions.map((session) => session.close())); + + if (failure) { + process.exit(-1); + } else { + console.log('all tests finished successfully'); + } } -runTests().then(onSuccess, onFailure); \ No newline at end of file +runTests().catch(function(err) { + console.log(err); + process.exit(-1); +}); \ No newline at end of file diff --git a/synapse/config-templates/consent/homeserver.yaml b/synapse/config-templates/consent/homeserver.yaml index a27fbf6f10..38aa4747b5 100644 --- a/synapse/config-templates/consent/homeserver.yaml +++ b/synapse/config-templates/consent/homeserver.yaml @@ -86,7 +86,7 @@ web_client: True # web_client_location: "/path/to/web/root" # The public-facing base URL for the client API (not including _matrix/...) -public_baseurl: http://localhost:8008/ +public_baseurl: http://localhost:{{SYNAPSE_PORT}}/ # Set the soft limit on the number of file descriptors synapse can use # Zero is used to indicate synapse should set the soft limit to the @@ -166,7 +166,7 @@ listeners: # Unsecure HTTP listener, # For when matrix traffic passes through loadbalancer that unwraps TLS. - - port: 8008 + - port: {{SYNAPSE_PORT}} tls: false bind_addresses: ['::', '0.0.0.0'] type: http @@ -693,5 +693,5 @@ user_consent: server_notices: system_mxid_localpart: notices system_mxid_display_name: "Server Notices" - system_mxid_avatar_url: "mxc://localhost:8008/oumMVlgDnLYFaPVkExemNVVZ" + system_mxid_avatar_url: "mxc://localhost:{{SYNAPSE_PORT}}/oumMVlgDnLYFaPVkExemNVVZ" room_name: "Server Notices" diff --git a/synapse/install.sh b/synapse/install.sh index dc4a08cb41..2e9b668b5e 100755 --- a/synapse/install.sh +++ b/synapse/install.sh @@ -4,7 +4,7 @@ SYNAPSE_BRANCH=master INSTALLATION_NAME=consent SERVER_DIR=installations/$INSTALLATION_NAME CONFIG_TEMPLATE=consent -PORT=8008 +PORT=5005 # set current directory to script directory BASE_DIR=$(readlink -f $(dirname $0)) @@ -33,7 +33,7 @@ python -m synapse.app.homeserver \ # apply configuration cp -r $BASE_DIR/config-templates/$CONFIG_TEMPLATE/. ./ sed -i "s#{{SYNAPSE_ROOT}}#$(pwd)/#g" homeserver.yaml -sed -i "s#{{SYNAPSE_PORT}}#${PORT}/#g" homeserver.yaml +sed -i "s#{{SYNAPSE_PORT}}#${PORT}#g" homeserver.yaml sed -i "s#{{FORM_SECRET}}#$(uuidgen)#g" homeserver.yaml sed -i "s#{{REGISTRATION_SHARED_SECRET}}#$(uuidgen)#g" homeserver.yaml sed -i "s#{{MACAROON_SECRET_KEY}}#$(uuidgen)#g" homeserver.yaml