mirror of https://github.com/vector-im/riot-web
Merge pull request #16 from matrix-org/bwindels/lltests
Test timeline messages have correct display name with lazy loadingpull/21833/head
commit
5e8a3db985
|
@ -9,7 +9,11 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"commander": "^2.17.1",
|
||||
"puppeteer": "^1.6.0"
|
||||
"puppeteer": "^1.6.0",
|
||||
"request": "^2.88.0",
|
||||
"request-promise-native": "^1.0.5",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
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 request = require('request-promise-native');
|
||||
const cheerio = require('cheerio');
|
||||
const url = require("url");
|
||||
|
||||
module.exports.approveConsent = async function(consentUrl) {
|
||||
const body = await request.get(consentUrl);
|
||||
const doc = cheerio.load(body);
|
||||
const v = doc("input[name=v]").val();
|
||||
const u = doc("input[name=u]").val();
|
||||
const h = doc("input[name=h]").val();
|
||||
const formAction = doc("form").attr("action");
|
||||
const absAction = url.resolve(consentUrl, formAction);
|
||||
await request.post(absAction).form({v, u, h});
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
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 util = require('util');
|
||||
const exec = util.promisify(require('child_process').exec);
|
||||
const request = require('request-promise-native');
|
||||
const RestSession = require('./session');
|
||||
const RestMultiSession = require('./multi');
|
||||
|
||||
module.exports = class RestSessionCreator {
|
||||
constructor(synapseSubdir, hsUrl, cwd) {
|
||||
this.synapseSubdir = synapseSubdir;
|
||||
this.hsUrl = hsUrl;
|
||||
this.cwd = cwd;
|
||||
}
|
||||
|
||||
async createSessionRange(usernames, password) {
|
||||
const sessionPromises = usernames.map((username) => this.createSession(username, password));
|
||||
const sessions = await Promise.all(sessionPromises);
|
||||
return new RestMultiSession(sessions);
|
||||
}
|
||||
|
||||
async createSession(username, password) {
|
||||
await this._register(username, password);
|
||||
const authResult = await this._authenticate(username, password);
|
||||
return new RestSession(authResult);
|
||||
}
|
||||
|
||||
_register(username, password) {
|
||||
const registerArgs = [
|
||||
'-c homeserver.yaml',
|
||||
`-u ${username}`,
|
||||
`-p ${password}`,
|
||||
// '--regular-user',
|
||||
'-a', //until PR gets merged
|
||||
this.hsUrl
|
||||
];
|
||||
const registerCmd = `./scripts/register_new_matrix_user ${registerArgs.join(' ')}`;
|
||||
const allCmds = [
|
||||
`cd ${this.synapseSubdir}`,
|
||||
"source env/bin/activate",
|
||||
registerCmd
|
||||
].join(';');
|
||||
|
||||
return exec(allCmds, {cwd: this.cwd, encoding: 'utf-8'}).catch((result) => {
|
||||
const lines = result.stdout.trim().split('\n');
|
||||
const failureReason = lines[lines.length - 1];
|
||||
throw new Error(`creating user ${username} failed: ${failureReason}`);
|
||||
});
|
||||
}
|
||||
|
||||
async _authenticate(username, password) {
|
||||
const requestBody = {
|
||||
"type": "m.login.password",
|
||||
"identifier": {
|
||||
"type": "m.id.user",
|
||||
"user": username
|
||||
},
|
||||
"password": password
|
||||
};
|
||||
const url = `${this.hsUrl}/_matrix/client/r0/login`;
|
||||
const responseBody = await request.post({url, json: true, body: requestBody});
|
||||
return {
|
||||
accessToken: responseBody.access_token,
|
||||
homeServer: responseBody.home_server,
|
||||
userId: responseBody.user_id,
|
||||
deviceId: responseBody.device_id,
|
||||
hsUrl: this.hsUrl,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
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 request = require('request-promise-native');
|
||||
const RestRoom = require('./room');
|
||||
const {approveConsent} = require('./consent');
|
||||
|
||||
module.exports = class RestMultiSession {
|
||||
constructor(sessions) {
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
slice(start, end) {
|
||||
return new RestMultiSession(this.sessions.slice(start, end));
|
||||
}
|
||||
|
||||
pop(userName) {
|
||||
const idx = this.sessions.findIndex((s) => s.userName() === userName);
|
||||
if(idx === -1) {
|
||||
throw new Error(`user ${userName} not found`);
|
||||
}
|
||||
const session = this.sessions.splice(idx, 1)[0];
|
||||
return session;
|
||||
}
|
||||
|
||||
async setDisplayName(fn) {
|
||||
await Promise.all(this.sessions.map((s) => s.setDisplayName(fn(s))));
|
||||
}
|
||||
|
||||
async join(roomId) {
|
||||
const rooms = await Promise.all(this.sessions.map((s) => s.join(roomId)));
|
||||
return new RestMultiRoom(rooms);
|
||||
}
|
||||
}
|
||||
|
||||
class RestMultiRoom {
|
||||
constructor(rooms) {
|
||||
this.rooms = rooms;
|
||||
}
|
||||
|
||||
async talk(message) {
|
||||
await Promise.all(this.rooms.map((r) => r.talk(message)));
|
||||
}
|
||||
|
||||
async leave() {
|
||||
await Promise.all(this.rooms.map((r) => r.leave()));
|
||||
}
|
||||
}
|
|
@ -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 uuidv4 = require('uuid/v4');
|
||||
|
||||
/* no pun intented */
|
||||
module.exports = class RestRoom {
|
||||
constructor(session, roomId) {
|
||||
this.session = session;
|
||||
this._roomId = roomId;
|
||||
}
|
||||
|
||||
async talk(message) {
|
||||
const txId = uuidv4();
|
||||
await this.session._put(`/rooms/${this._roomId}/send/m.room.message/${txId}`, {
|
||||
"msgtype": "m.text",
|
||||
"body": message
|
||||
});
|
||||
return txId;
|
||||
}
|
||||
|
||||
async leave() {
|
||||
await this.session._post(`/rooms/${this._roomId}/leave`);
|
||||
}
|
||||
|
||||
roomId() {
|
||||
return this._roomId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
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 request = require('request-promise-native');
|
||||
const RestRoom = require('./room');
|
||||
const {approveConsent} = require('./consent');
|
||||
|
||||
module.exports = class RestSession {
|
||||
constructor(credentials) {
|
||||
this._credentials = credentials;
|
||||
this._displayName = null;
|
||||
}
|
||||
|
||||
userId() {
|
||||
return this._credentials.userId;
|
||||
}
|
||||
|
||||
userName() {
|
||||
return this._credentials.userId.split(":")[0].substr(1);
|
||||
}
|
||||
|
||||
displayName() {
|
||||
return this._displayName;
|
||||
}
|
||||
|
||||
async setDisplayName(displayName) {
|
||||
this._displayName = displayName;
|
||||
await this._put(`/profile/${this._credentials.userId}/displayname`, {
|
||||
displayname: displayName
|
||||
});
|
||||
}
|
||||
|
||||
async join(roomIdOrAlias) {
|
||||
const {room_id} = await this._post(`/join/${encodeURIComponent(roomIdOrAlias)}`);
|
||||
return new RestRoom(this, room_id);
|
||||
}
|
||||
|
||||
async createRoom(name, options) {
|
||||
const body = {
|
||||
name,
|
||||
};
|
||||
if (options.invite) {
|
||||
body.invite = options.invite;
|
||||
}
|
||||
if (options.public) {
|
||||
body.visibility = "public";
|
||||
} else {
|
||||
body.visibility = "private";
|
||||
}
|
||||
if (options.dm) {
|
||||
body.is_direct = true;
|
||||
}
|
||||
if (options.topic) {
|
||||
body.topic = options.topic;
|
||||
}
|
||||
|
||||
const {room_id} = await this._post(`/createRoom`, body);
|
||||
return new RestRoom(this, room_id);
|
||||
}
|
||||
|
||||
_post(csApiPath, body) {
|
||||
return this._request("POST", csApiPath, body);
|
||||
}
|
||||
|
||||
_put(csApiPath, body) {
|
||||
return this._request("PUT", csApiPath, body);
|
||||
}
|
||||
|
||||
async _request(method, csApiPath, body) {
|
||||
try {
|
||||
const responseBody = await request({
|
||||
url: `${this._credentials.hsUrl}/_matrix/client/r0${csApiPath}`,
|
||||
method,
|
||||
headers: {
|
||||
"Authorization": `Bearer ${this._credentials.accessToken}`
|
||||
},
|
||||
json: true,
|
||||
body
|
||||
});
|
||||
return responseBody;
|
||||
|
||||
} catch(err) {
|
||||
const responseBody = err.response.body;
|
||||
if (responseBody.errcode === 'M_CONSENT_NOT_GIVEN') {
|
||||
await approveConsent(responseBody.consent_uri);
|
||||
return this._request(method, csApiPath, body);
|
||||
} else if(responseBody && responseBody.error) {
|
||||
throw new Error(`${method} ${csApiPath}: ${responseBody.error}`);
|
||||
} else {
|
||||
throw new Error(`${method} ${csApiPath}: ${err.response.statusCode}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,26 +21,47 @@ const join = require('./tests/join');
|
|||
const sendMessage = require('./tests/send-message');
|
||||
const acceptInvite = require('./tests/accept-invite');
|
||||
const invite = require('./tests/invite');
|
||||
const receiveMessage = require('./tests/receive-message');
|
||||
const {
|
||||
receiveMessage,
|
||||
checkTimelineContains,
|
||||
scrollToTimelineTop
|
||||
} = require('./tests/timeline');
|
||||
const createRoom = require('./tests/create-room');
|
||||
const changeRoomSettings = require('./tests/room-settings');
|
||||
const acceptServerNoticesInviteAndConsent = require('./tests/server-notices-consent');
|
||||
const getE2EDeviceFromSettings = require('./tests/e2e-device');
|
||||
const {enableLazyLoading, getE2EDeviceFromSettings} = require('./tests/settings');
|
||||
const verifyDeviceForUser = require("./tests/verify-device");
|
||||
|
||||
module.exports = async function scenario(createSession) {
|
||||
module.exports = async function scenario(createSession, restCreator) {
|
||||
async function createUser(username) {
|
||||
const session = await createSession(username);
|
||||
await signup(session, session.username, 'testtest');
|
||||
await signup(session, session.username, 'testtest', session.hsUrl);
|
||||
await acceptServerNoticesInviteAndConsent(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
const alice = await createUser("alice");
|
||||
const bob = await createUser("bob");
|
||||
const charlies = await createRestUsers(restCreator);
|
||||
|
||||
await createDirectoryRoomAndTalk(alice, bob);
|
||||
await createE2ERoomAndTalk(alice, bob);
|
||||
await aLazyLoadingTest(alice, bob, charlies);
|
||||
}
|
||||
|
||||
function range(start, amount, step = 1) {
|
||||
const r = [];
|
||||
for (let i = 0; i < amount; ++i) {
|
||||
r.push(start + (i * step));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
async function createRestUsers(restCreator) {
|
||||
const usernames = range(1, 10).map((i) => `charly-${i}`);
|
||||
const charlies = await restCreator.createSessionRange(usernames, 'testtest');
|
||||
await charlies.setDisplayName((s) => `Charly #${s.userName().split('-')[1]}`);
|
||||
return charlies;
|
||||
}
|
||||
|
||||
async function createDirectoryRoomAndTalk(alice, bob) {
|
||||
|
@ -83,3 +104,38 @@ async function createE2ERoomAndTalk(alice, bob) {
|
|||
await sendMessage(bob, bobMessage);
|
||||
await receiveMessage(alice, {sender: "bob", body: bobMessage, encrypted: true});
|
||||
}
|
||||
|
||||
async function aLazyLoadingTest(alice, bob, charlies) {
|
||||
console.log(" creating a room for lazy loading member scenarios:");
|
||||
await enableLazyLoading(alice);
|
||||
const room = "Lazy Loading Test";
|
||||
const alias = "#lltest:localhost";
|
||||
const charlyMsg1 = "hi bob!";
|
||||
const charlyMsg2 = "how's it going??";
|
||||
await createRoom(bob, room);
|
||||
await changeRoomSettings(bob, {directory: true, visibility: "public_no_guests", alias});
|
||||
// wait for alias to be set by server after clicking "save"
|
||||
// so the charlies can join it.
|
||||
await bob.delay(500);
|
||||
const charlyMembers = await charlies.join(alias);
|
||||
await charlyMembers.talk(charlyMsg1);
|
||||
await charlyMembers.talk(charlyMsg2);
|
||||
bob.log.step("sends 20 messages").mute();
|
||||
for(let i = 20; i >= 1; --i) {
|
||||
await sendMessage(bob, `I will only say this ${i} time(s)!`);
|
||||
}
|
||||
bob.log.unmute().done();
|
||||
await join(alice, alias);
|
||||
await scrollToTimelineTop(alice);
|
||||
//alice should see 2 messages from every charly with
|
||||
//the correct display name
|
||||
const expectedMessages = [charlyMsg1, charlyMsg2].reduce((messages, msgText) => {
|
||||
return charlies.sessions.reduce((messages, charly) => {
|
||||
return messages.concat({
|
||||
sender: charly.displayName(),
|
||||
body: msgText,
|
||||
});
|
||||
}, messages);
|
||||
}, []);
|
||||
await checkTimelineContains(alice, expectedMessages, "Charly #1-10");
|
||||
}
|
||||
|
|
|
@ -35,32 +35,54 @@ class Logger {
|
|||
constructor(username) {
|
||||
this.indent = 0;
|
||||
this.username = username;
|
||||
this.muted = false;
|
||||
}
|
||||
|
||||
startGroup(description) {
|
||||
const indent = " ".repeat(this.indent * 2);
|
||||
console.log(`${indent} * ${this.username} ${description}:`);
|
||||
if (!this.muted) {
|
||||
const indent = " ".repeat(this.indent * 2);
|
||||
console.log(`${indent} * ${this.username} ${description}:`);
|
||||
}
|
||||
this.indent += 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
endGroup() {
|
||||
this.indent -= 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
step(description) {
|
||||
const indent = " ".repeat(this.indent * 2);
|
||||
process.stdout.write(`${indent} * ${this.username} ${description} ... `);
|
||||
if (!this.muted) {
|
||||
const indent = " ".repeat(this.indent * 2);
|
||||
process.stdout.write(`${indent} * ${this.username} ${description} ... `);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
done(status = "done") {
|
||||
process.stdout.write(status + "\n");
|
||||
if (!this.muted) {
|
||||
process.stdout.write(status + "\n");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
mute() {
|
||||
this.muted = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
unmute() {
|
||||
this.muted = false;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class RiotSession {
|
||||
constructor(browser, page, username, riotserver) {
|
||||
constructor(browser, page, username, riotserver, hsUrl) {
|
||||
this.browser = browser;
|
||||
this.page = page;
|
||||
this.hsUrl = hsUrl;
|
||||
this.riotserver = riotserver;
|
||||
this.username = username;
|
||||
this.consoleLog = new LogBuffer(page, "console", (msg) => `${msg.text()}\n`);
|
||||
|
@ -72,14 +94,14 @@ module.exports = class RiotSession {
|
|||
this.log = new Logger(this.username);
|
||||
}
|
||||
|
||||
static async create(username, puppeteerOptions, riotserver) {
|
||||
static async create(username, puppeteerOptions, riotserver, hsUrl) {
|
||||
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);
|
||||
return new RiotSession(browser, page, username, riotserver, hsUrl);
|
||||
}
|
||||
|
||||
async tryGetInnertext(selector) {
|
||||
|
@ -161,6 +183,22 @@ module.exports = class RiotSession {
|
|||
return await this.queryAll(selector);
|
||||
}
|
||||
|
||||
waitForReload(timeout = 5000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
this.browser.removeEventListener('domcontentloaded', callback);
|
||||
reject(new Error(`timeout of ${timeout}ms for waitForReload elapsed`));
|
||||
}, timeout);
|
||||
|
||||
const callback = async () => {
|
||||
clearTimeout(timeoutHandle);
|
||||
resolve();
|
||||
};
|
||||
|
||||
this.page.once('domcontentloaded', callback);
|
||||
});
|
||||
}
|
||||
|
||||
waitForNewPage(timeout = 5000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
|
|
|
@ -1,49 +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.
|
||||
*/
|
||||
|
||||
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();
|
||||
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(1000);
|
||||
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();
|
||||
}
|
|
@ -76,6 +76,13 @@ module.exports = async function changeRoomSettings(session, settings) {
|
|||
session.log.done();
|
||||
}
|
||||
|
||||
if (settings.alias) {
|
||||
session.log.step(`sets alias to ${settings.alias}`);
|
||||
const aliasField = await session.waitAndQuery(".mx_RoomSettings .mx_EditableItemList .mx_EditableItem_editable");
|
||||
await session.replaceInputText(aliasField, settings.alias);
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
const saveButton = await session.query(".mx_RoomHeader_wrapper .mx_RoomHeader_textButton");
|
||||
await saveButton.click();
|
||||
|
||||
|
|
|
@ -25,5 +25,7 @@ module.exports = async function sendMessage(session, message) {
|
|||
const text = await session.innerText(composer);
|
||||
assert.equal(text.trim(), message.trim());
|
||||
await composer.press("Enter");
|
||||
// wait for the message to appear sent
|
||||
await session.waitAndQuery(".mx_EventTile_last:not(.mx_EventTile_sending)");
|
||||
session.log.done();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,23 @@ limitations under the License.
|
|||
|
||||
const assert = require('assert');
|
||||
|
||||
module.exports = async function getE2EDeviceFromSettings(session) {
|
||||
module.exports.enableLazyLoading = async function(session) {
|
||||
session.log.step(`enables lazy loading of members in the lab settings`);
|
||||
const settingsButton = await session.query('.mx_BottomLeftMenu_settings');
|
||||
await settingsButton.click();
|
||||
const llCheckbox = await session.waitAndQuery("#feature_lazyloading");
|
||||
await llCheckbox.click();
|
||||
await session.waitForReload();
|
||||
const closeButton = await session.waitAndQuery(".mx_RoomHeader_cancelButton");
|
||||
await closeButton.click();
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
module.exports.getE2EDeviceFromSettings = async function(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", 1000);
|
||||
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();
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
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.scrollToTimelineTop = async function(session) {
|
||||
session.log.step(`scrolls to the top of the timeline`);
|
||||
await session.page.evaluate(() => {
|
||||
return Promise.resolve().then(async () => {
|
||||
const timelineScrollView = document.querySelector(".mx_RoomView .gm-scroll-view");
|
||||
let timedOut = false;
|
||||
let timeoutHandle = null;
|
||||
// set scrollTop to 0 in a loop and check every 50ms
|
||||
// if content became available (scrollTop not being 0 anymore),
|
||||
// assume everything is loaded after 3s
|
||||
do {
|
||||
if (timelineScrollView.scrollTop !== 0) {
|
||||
if (timeoutHandle) {
|
||||
clearTimeout(timeoutHandle);
|
||||
}
|
||||
timeoutHandle = setTimeout(() => timedOut = true, 3000);
|
||||
timelineScrollView.scrollTop = 0;
|
||||
} else {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
}
|
||||
} while (!timedOut)
|
||||
});
|
||||
})
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
module.exports.receiveMessage = async function(session, expectedMessage) {
|
||||
session.log.step(`receives message "${expectedMessage.body}" from ${expectedMessage.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 (expectedMessage.encrypted) {
|
||||
return body.indexOf(expectedMessage.sender) !== -1 &&
|
||||
body.indexOf("m.room.encrypted") !== -1;
|
||||
} else {
|
||||
return body.indexOf(expectedMessage.body) !== -1;
|
||||
}
|
||||
});
|
||||
// wait a bit for the incoming event to be rendered
|
||||
await session.delay(1000);
|
||||
const lastTile = await getLastEventTile(session);
|
||||
const foundMessage = await getMessageFromEventTile(lastTile);
|
||||
assertMessage(foundMessage, expectedMessage);
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
|
||||
module.exports.checkTimelineContains = async function (session, expectedMessages, sendersDescription) {
|
||||
session.log.step(`checks timeline contains ${expectedMessages.length} ` +
|
||||
`given messages${sendersDescription ? ` from ${sendersDescription}`:""}`);
|
||||
const eventTiles = await getAllEventTiles(session);
|
||||
let timelineMessages = await Promise.all(eventTiles.map((eventTile) => {
|
||||
return getMessageFromEventTile(eventTile);
|
||||
}));
|
||||
//filter out tiles that were not messages
|
||||
timelineMessages = timelineMessages .filter((m) => !!m);
|
||||
expectedMessages.forEach((expectedMessage) => {
|
||||
const foundMessage = timelineMessages.find((message) => {
|
||||
return message.sender === expectedMessage.sender &&
|
||||
message.body === expectedMessage.body;
|
||||
});
|
||||
assertMessage(foundMessage, expectedMessage);
|
||||
});
|
||||
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
function assertMessage(foundMessage, expectedMessage) {
|
||||
assert(foundMessage, `message ${JSON.stringify(expectedMessage)} not found in timeline`);
|
||||
assert.equal(foundMessage.body, expectedMessage.body);
|
||||
assert.equal(foundMessage.sender, expectedMessage.sender);
|
||||
if (expectedMessage.hasOwnProperty("encrypted")) {
|
||||
assert.equal(foundMessage.encrypted, expectedMessage.encrypted);
|
||||
}
|
||||
}
|
||||
|
||||
function getLastEventTile(session) {
|
||||
return session.query(".mx_EventTile_last");
|
||||
}
|
||||
|
||||
function getAllEventTiles(session) {
|
||||
return session.queryAll(".mx_RoomView_MessageList > *");
|
||||
}
|
||||
|
||||
async function getMessageFromEventTile(eventTile) {
|
||||
const senderElement = await eventTile.$(".mx_SenderProfile_name");
|
||||
const bodyElement = await eventTile.$(".mx_EventTile_body");
|
||||
let sender = null;
|
||||
if (senderElement) {
|
||||
sender = await(await senderElement.getProperty("innerText")).jsonValue();
|
||||
}
|
||||
if (!bodyElement) {
|
||||
return null;
|
||||
}
|
||||
const body = await(await bodyElement.getProperty("innerText")).jsonValue();
|
||||
const e2eIcon = await eventTile.$(".mx_EventTile_e2eIcon");
|
||||
|
||||
return {
|
||||
sender,
|
||||
body,
|
||||
encrypted: !!e2eIcon
|
||||
};
|
||||
}
|
13
start.js
13
start.js
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
const assert = require('assert');
|
||||
const RiotSession = require('./src/session');
|
||||
const scenario = require('./src/scenario');
|
||||
const RestSessionCreator = require('./src/rest/creator');
|
||||
|
||||
const program = require('commander');
|
||||
program
|
||||
|
@ -27,6 +28,8 @@ program
|
|||
.option('--dev-tools', "open chrome devtools in browser window", false)
|
||||
.parse(process.argv);
|
||||
|
||||
const hsUrl = 'http://localhost:5005';
|
||||
|
||||
async function runTests() {
|
||||
let sessions = [];
|
||||
console.log("running tests ...");
|
||||
|
@ -41,15 +44,21 @@ async function runTests() {
|
|||
options.executablePath = path;
|
||||
}
|
||||
|
||||
const restCreator = new RestSessionCreator(
|
||||
'synapse/installations/consent',
|
||||
hsUrl,
|
||||
__dirname
|
||||
);
|
||||
|
||||
async function createSession(username) {
|
||||
const session = await RiotSession.create(username, options, program.riotUrl);
|
||||
const session = await RiotSession.create(username, options, program.riotUrl, hsUrl);
|
||||
sessions.push(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
let failure = false;
|
||||
try {
|
||||
await scenario(createSession);
|
||||
await scenario(createSession, restCreator);
|
||||
} catch(err) {
|
||||
failure = true;
|
||||
console.log('failure: ', err);
|
||||
|
|
|
@ -207,10 +207,10 @@ log_config: "{{SYNAPSE_ROOT}}localhost.log.config"
|
|||
## Ratelimiting ##
|
||||
|
||||
# Number of messages a client can send per second
|
||||
rc_messages_per_second: 0.2
|
||||
rc_messages_per_second: 100
|
||||
|
||||
# Number of message a client can send before being throttled
|
||||
rc_message_burst_count: 10.0
|
||||
rc_message_burst_count: 20.0
|
||||
|
||||
# The federation window size in milliseconds
|
||||
federation_rc_window_size: 1000
|
||||
|
|
Loading…
Reference in New Issue