Merge pull request #4 from matrix-org/bwindels/2usersjoin
Support multiple users, have 2nd user join created roompull/21833/head
						commit
						4c3386a2a5
					
				
							
								
								
									
										149
									
								
								helpers.js
								
								
								
								
							
							
						
						
									
										149
									
								
								helpers.js
								
								
								
								
							|  | @ -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, | ||||
| } | ||||
|  | @ -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 | ||||
|     }, | ||||
|  |  | |||
|  | @ -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"); | ||||
| } | ||||
|  | @ -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(); | ||||
|   } | ||||
| } | ||||
|  | @ -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
 | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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
 | ||||
| }  | ||||
|   await session.delay(500); //TODO yuck, timers
 | ||||
|   await termsPage.close(); | ||||
|   session.log.done(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
							
								
								
									
										100
									
								
								start.js
								
								
								
								
							
							
						
						
									
										100
									
								
								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); | ||||
| runTests().catch(function(err) { | ||||
|   console.log(err); | ||||
|   process.exit(-1); | ||||
| }); | ||||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Bruno Windels
						Bruno Windels