mirror of https://github.com/vector-im/riot-web
				
				
				
			bring indentation in line with other front-end projects
							parent
							
								
									2c983f8cee
								
							
						
					
					
						commit
						377a20fffa
					
				|  | @ -0,0 +1,23 @@ | |||
| #   Copyright 2017 Aviral Dasgupta | ||||
| # | ||||
| #   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. | ||||
| 
 | ||||
| root = true | ||||
| 
 | ||||
| [*] | ||||
| charset=utf-8 | ||||
| end_of_line = lf | ||||
| insert_final_newline = true | ||||
| indent_style = space | ||||
| indent_size = 4 | ||||
| trim_trailing_whitespace = true | ||||
							
								
								
									
										24
									
								
								package.json
								
								
								
								
							
							
						
						
									
										24
									
								
								package.json
								
								
								
								
							|  | @ -1,14 +1,14 @@ | |||
| { | ||||
|   "name": "e2e-tests", | ||||
|   "version": "1.0.0", | ||||
|   "description": "", | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|     "test": "echo \"Error: no test specified\" && exit 1" | ||||
|   }, | ||||
|   "author": "", | ||||
|   "license": "ISC", | ||||
|   "dependencies": { | ||||
|     "puppeteer": "^1.6.0" | ||||
|   } | ||||
|     "name": "e2e-tests", | ||||
|     "version": "1.0.0", | ||||
|     "description": "", | ||||
|     "main": "index.js", | ||||
|     "scripts": { | ||||
|         "test": "echo \"Error: no test specified\" && exit 1" | ||||
|     }, | ||||
|     "author": "", | ||||
|     "license": "ISC", | ||||
|     "dependencies": { | ||||
|         "puppeteer": "^1.6.0" | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ RIOT_BRANCH=master | |||
| 
 | ||||
| BASE_DIR=$(readlink -f $(dirname $0)) | ||||
| if [ -d $BASE_DIR/riot-web ]; then | ||||
| 	echo "riot is already installed" | ||||
| 	exit | ||||
|     echo "riot is already installed" | ||||
|     exit | ||||
| fi | ||||
| 
 | ||||
| cd $BASE_DIR | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ PIDFILE=$BASE_DIR/riot.pid | |||
| CONFIG_BACKUP=config.e2etests_backup.json | ||||
| 
 | ||||
| if [ -f $PIDFILE ]; then | ||||
| 	exit | ||||
|     exit | ||||
| fi | ||||
| 
 | ||||
| cd $BASE_DIR/ | ||||
|  | @ -14,29 +14,29 @@ pushd riot-web/webapp/ > /dev/null | |||
| 
 | ||||
| # backup config file before we copy template | ||||
| if [ -f config.json ]; then | ||||
| 	mv config.json $CONFIG_BACKUP | ||||
|     mv config.json $CONFIG_BACKUP | ||||
| fi | ||||
| cp $BASE_DIR/config-template/config.json . | ||||
| 
 | ||||
| LOGFILE=$(mktemp) | ||||
| # run web server in the background, showing output on error | ||||
| ( | ||||
| 	python -m SimpleHTTPServer $PORT > $LOGFILE 2>&1 & | ||||
| 	PID=$! | ||||
| 	echo $PID > $PIDFILE | ||||
| 	# wait so subshell does not exit | ||||
| 	# otherwise sleep below would not work | ||||
| 	wait $PID; RESULT=$? | ||||
|     python -m SimpleHTTPServer $PORT > $LOGFILE 2>&1 & | ||||
|     PID=$! | ||||
|     echo $PID > $PIDFILE | ||||
|     # wait so subshell does not exit | ||||
|     # otherwise sleep below would not work | ||||
|     wait $PID; RESULT=$? | ||||
| 
 | ||||
| 	# NOT expected SIGTERM (128 + 15) | ||||
| 	# from stop.sh? | ||||
| 	if [ $RESULT -ne 143 ]; then | ||||
| 		echo "failed" | ||||
| 		cat $LOGFILE | ||||
| 		rm $PIDFILE 2> /dev/null | ||||
| 	fi | ||||
| 	rm $LOGFILE | ||||
| 	exit $RESULT | ||||
|     # NOT expected SIGTERM (128 + 15) | ||||
|     # from stop.sh? | ||||
|     if [ $RESULT -ne 143 ]; then | ||||
|         echo "failed" | ||||
|         cat $LOGFILE | ||||
|         rm $PIDFILE 2> /dev/null | ||||
|     fi | ||||
|     rm $LOGFILE | ||||
|     exit $RESULT | ||||
| )& | ||||
| # to be able to return the exit code for immediate errors (like address already in use) | ||||
| # we wait for a short amount of time in the background and exit when the first | ||||
|  | @ -46,6 +46,6 @@ sleep 0.5 & | |||
| wait -n; RESULT=$? | ||||
| # return exit code of first child to exit | ||||
| if [ $RESULT -eq 0 ]; then | ||||
| 	echo "running" | ||||
|     echo "running" | ||||
| fi | ||||
| exit $RESULT | ||||
|  |  | |||
							
								
								
									
										20
									
								
								riot/stop.sh
								
								
								
								
							
							
						
						
									
										20
									
								
								riot/stop.sh
								
								
								
								
							|  | @ -6,15 +6,15 @@ CONFIG_BACKUP=config.e2etests_backup.json | |||
| cd $BASE_DIR | ||||
| 
 | ||||
| if [ -f $PIDFILE ]; then | ||||
| 	echo "stopping riot server ..." | ||||
| 	PID=$(cat $PIDFILE) | ||||
| 	rm $PIDFILE | ||||
| 	kill $PID | ||||
|     echo "stopping riot server ..." | ||||
|     PID=$(cat $PIDFILE) | ||||
|     rm $PIDFILE | ||||
|     kill $PID | ||||
| 
 | ||||
| 	# revert config file | ||||
| 	cd riot-web/webapp | ||||
| 	rm config.json | ||||
| 	if [ -f $CONFIG_BACKUP ]; then | ||||
| 		mv $CONFIG_BACKUP config.json | ||||
| 	fi | ||||
|     # revert config file | ||||
|     cd riot-web/webapp | ||||
|     rm config.json | ||||
|     if [ -f $CONFIG_BACKUP ]; then | ||||
|         mv $CONFIG_BACKUP config.json | ||||
|     fi | ||||
| fi | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -29,57 +29,57 @@ const getE2EDeviceFromSettings = require('./tests/e2e-device'); | |||
| const verifyDeviceForUser = require("./tests/verify-device"); | ||||
| 
 | ||||
| module.exports = async function scenario(createSession) { | ||||
|   async function createUser(username) { | ||||
|     const session = await createSession(username); | ||||
|     await signup(session, session.username, 'testtest'); | ||||
|     await acceptServerNoticesInviteAndConsent(session); | ||||
|     return session; | ||||
|   } | ||||
|     async function createUser(username) { | ||||
|         const session = await createSession(username); | ||||
|         await signup(session, session.username, 'testtest'); | ||||
|         await acceptServerNoticesInviteAndConsent(session); | ||||
|         return session; | ||||
|     } | ||||
| 
 | ||||
|   const alice = await createUser("alice"); | ||||
|   const bob = await createUser("bob"); | ||||
|     const alice = await createUser("alice"); | ||||
|     const bob = await createUser("bob"); | ||||
| 
 | ||||
|   await createDirectoryRoomAndTalk(alice, bob); | ||||
|   await createE2ERoomAndTalk(alice, bob); | ||||
|     await createDirectoryRoomAndTalk(alice, bob); | ||||
|     await createE2ERoomAndTalk(alice, bob); | ||||
| } | ||||
| 
 | ||||
| async function createDirectoryRoomAndTalk(alice, bob) { | ||||
|   console.log(" creating a public room and join through directory:"); | ||||
|   const room = 'test'; | ||||
|   await createRoom(alice, room); | ||||
|   await changeRoomSettings(alice, {directory: true, visibility: "public_no_guests"}); | ||||
|   await join(bob, room); | ||||
|   const bobMessage = "hi Alice!"; | ||||
|   await sendMessage(bob, bobMessage); | ||||
|   await receiveMessage(alice, {sender: "bob", body: bobMessage}); | ||||
|   const aliceMessage = "hi Bob, welcome!" | ||||
|   await sendMessage(alice, aliceMessage); | ||||
|   await receiveMessage(bob, {sender: "alice", body: aliceMessage}); | ||||
|     console.log(" creating a public room and join through directory:"); | ||||
|     const room = 'test'; | ||||
|     await createRoom(alice, room); | ||||
|     await changeRoomSettings(alice, {directory: true, visibility: "public_no_guests"}); | ||||
|     await join(bob, room); | ||||
|     const bobMessage = "hi Alice!"; | ||||
|     await sendMessage(bob, bobMessage); | ||||
|     await receiveMessage(alice, {sender: "bob", body: bobMessage}); | ||||
|     const aliceMessage = "hi Bob, welcome!" | ||||
|     await sendMessage(alice, aliceMessage); | ||||
|     await receiveMessage(bob, {sender: "alice", body: aliceMessage}); | ||||
| } | ||||
| 
 | ||||
| async function createE2ERoomAndTalk(alice, bob) { | ||||
|   console.log(" creating an e2e encrypted room and join through invite:"); | ||||
|   const room = "secrets"; | ||||
|   await createRoom(bob, room); | ||||
|   await changeRoomSettings(bob, {encryption: true}); | ||||
|   await invite(bob, "@alice:localhost"); | ||||
|   await acceptInvite(alice, room); | ||||
|   const bobDevice = await getE2EDeviceFromSettings(bob); | ||||
|   // wait some time for the encryption warning dialog
 | ||||
|   // to appear after closing the settings
 | ||||
|   await bob.delay(500); | ||||
|   await acceptDialog(bob, "encryption"); | ||||
|   const aliceDevice = await getE2EDeviceFromSettings(alice); | ||||
|   // wait some time for the encryption warning dialog
 | ||||
|   // to appear after closing the settings
 | ||||
|   await alice.delay(500); | ||||
|   await acceptDialog(alice, "encryption"); | ||||
|   await verifyDeviceForUser(bob, "alice", aliceDevice); | ||||
|   await verifyDeviceForUser(alice, "bob", bobDevice); | ||||
|   const aliceMessage = "Guess what I just heard?!" | ||||
|   await sendMessage(alice, aliceMessage); | ||||
|   await receiveMessage(bob, {sender: "alice", body: aliceMessage, encrypted: true}); | ||||
|   const bobMessage = "You've got to tell me!"; | ||||
|   await sendMessage(bob, bobMessage); | ||||
|   await receiveMessage(alice, {sender: "bob", body: bobMessage, encrypted: true}); | ||||
|     console.log(" creating an e2e encrypted room and join through invite:"); | ||||
|     const room = "secrets"; | ||||
|     await createRoom(bob, room); | ||||
|     await changeRoomSettings(bob, {encryption: true}); | ||||
|     await invite(bob, "@alice:localhost"); | ||||
|     await acceptInvite(alice, room); | ||||
|     const bobDevice = await getE2EDeviceFromSettings(bob); | ||||
|     // wait some time for the encryption warning dialog
 | ||||
|     // to appear after closing the settings
 | ||||
|     await bob.delay(500); | ||||
|     await acceptDialog(bob, "encryption"); | ||||
|     const aliceDevice = await getE2EDeviceFromSettings(alice); | ||||
|     // wait some time for the encryption warning dialog
 | ||||
|     // to appear after closing the settings
 | ||||
|     await alice.delay(500); | ||||
|     await acceptDialog(alice, "encryption"); | ||||
|     await verifyDeviceForUser(bob, "alice", aliceDevice); | ||||
|     await verifyDeviceForUser(alice, "bob", bobDevice); | ||||
|     const aliceMessage = "Guess what I just heard?!" | ||||
|     await sendMessage(alice, aliceMessage); | ||||
|     await receiveMessage(bob, {sender: "alice", body: aliceMessage, encrypted: true}); | ||||
|     const bobMessage = "You've got to tell me!"; | ||||
|     await sendMessage(bob, bobMessage); | ||||
|     await receiveMessage(alice, {sender: "bob", body: bobMessage, encrypted: true}); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										304
									
								
								src/session.js
								
								
								
								
							
							
						
						
									
										304
									
								
								src/session.js
								
								
								
								
							|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,180 +17,180 @@ 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; | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|     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; | ||||
|   } | ||||
|     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; | ||||
|   } | ||||
|     startGroup(description) { | ||||
|         const indent = " ".repeat(this.indent * 2); | ||||
|         console.log(`${indent} * ${this.username} ${description}:`); | ||||
|         this.indent += 1; | ||||
|     } | ||||
| 
 | ||||
|   endGroup() { | ||||
|     this.indent -= 1; | ||||
|   } | ||||
|     endGroup() { | ||||
|         this.indent -= 1; | ||||
|     } | ||||
| 
 | ||||
|   step(description) { | ||||
|     const indent = " ".repeat(this.indent * 2); | ||||
|     process.stdout.write(`${indent} * ${this.username} ${description} ... `); | ||||
|   } | ||||
|     step(description) { | ||||
|         const indent = " ".repeat(this.indent * 2); | ||||
|         process.stdout.write(`${indent} * ${this.username} ${description} ... `); | ||||
|     } | ||||
| 
 | ||||
|   done(status = "done") { | ||||
|     process.stdout.write(status + "\n"); | ||||
|   } | ||||
|     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(); | ||||
|     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); | ||||
|     } | ||||
|     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; | ||||
|       } | ||||
|     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 printElements(label, elements) { | ||||
|     console.log(label, await Promise.all(elements.map(getOuterHTML))); | ||||
|   } | ||||
|     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 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); | ||||
|   } | ||||
|     async getElementProperty(handle, property) { | ||||
|         const propHandle = await handle.getProperty(property); | ||||
|         return await propHandle.jsonValue(); | ||||
|     } | ||||
| 
 | ||||
|   query(selector) { | ||||
|     return this.page.$(selector);   | ||||
|   } | ||||
|    | ||||
|   waitAndQuery(selector, timeout = 500) { | ||||
|     return this.page.waitForSelector(selector, {visible: true, timeout}); | ||||
|   } | ||||
|     innerText(field) { | ||||
|         return this.getElementProperty(field, 'innerText'); | ||||
|     } | ||||
| 
 | ||||
|   queryAll(selector) { | ||||
|     return this.page.$$(selector);   | ||||
|   } | ||||
|     getOuterHTML(element_handle) { | ||||
|         return this.getElementProperty(field, 'outerHTML'); | ||||
|     } | ||||
| 
 | ||||
|   async waitAndQueryAll(selector, timeout = 500) { | ||||
|     await this.waitAndQuery(selector, timeout); | ||||
|     return await this.queryAll(selector); | ||||
|   } | ||||
|     consoleLogs() { | ||||
|         return this.consoleLog.buffer; | ||||
|     } | ||||
| 
 | ||||
|   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); | ||||
|     networkLogs() { | ||||
|         return this.networkLog.buffer; | ||||
|     } | ||||
| 
 | ||||
|       const callback = async (target) => { | ||||
|         clearTimeout(timeoutHandle); | ||||
|         const page = await target.page(); | ||||
|         resolve(page); | ||||
|       }; | ||||
|     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; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|       this.browser.once('targetcreated', callback); | ||||
|     }); | ||||
|   } | ||||
|     async printElements(label, elements) { | ||||
|         console.log(label, await Promise.all(elements.map(getOuterHTML))); | ||||
|     } | ||||
| 
 | ||||
|   goto(url) { | ||||
|     return this.page.goto(url); | ||||
|   } | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
|   url(path) { | ||||
|     return this.riotserver + path; | ||||
|   } | ||||
|     query(selector) { | ||||
|         return this.page.$(selector); | ||||
|     } | ||||
| 
 | ||||
|   delay(ms) { | ||||
|     return new Promise(resolve => setTimeout(resolve, ms)); | ||||
|   } | ||||
|     waitAndQuery(selector, timeout = 500) { | ||||
|         return this.page.waitForSelector(selector, {visible: true, timeout}); | ||||
|     } | ||||
| 
 | ||||
|   close() { | ||||
|     return this.browser.close(); | ||||
|   } | ||||
|     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(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -18,24 +18,24 @@ const assert = require('assert'); | |||
| const {acceptDialogMaybe} = require('./dialog'); | ||||
| 
 | ||||
| module.exports = async function acceptInvite(session, name) { | ||||
|   session.log.step(`accepts "${name}" invite`); | ||||
|   //TODO: brittle selector
 | ||||
|   const invitesHandles = await session.waitAndQueryAll('.mx_RoomTile_name.mx_RoomTile_invite', 1000); | ||||
|   const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => { | ||||
|   	const text = await session.innerText(inviteHandle); | ||||
|   	return {inviteHandle, text}; | ||||
|   })); | ||||
|   const inviteHandle = invitesWithText.find(({inviteHandle, text}) => { | ||||
| 	return text.trim() === name; | ||||
|   }).inviteHandle; | ||||
|     session.log.step(`accepts "${name}" invite`); | ||||
|     //TODO: brittle selector
 | ||||
|     const invitesHandles = await session.waitAndQueryAll('.mx_RoomTile_name.mx_RoomTile_invite', 1000); | ||||
|     const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => { | ||||
|         const text = await session.innerText(inviteHandle); | ||||
|         return {inviteHandle, text}; | ||||
|     })); | ||||
|     const inviteHandle = invitesWithText.find(({inviteHandle, text}) => { | ||||
|     return text.trim() === name; | ||||
|     }).inviteHandle; | ||||
| 
 | ||||
|   await inviteHandle.click(); | ||||
|     await inviteHandle.click(); | ||||
| 
 | ||||
|   const acceptInvitationLink = await session.waitAndQuery(".mx_RoomPreviewBar_join_text a:first-child"); | ||||
|   await acceptInvitationLink.click(); | ||||
|     const acceptInvitationLink = await session.waitAndQuery(".mx_RoomPreviewBar_join_text a:first-child"); | ||||
|     await acceptInvitationLink.click(); | ||||
| 
 | ||||
|   // accept e2e warning dialog
 | ||||
|   acceptDialogMaybe(session, "encryption"); | ||||
|     // accept e2e warning dialog
 | ||||
|     acceptDialogMaybe(session, "encryption"); | ||||
| 
 | ||||
|   session.log.done(); | ||||
|     session.log.done(); | ||||
| } | ||||
|  | @ -17,11 +17,11 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| 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 session.delay(500); //TODO yuck, timers
 | ||||
|     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 session.delay(500); //TODO yuck, timers
 | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,17 +17,17 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| module.exports = async function createRoom(session, roomName) { | ||||
|   session.log.step(`creates room "${roomName}"`); | ||||
|   //TODO: brittle selector
 | ||||
|   const createRoomButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Create new room"]'); | ||||
|   await createRoomButton.click(); | ||||
|     session.log.step(`creates room "${roomName}"`); | ||||
|     //TODO: brittle selector
 | ||||
|     const createRoomButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Create new room"]'); | ||||
|     await createRoomButton.click(); | ||||
| 
 | ||||
|   const roomNameInput = await session.waitAndQuery('.mx_CreateRoomDialog_input'); | ||||
|   await session.replaceInputText(roomNameInput, roomName); | ||||
|     const roomNameInput = await session.waitAndQuery('.mx_CreateRoomDialog_input'); | ||||
|     await session.replaceInputText(roomNameInput, roomName); | ||||
| 
 | ||||
|   const createButton = await session.waitAndQuery('.mx_Dialog_primary'); | ||||
|   await createButton.click(); | ||||
|     const createButton = await session.waitAndQuery('.mx_Dialog_primary'); | ||||
|     await createButton.click(); | ||||
| 
 | ||||
|   await session.waitAndQuery('.mx_MessageComposer'); | ||||
|   session.log.done(); | ||||
|     await session.waitAndQuery('.mx_MessageComposer'); | ||||
|     session.log.done(); | ||||
| } | ||||
|  | @ -18,30 +18,30 @@ const assert = require('assert'); | |||
| 
 | ||||
| 
 | ||||
| async function acceptDialog(session, expectedContent) { | ||||
| 	const foundDialog = await acceptDialogMaybe(session, expectedContent); | ||||
| 	if (!foundDialog) { | ||||
| 		throw new Error("could not find a dialog"); | ||||
| 	} | ||||
|     const foundDialog = await acceptDialogMaybe(session, expectedContent); | ||||
|     if (!foundDialog) { | ||||
|         throw new Error("could not find a dialog"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async function acceptDialogMaybe(session, expectedContent) { | ||||
| 	let dialog = null; | ||||
| 	try { | ||||
| 		dialog = await session.waitAndQuery(".mx_QuestionDialog", 100); | ||||
| 	} catch(err) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (expectedContent) { | ||||
| 		const contentElement = await dialog.$(".mx_Dialog_content"); | ||||
| 		const content = await (await contentElement.getProperty("innerText")).jsonValue(); | ||||
| 		assert.ok(content.indexOf(expectedContent) !== -1); | ||||
| 	} | ||||
| 	const primaryButton = await dialog.$(".mx_Dialog_primary"); | ||||
| 	await primaryButton.click(); | ||||
| 	return true; | ||||
|     let dialog = null; | ||||
|     try { | ||||
|         dialog = await session.waitAndQuery(".mx_QuestionDialog", 100); | ||||
|     } catch(err) { | ||||
|         return false; | ||||
|     } | ||||
|     if (expectedContent) { | ||||
|         const contentElement = await dialog.$(".mx_Dialog_content"); | ||||
|         const content = await (await contentElement.getProperty("innerText")).jsonValue(); | ||||
|         assert.ok(content.indexOf(expectedContent) !== -1); | ||||
|     } | ||||
|     const primaryButton = await dialog.$(".mx_Dialog_primary"); | ||||
|     await primaryButton.click(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| 	acceptDialog, | ||||
| 	acceptDialogMaybe, | ||||
|     acceptDialog, | ||||
|     acceptDialogMaybe, | ||||
| }; | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,15 +17,15 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| module.exports = async function getE2EDeviceFromSettings(session) { | ||||
|   session.log.step(`gets e2e device/key from settings`); | ||||
|   const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); | ||||
|   await settingsButton.click(); | ||||
|   const deviceAndKey = await session.waitAndQueryAll(".mx_UserSettings_section.mx_UserSettings_cryptoSection code"); | ||||
|   assert.equal(deviceAndKey.length, 2); | ||||
|   const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue(); | ||||
|   const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue(); | ||||
|   const closeButton = await session.query(".mx_RoomHeader_cancelButton"); | ||||
|   await closeButton.click(); | ||||
|   session.log.done(); | ||||
|   return {id, key}; | ||||
|     session.log.step(`gets e2e device/key from settings`); | ||||
|     const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); | ||||
|     await settingsButton.click(); | ||||
|     const deviceAndKey = await session.waitAndQueryAll(".mx_UserSettings_section.mx_UserSettings_cryptoSection code"); | ||||
|     assert.equal(deviceAndKey.length, 2); | ||||
|     const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue(); | ||||
|     const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue(); | ||||
|     const closeButton = await session.query(".mx_RoomHeader_cancelButton"); | ||||
|     await closeButton.click(); | ||||
|     session.log.done(); | ||||
|     return {id, key}; | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,14 +17,14 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| module.exports = async function invite(session, userId) { | ||||
|   session.log.step(`invites "${userId}" to room`); | ||||
|   await session.delay(200); | ||||
|   const inviteButton = await session.waitAndQuery(".mx_RightPanel_invite"); | ||||
|   await inviteButton.click(); | ||||
|   const inviteTextArea = await session.waitAndQuery(".mx_ChatInviteDialog textarea"); | ||||
|   await inviteTextArea.type(userId); | ||||
|   await inviteTextArea.press("Enter"); | ||||
|   const confirmButton = await session.query(".mx_Dialog_primary"); | ||||
|   await confirmButton.click(); | ||||
|   session.log.done(); | ||||
|     session.log.step(`invites "${userId}" to room`); | ||||
|     await session.delay(200); | ||||
|     const inviteButton = await session.waitAndQuery(".mx_RightPanel_invite"); | ||||
|     await inviteButton.click(); | ||||
|     const inviteTextArea = await session.waitAndQuery(".mx_ChatInviteDialog textarea"); | ||||
|     await inviteTextArea.type(userId); | ||||
|     await inviteTextArea.press("Enter"); | ||||
|     const confirmButton = await session.query(".mx_Dialog_primary"); | ||||
|     await confirmButton.click(); | ||||
|     session.log.done(); | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,20 +17,20 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| module.exports = async function join(session, roomName) { | ||||
|   session.log.step(`joins room "${roomName}"`); | ||||
|   //TODO: brittle selector
 | ||||
|   const directoryButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Room directory"]'); | ||||
|   await directoryButton.click(); | ||||
|     session.log.step(`joins room "${roomName}"`); | ||||
|     //TODO: brittle selector
 | ||||
|     const directoryButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Room directory"]'); | ||||
|     await directoryButton.click(); | ||||
| 
 | ||||
|   const roomInput = await session.waitAndQuery('.mx_DirectorySearchBox_input'); | ||||
|   await session.replaceInputText(roomInput, roomName); | ||||
|     const roomInput = await session.waitAndQuery('.mx_DirectorySearchBox_input'); | ||||
|     await session.replaceInputText(roomInput, roomName); | ||||
| 
 | ||||
|   const firstRoomLabel = await session.waitAndQuery('.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child', 1000); | ||||
|   await firstRoomLabel.click(); | ||||
|     const firstRoomLabel = await session.waitAndQuery('.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child', 1000); | ||||
|     await firstRoomLabel.click(); | ||||
| 
 | ||||
|   const joinLink = await session.waitAndQuery('.mx_RoomPreviewBar_join_text a'); | ||||
|   await joinLink.click(); | ||||
|     const joinLink = await session.waitAndQuery('.mx_RoomPreviewBar_join_text a'); | ||||
|     await joinLink.click(); | ||||
| 
 | ||||
|   await session.waitAndQuery('.mx_MessageComposer'); | ||||
|   session.log.done(); | ||||
|     await session.waitAndQuery('.mx_MessageComposer'); | ||||
|     session.log.done(); | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,33 +17,33 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| module.exports = async function receiveMessage(session, message) { | ||||
|   session.log.step(`receives message "${message.body}" from ${message.sender}`); | ||||
|   // wait for a response to come in that contains the message
 | ||||
|   // crude, but effective
 | ||||
|   await session.page.waitForResponse(async (response) => { | ||||
|     if (response.request().url().indexOf("/sync") === -1) { | ||||
|       return false; | ||||
|     } | ||||
|     const body = await response.text(); | ||||
|     session.log.step(`receives message "${message.body}" from ${message.sender}`); | ||||
|     // wait for a response to come in that contains the message
 | ||||
|     // crude, but effective
 | ||||
|     await session.page.waitForResponse(async (response) => { | ||||
|         if (response.request().url().indexOf("/sync") === -1) { | ||||
|             return false; | ||||
|         } | ||||
|         const body = await response.text(); | ||||
|         if (message.encrypted) { | ||||
|             return body.indexOf(message.sender) !== -1 && | ||||
|                          body.indexOf("m.room.encrypted") !== -1; | ||||
|         } else { | ||||
|             return body.indexOf(message.body) !== -1; | ||||
|         } | ||||
|     }); | ||||
|     // wait a bit for the incoming event to be rendered
 | ||||
|     await session.delay(300); | ||||
|     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(); | ||||
|     if (message.encrypted) { | ||||
|       return body.indexOf(message.sender) !== -1 && | ||||
|              body.indexOf("m.room.encrypted") !== -1; | ||||
|     } else { | ||||
|       return body.indexOf(message.body) !== -1; | ||||
|         const e2eIcon = await lastTile.$(".mx_EventTile_e2eIcon"); | ||||
|         assert.ok(e2eIcon); | ||||
|     } | ||||
|   }); | ||||
|   // wait a bit for the incoming event to be rendered
 | ||||
|   await session.delay(300); | ||||
|   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(); | ||||
|   if (message.encrypted) { | ||||
|     const e2eIcon = await lastTile.$(".mx_EventTile_e2eIcon"); | ||||
|     assert.ok(e2eIcon); | ||||
|   } | ||||
|   assert.equal(body, message.body); | ||||
|   assert.equal(sender, message.sender); | ||||
|   session.log.done(); | ||||
|     assert.equal(body, message.body); | ||||
|     assert.equal(sender, message.sender); | ||||
|     session.log.done(); | ||||
| } | ||||
|  | @ -18,66 +18,66 @@ const assert = require('assert'); | |||
| const {acceptDialog} = require('./dialog'); | ||||
| 
 | ||||
| async function setCheckboxSetting(session, checkbox, enabled) { | ||||
| 	const checked = await session.getElementProperty(checkbox, "checked"); | ||||
| 	assert.equal(typeof checked, "boolean"); | ||||
| 	if (checked !== enabled) { | ||||
| 		await checkbox.click(); | ||||
| 		session.log.done(); | ||||
| 		return true; | ||||
| 	} else { | ||||
| 		session.log.done("already set"); | ||||
| 	} | ||||
|     const checked = await session.getElementProperty(checkbox, "checked"); | ||||
|     assert.equal(typeof checked, "boolean"); | ||||
|     if (checked !== enabled) { | ||||
|         await checkbox.click(); | ||||
|         session.log.done(); | ||||
|         return true; | ||||
|     } else { | ||||
|         session.log.done("already set"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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]; | ||||
|     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}`); | ||||
| 		await setCheckboxSetting(session, isDirectory, settings.directory); | ||||
| 	} | ||||
|     if (typeof settings.directory === "boolean") { | ||||
|         session.log.step(`sets directory listing to ${settings.directory}`); | ||||
|         await setCheckboxSetting(session, isDirectory, settings.directory); | ||||
|     } | ||||
| 
 | ||||
| 	if (typeof settings.encryption === "boolean") { | ||||
| 		session.log.step(`sets room e2e encryption to ${settings.encryption}`); | ||||
| 		const clicked = await setCheckboxSetting(session, e2eEncryptionCheck, settings.encryption); | ||||
| 		// if enabling, accept beta warning dialog
 | ||||
| 		if (clicked && settings.encryption) { | ||||
| 			await acceptDialog(session, "encryption"); | ||||
| 		} | ||||
| 	} | ||||
|     if (typeof settings.encryption === "boolean") { | ||||
|         session.log.step(`sets room e2e encryption to ${settings.encryption}`); | ||||
|         const clicked = await setCheckboxSetting(session, e2eEncryptionCheck, settings.encryption); | ||||
|         // if enabling, accept beta warning dialog
 | ||||
|         if (clicked && settings.encryption) { | ||||
|             await acceptDialog(session, "encryption"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	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(); | ||||
| 	} | ||||
|     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(); | ||||
|     const saveButton = await session.query(".mx_RoomHeader_wrapper .mx_RoomHeader_textButton"); | ||||
|     await saveButton.click(); | ||||
| 
 | ||||
| 	session.log.endGroup(); | ||||
|     session.log.endGroup(); | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,13 +17,13 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| module.exports = async function sendMessage(session, message) { | ||||
|   session.log.step(`writes "${message}" in room`); | ||||
|   // this selector needs to be the element that has contenteditable=true,
 | ||||
|   // not any if its parents, otherwise it behaves flaky at best.
 | ||||
|   const composer = await session.waitAndQuery('.mx_MessageComposer_editor'); | ||||
|   await composer.type(message); | ||||
|   const text = await session.innerText(composer); | ||||
|   assert.equal(text.trim(), message.trim()); | ||||
|   await composer.press("Enter"); | ||||
|   session.log.done(); | ||||
|     session.log.step(`writes "${message}" in room`); | ||||
|     // this selector needs to be the element that has contenteditable=true,
 | ||||
|     // not any if its parents, otherwise it behaves flaky at best.
 | ||||
|     const composer = await session.waitAndQuery('.mx_MessageComposer_editor'); | ||||
|     await composer.type(message); | ||||
|     const text = await session.innerText(composer); | ||||
|     assert.equal(text.trim(), message.trim()); | ||||
|     await composer.press("Enter"); | ||||
|     session.log.done(); | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,15 +17,15 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| const acceptInvite = require("./accept-invite") | ||||
| module.exports = async function acceptServerNoticesInviteAndConsent(session) { | ||||
|   await acceptInvite(session, "Server Notices"); | ||||
|   session.log.step(`accepts terms & conditions`); | ||||
|   const consentLink = await session.waitAndQuery(".mx_EventTile_body a", 1000); | ||||
|   const termsPagePromise = session.waitForNewPage(); | ||||
|   await consentLink.click(); | ||||
|   const termsPage = await termsPagePromise; | ||||
|   const acceptButton = await termsPage.$('input[type=submit]'); | ||||
|   await acceptButton.click(); | ||||
|   await session.delay(500); //TODO yuck, timers
 | ||||
|   await termsPage.close(); | ||||
|   session.log.done(); | ||||
|     await acceptInvite(session, "Server Notices"); | ||||
|     session.log.step(`accepts terms & conditions`); | ||||
|     const consentLink = await session.waitAndQuery(".mx_EventTile_body a", 1000); | ||||
|     const termsPagePromise = session.waitForNewPage(); | ||||
|     await consentLink.click(); | ||||
|     const termsPage = await termsPagePromise; | ||||
|     const acceptButton = await termsPage.$('input[type=submit]'); | ||||
|     await acceptButton.click(); | ||||
|     await session.delay(500); //TODO yuck, timers
 | ||||
|     await termsPage.close(); | ||||
|     session.log.done(); | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -18,52 +18,52 @@ const acceptTerms = require('./consent'); | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| 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 session.waitAndQuery('#advanced'); | ||||
|     await advancedRadioButton.click(); | ||||
|   } | ||||
|   // wait until register button is visible
 | ||||
|   await session.waitAndQuery('.mx_Login_submit[value=Register]'); | ||||
|   //fill out form
 | ||||
|   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 session.replaceInputText(usernameField, username); | ||||
|   await session.replaceInputText(passwordField, password); | ||||
|   await session.replaceInputText(passwordRepeatField, password); | ||||
|   if (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 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 session.query('.mx_Login_submit'); | ||||
|   await registerButton.focus(); | ||||
|   //check no errors
 | ||||
|   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(); | ||||
|     session.log.step("signs up"); | ||||
|     await session.goto(session.url('/#/register')); | ||||
|     //click 'Custom server' radio button
 | ||||
|     if (homeserver) { | ||||
|         const advancedRadioButton = await session.waitAndQuery('#advanced'); | ||||
|         await advancedRadioButton.click(); | ||||
|     } | ||||
|     // wait until register button is visible
 | ||||
|     await session.waitAndQuery('.mx_Login_submit[value=Register]'); | ||||
|     //fill out form
 | ||||
|     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 session.replaceInputText(usernameField, username); | ||||
|     await session.replaceInputText(passwordField, password); | ||||
|     await session.replaceInputText(passwordRepeatField, password); | ||||
|     if (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 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 session.query('.mx_Login_submit'); | ||||
|     await registerButton.focus(); | ||||
|     //check no errors
 | ||||
|     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 session.waitAndQuery('.mx_QuestionDialog button.mx_Dialog_primary'); | ||||
|   await continueButton.click(); | ||||
|   //wait for registration to finish so the hash gets set
 | ||||
|   //onhashchange better?
 | ||||
|   await session.delay(2000); | ||||
|     //confirm dialog saying you cant log back in without e-mail
 | ||||
|     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 session.delay(2000); | ||||
| 
 | ||||
|   const url = session.page.url(); | ||||
|   assert.strictEqual(url, session.url('/#/home')); | ||||
|   session.log.done(); | ||||
|     const url = session.page.url(); | ||||
|     assert.strictEqual(url, session.url('/#/home')); | ||||
|     session.log.done(); | ||||
| } | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -17,26 +17,26 @@ limitations under the License. | |||
| const assert = require('assert'); | ||||
| 
 | ||||
| module.exports = async function verifyDeviceForUser(session, name, expectedDevice) { | ||||
|   session.log.step(`verifies e2e device for ${name}`); | ||||
|   const memberNameElements = await session.queryAll(".mx_MemberList .mx_EntityTile_name"); | ||||
|   const membersAndNames = await Promise.all(memberNameElements.map(async (el) => { | ||||
|   	return [el, await session.innerText(el)]; | ||||
|   })); | ||||
|   const matchingMember = membersAndNames.filter(([el, text]) => { | ||||
|   	return text === name; | ||||
|   }).map(([el]) => el)[0]; | ||||
|   await matchingMember.click(); | ||||
|   const firstVerifyButton = await session.waitAndQuery(".mx_MemberDeviceInfo_verify"); | ||||
|   await firstVerifyButton.click(); | ||||
|   const dialogCodeFields = await session.waitAndQueryAll(".mx_QuestionDialog code"); | ||||
|   assert.equal(dialogCodeFields.length, 2); | ||||
|   const deviceId = await session.innerText(dialogCodeFields[0]); | ||||
|   const deviceKey = await session.innerText(dialogCodeFields[1]); | ||||
|   assert.equal(expectedDevice.id, deviceId); | ||||
|   assert.equal(expectedDevice.key, deviceKey); | ||||
|   const confirmButton = await session.query(".mx_Dialog_primary"); | ||||
|   await confirmButton.click(); | ||||
|   const closeMemberInfo = await session.query(".mx_MemberInfo_cancel"); | ||||
|   await closeMemberInfo.click(); | ||||
|   session.log.done(); | ||||
|     session.log.step(`verifies e2e device for ${name}`); | ||||
|     const memberNameElements = await session.queryAll(".mx_MemberList .mx_EntityTile_name"); | ||||
|     const membersAndNames = await Promise.all(memberNameElements.map(async (el) => { | ||||
|         return [el, await session.innerText(el)]; | ||||
|     })); | ||||
|     const matchingMember = membersAndNames.filter(([el, text]) => { | ||||
|         return text === name; | ||||
|     }).map(([el]) => el)[0]; | ||||
|     await matchingMember.click(); | ||||
|     const firstVerifyButton = await session.waitAndQuery(".mx_MemberDeviceInfo_verify"); | ||||
|     await firstVerifyButton.click(); | ||||
|     const dialogCodeFields = await session.waitAndQueryAll(".mx_QuestionDialog code"); | ||||
|     assert.equal(dialogCodeFields.length, 2); | ||||
|     const deviceId = await session.innerText(dialogCodeFields[0]); | ||||
|     const deviceKey = await session.innerText(dialogCodeFields[1]); | ||||
|     assert.equal(expectedDevice.id, deviceId); | ||||
|     assert.equal(expectedDevice.key, deviceKey); | ||||
|     const confirmButton = await session.query(".mx_Dialog_primary"); | ||||
|     await confirmButton.click(); | ||||
|     const closeMemberInfo = await session.query(".mx_MemberInfo_cancel"); | ||||
|     await closeMemberInfo.click(); | ||||
|     session.log.done(); | ||||
| } | ||||
							
								
								
									
										106
									
								
								start.js
								
								
								
								
							
							
						
						
									
										106
									
								
								start.js
								
								
								
								
							|  | @ -5,7 +5,7 @@ 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
 | ||||
|         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, | ||||
|  | @ -24,64 +24,64 @@ const noLogs = process.argv.indexOf("--no-logs") !== -1; | |||
| const debug = process.argv.indexOf("--debug") !== -1; | ||||
| 
 | ||||
| async function runTests() { | ||||
|   let sessions = []; | ||||
|     let sessions = []; | ||||
| 
 | ||||
|   console.log("running tests ..."); | ||||
|   const options = {}; | ||||
|   if (debug) { | ||||
|     // options.slowMo = 10;
 | ||||
|     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; | ||||
|   } | ||||
| 
 | ||||
|   async function createSession(username) { | ||||
|     const session = await RiotSession.create(username, options, riotserver); | ||||
|     sessions.push(session); | ||||
|     return session; | ||||
|   } | ||||
| 
 | ||||
|   let failure = false; | ||||
|   try { | ||||
|     await scenario(createSession); | ||||
|   } catch(err) { | ||||
|     failure = true; | ||||
|     console.log('failure: ', err); | ||||
|     if (!noLogs) { | ||||
|       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   ----------------`); | ||||
|       } | ||||
|     console.log("running tests ..."); | ||||
|     const options = {}; | ||||
|     if (debug) { | ||||
|         options.slowMo = 20; | ||||
|         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; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // wait 5 minutes on failure if not running headless
 | ||||
|   // to inspect what went wrong
 | ||||
|   if (failure && options.headless === false) { | ||||
|     await new Promise((resolve) => setTimeout(resolve, 5 * 60 * 1000)); | ||||
|   } | ||||
|     async function createSession(username) { | ||||
|         const session = await RiotSession.create(username, options, riotserver); | ||||
|         sessions.push(session); | ||||
|         return session; | ||||
|     } | ||||
| 
 | ||||
|   await Promise.all(sessions.map((session) => session.close())); | ||||
|     let failure = false; | ||||
|     try { | ||||
|         await scenario(createSession); | ||||
|     } catch(err) { | ||||
|         failure = true; | ||||
|         console.log('failure: ', err); | ||||
|         if (!noLogs) { | ||||
|             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   ----------------`); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   if (failure) { | ||||
|     process.exit(-1); | ||||
|   } else { | ||||
|     console.log('all tests finished successfully'); | ||||
|   } | ||||
|     // wait 5 minutes on failure if not running headless
 | ||||
|     // to inspect what went wrong
 | ||||
|     if (failure && options.headless === false) { | ||||
|         await new Promise((resolve) => setTimeout(resolve, 5 * 60 * 1000)); | ||||
|     } | ||||
| 
 | ||||
|     await Promise.all(sessions.map((session) => session.close())); | ||||
| 
 | ||||
|     if (failure) { | ||||
|         process.exit(-1); | ||||
|     } else { | ||||
|         console.log('all tests finished successfully'); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| runTests().catch(function(err) { | ||||
|   console.log(err); | ||||
|   process.exit(-1); | ||||
|     console.log(err); | ||||
|     process.exit(-1); | ||||
| }); | ||||
|  | @ -9,8 +9,8 @@ PORT=5005 | |||
| BASE_DIR=$(readlink -f $(dirname $0)) | ||||
| 
 | ||||
| if [ -d $BASE_DIR/$SERVER_DIR ]; then | ||||
| 	echo "synapse is already installed" | ||||
| 	exit | ||||
|     echo "synapse is already installed" | ||||
|     exit | ||||
| fi | ||||
| 
 | ||||
| cd $BASE_DIR | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Bruno Windels
						Bruno Windels