move everything to subfolder to merge into react-sdk
This commit is contained in:
parent
6cb9ef7e65
commit
ca86969f92
47 changed files with 0 additions and 0 deletions
30
test/end-to-end-tests/src/logbuffer.js
Normal file
30
test/end-to-end-tests/src/logbuffer.js
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
module.exports = 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
62
test/end-to-end-tests/src/logger.js
Normal file
62
test/end-to-end-tests/src/logger.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
module.exports = class Logger {
|
||||
constructor(username) {
|
||||
this.indent = 0;
|
||||
this.username = username;
|
||||
this.muted = false;
|
||||
}
|
||||
|
||||
startGroup(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) {
|
||||
if (!this.muted) {
|
||||
const indent = " ".repeat(this.indent * 2);
|
||||
process.stdout.write(`${indent} * ${this.username} ${description} ... `);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
done(status = "done") {
|
||||
if (!this.muted) {
|
||||
process.stdout.write(status + "\n");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
mute() {
|
||||
this.muted = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
unmute() {
|
||||
this.muted = false;
|
||||
return this;
|
||||
}
|
||||
}
|
30
test/end-to-end-tests/src/rest/consent.js
Normal file
30
test/end-to-end-tests/src/rest/consent.js
Normal file
|
@ -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});
|
||||
};
|
91
test/end-to-end-tests/src/rest/creator.js
Normal file
91
test/end-to-end-tests/src/rest/creator.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
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 {exec} = require('child_process');
|
||||
const request = require('request-promise-native');
|
||||
const RestSession = require('./session');
|
||||
const RestMultiSession = require('./multi');
|
||||
|
||||
function execAsync(command, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(command, options, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve({stdout, stderr});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = class RestSessionCreator {
|
||||
constructor(synapseSubdir, hsUrl, cwd) {
|
||||
this.synapseSubdir = synapseSubdir;
|
||||
this.hsUrl = hsUrl;
|
||||
this.cwd = cwd;
|
||||
}
|
||||
|
||||
async createSessionRange(usernames, password, groupName) {
|
||||
const sessionPromises = usernames.map((username) => this.createSession(username, password));
|
||||
const sessions = await Promise.all(sessionPromises);
|
||||
return new RestMultiSession(sessions, groupName);
|
||||
}
|
||||
|
||||
async createSession(username, password) {
|
||||
await this._register(username, password);
|
||||
console.log(` * created REST user ${username} ... done`);
|
||||
const authResult = await this._authenticate(username, password);
|
||||
return new RestSession(authResult);
|
||||
}
|
||||
|
||||
async _register(username, password) {
|
||||
const registerArgs = [
|
||||
'-c homeserver.yaml',
|
||||
`-u ${username}`,
|
||||
`-p ${password}`,
|
||||
'--no-admin',
|
||||
this.hsUrl
|
||||
];
|
||||
const registerCmd = `./register_new_matrix_user ${registerArgs.join(' ')}`;
|
||||
const allCmds = [
|
||||
`cd ${this.synapseSubdir}`,
|
||||
". ./activate",
|
||||
registerCmd
|
||||
].join(' && ');
|
||||
|
||||
await execAsync(allCmds, {cwd: this.cwd, encoding: 'utf-8'});
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
95
test/end-to-end-tests/src/rest/multi.js
Normal file
95
test/end-to-end-tests/src/rest/multi.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
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');
|
||||
const Logger = require('../logger');
|
||||
|
||||
module.exports = class RestMultiSession {
|
||||
constructor(sessions, groupName) {
|
||||
this.log = new Logger(groupName);
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
slice(groupName, start, end) {
|
||||
return new RestMultiSession(this.sessions.slice(start, end), groupName);
|
||||
}
|
||||
|
||||
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) {
|
||||
this.log.step("set their display name")
|
||||
await Promise.all(this.sessions.map(async (s) => {
|
||||
s.log.mute();
|
||||
await s.setDisplayName(fn(s));
|
||||
s.log.unmute();
|
||||
}));
|
||||
this.log.done();
|
||||
}
|
||||
|
||||
async join(roomIdOrAlias) {
|
||||
this.log.step(`join ${roomIdOrAlias}`)
|
||||
const rooms = await Promise.all(this.sessions.map(async (s) => {
|
||||
s.log.mute();
|
||||
const room = await s.join(roomIdOrAlias);
|
||||
s.log.unmute();
|
||||
return room;
|
||||
}));
|
||||
this.log.done();
|
||||
return new RestMultiRoom(rooms, roomIdOrAlias, this.log);
|
||||
}
|
||||
|
||||
room(roomIdOrAlias) {
|
||||
const rooms = this.sessions.map(s => s.room(roomIdOrAlias));
|
||||
return new RestMultiRoom(rooms, roomIdOrAlias, this.log);
|
||||
}
|
||||
}
|
||||
|
||||
class RestMultiRoom {
|
||||
constructor(rooms, roomIdOrAlias, log) {
|
||||
this.rooms = rooms;
|
||||
this.roomIdOrAlias = roomIdOrAlias;
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
async talk(message) {
|
||||
this.log.step(`say "${message}" in ${this.roomIdOrAlias}`)
|
||||
await Promise.all(this.rooms.map(async (r) => {
|
||||
r.log.mute();
|
||||
await r.talk(message);
|
||||
r.log.unmute();
|
||||
}));
|
||||
this.log.done();
|
||||
}
|
||||
|
||||
async leave() {
|
||||
this.log.step(`leave ${this.roomIdOrAlias}`)
|
||||
await Promise.all(this.rooms.map(async (r) => {
|
||||
r.log.mute();
|
||||
await r.leave();
|
||||
r.log.unmute();
|
||||
}));
|
||||
this.log.done();
|
||||
}
|
||||
}
|
47
test/end-to-end-tests/src/rest/room.js
Normal file
47
test/end-to-end-tests/src/rest/room.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
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, log) {
|
||||
this.session = session;
|
||||
this._roomId = roomId;
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
async talk(message) {
|
||||
this.log.step(`says "${message}" in ${this._roomId}`)
|
||||
const txId = uuidv4();
|
||||
await this.session._put(`/rooms/${this._roomId}/send/m.room.message/${txId}`, {
|
||||
"msgtype": "m.text",
|
||||
"body": message
|
||||
});
|
||||
this.log.done();
|
||||
return txId;
|
||||
}
|
||||
|
||||
async leave() {
|
||||
this.log.step(`leaves ${this._roomId}`)
|
||||
await this.session._post(`/rooms/${this._roomId}/leave`);
|
||||
this.log.done();
|
||||
}
|
||||
|
||||
roomId() {
|
||||
return this._roomId;
|
||||
}
|
||||
}
|
127
test/end-to-end-tests/src/rest/session.js
Normal file
127
test/end-to-end-tests/src/rest/session.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
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 Logger = require('../logger');
|
||||
const RestRoom = require('./room');
|
||||
const {approveConsent} = require('./consent');
|
||||
|
||||
module.exports = class RestSession {
|
||||
constructor(credentials) {
|
||||
this.log = new Logger(credentials.userId);
|
||||
this._credentials = credentials;
|
||||
this._displayName = null;
|
||||
this._rooms = {};
|
||||
}
|
||||
|
||||
userId() {
|
||||
return this._credentials.userId;
|
||||
}
|
||||
|
||||
userName() {
|
||||
return this._credentials.userId.split(":")[0].substr(1);
|
||||
}
|
||||
|
||||
displayName() {
|
||||
return this._displayName;
|
||||
}
|
||||
|
||||
async setDisplayName(displayName) {
|
||||
this.log.step(`sets their display name to ${displayName}`);
|
||||
this._displayName = displayName;
|
||||
await this._put(`/profile/${this._credentials.userId}/displayname`, {
|
||||
displayname: displayName
|
||||
});
|
||||
this.log.done();
|
||||
}
|
||||
|
||||
async join(roomIdOrAlias) {
|
||||
this.log.step(`joins ${roomIdOrAlias}`);
|
||||
const {room_id} = await this._post(`/join/${encodeURIComponent(roomIdOrAlias)}`);
|
||||
this.log.done();
|
||||
const room = new RestRoom(this, room_id, this.log);
|
||||
this._rooms[room_id] = room;
|
||||
this._rooms[roomIdOrAlias] = room;
|
||||
return room;
|
||||
}
|
||||
|
||||
room(roomIdOrAlias) {
|
||||
if (this._rooms.hasOwnProperty(roomIdOrAlias)) {
|
||||
return this._rooms[roomIdOrAlias];
|
||||
} else {
|
||||
throw new Error(`${this._credentials.userId} is not in ${roomIdOrAlias}`);
|
||||
}
|
||||
}
|
||||
|
||||
async createRoom(name, options) {
|
||||
this.log.step(`creates room ${name}`);
|
||||
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);
|
||||
this.log.done();
|
||||
return new RestRoom(this, room_id, this.log);
|
||||
}
|
||||
|
||||
_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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
test/end-to-end-tests/src/scenario.js
Normal file
52
test/end-to-end-tests/src/scenario.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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 {range} = require('./util');
|
||||
const signup = require('./usecases/signup');
|
||||
const roomDirectoryScenarios = require('./scenarios/directory');
|
||||
const lazyLoadingScenarios = require('./scenarios/lazy-loading');
|
||||
const e2eEncryptionScenarios = require('./scenarios/e2e-encryption');
|
||||
|
||||
module.exports = async function scenario(createSession, restCreator) {
|
||||
let firstUser = true;
|
||||
async function createUser(username) {
|
||||
const session = await createSession(username);
|
||||
if (firstUser) {
|
||||
// only show browser version for first browser opened
|
||||
console.log(`running tests on ${await session.browser.version()} ...`);
|
||||
firstUser = false;
|
||||
}
|
||||
await signup(session, session.username, 'testsarefun!!!', session.hsUrl);
|
||||
return session;
|
||||
}
|
||||
|
||||
const alice = await createUser("alice");
|
||||
const bob = await createUser("bob");
|
||||
|
||||
await roomDirectoryScenarios(alice, bob);
|
||||
await e2eEncryptionScenarios(alice, bob);
|
||||
console.log("create REST users:");
|
||||
const charlies = await createRestUsers(restCreator);
|
||||
await lazyLoadingScenarios(alice, bob, charlies);
|
||||
}
|
||||
|
||||
async function createRestUsers(restCreator) {
|
||||
const usernames = range(1, 10).map((i) => `charly-${i}`);
|
||||
const charlies = await restCreator.createSessionRange(usernames, "testtest", "charly-1..10");
|
||||
await charlies.setDisplayName((s) => `Charly #${s.userName().split('-')[1]}`);
|
||||
return charlies;
|
||||
}
|
1
test/end-to-end-tests/src/scenarios/README.md
Normal file
1
test/end-to-end-tests/src/scenarios/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
scenarios contains the high-level playbook for the test suite
|
36
test/end-to-end-tests/src/scenarios/directory.js
Normal file
36
test/end-to-end-tests/src/scenarios/directory.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 join = require('../usecases/join');
|
||||
const sendMessage = require('../usecases/send-message');
|
||||
const {receiveMessage} = require('../usecases/timeline');
|
||||
const {createRoom} = require('../usecases/create-room');
|
||||
const changeRoomSettings = require('../usecases/room-settings');
|
||||
|
||||
module.exports = async function roomDirectoryScenarios(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", alias: "#test"});
|
||||
await join(bob, room); //looks up room in directory
|
||||
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});
|
||||
}
|
52
test/end-to-end-tests/src/scenarios/e2e-encryption.js
Normal file
52
test/end-to-end-tests/src/scenarios/e2e-encryption.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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 {delay} = require('../util');
|
||||
const {acceptDialogMaybe} = require('../usecases/dialog');
|
||||
const join = require('../usecases/join');
|
||||
const sendMessage = require('../usecases/send-message');
|
||||
const acceptInvite = require('../usecases/accept-invite');
|
||||
const invite = require('../usecases/invite');
|
||||
const {receiveMessage} = require('../usecases/timeline');
|
||||
const {createRoom} = require('../usecases/create-room');
|
||||
const changeRoomSettings = require('../usecases/room-settings');
|
||||
const {startSasVerifcation, acceptSasVerification} = require('../usecases/verify');
|
||||
const assert = require('assert');
|
||||
|
||||
module.exports = async function e2eEncryptionScenarios(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 cancelKeyBackup(bob);
|
||||
await invite(bob, "@alice:localhost");
|
||||
await acceptInvite(alice, room);
|
||||
// do sas verifcation
|
||||
bob.log.step(`starts SAS verification with ${alice.username}`);
|
||||
const bobSasPromise = startSasVerifcation(bob, alice.username);
|
||||
const aliceSasPromise = acceptSasVerification(alice, bob.username);
|
||||
// wait in parallel, so they don't deadlock on each other
|
||||
const [bobSas, aliceSas] = await Promise.all([bobSasPromise, aliceSasPromise]);
|
||||
assert.deepEqual(bobSas, aliceSas);
|
||||
bob.log.done(`done (match for ${bobSas.join(", ")})`);
|
||||
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});
|
||||
}
|
123
test/end-to-end-tests/src/scenarios/lazy-loading.js
Normal file
123
test/end-to-end-tests/src/scenarios/lazy-loading.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
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 {delay} = require('../util');
|
||||
const join = require('../usecases/join');
|
||||
const sendMessage = require('../usecases/send-message');
|
||||
const {
|
||||
checkTimelineContains,
|
||||
scrollToTimelineTop
|
||||
} = require('../usecases/timeline');
|
||||
const {createRoom} = require('../usecases/create-room');
|
||||
const {getMembersInMemberlist} = require('../usecases/memberlist');
|
||||
const changeRoomSettings = require('../usecases/room-settings');
|
||||
const {enableLazyLoading} = require('../usecases/settings');
|
||||
const assert = require('assert');
|
||||
|
||||
module.exports = async function lazyLoadingScenarios(alice, bob, charlies) {
|
||||
console.log(" creating a room for lazy loading member scenarios:");
|
||||
const charly1to5 = charlies.slice("charly-1..5", 0, 5);
|
||||
const charly6to10 = charlies.slice("charly-6..10", 5);
|
||||
assert(charly1to5.sessions.length, 5);
|
||||
assert(charly6to10.sessions.length, 5);
|
||||
await setupRoomWithBobAliceAndCharlies(alice, bob, charly1to5);
|
||||
await checkPaginatedDisplayNames(alice, charly1to5);
|
||||
await checkMemberList(alice, charly1to5);
|
||||
await joinCharliesWhileAliceIsOffline(alice, charly6to10);
|
||||
await checkMemberList(alice, charly6to10);
|
||||
await charlies.room(alias).leave();
|
||||
await delay(1000);
|
||||
await checkMemberListLacksCharlies(alice, charlies);
|
||||
await checkMemberListLacksCharlies(bob, charlies);
|
||||
}
|
||||
|
||||
const room = "Lazy Loading Test";
|
||||
const alias = "#lltest:localhost";
|
||||
const charlyMsg1 = "hi bob!";
|
||||
const charlyMsg2 = "how's it going??";
|
||||
|
||||
async function setupRoomWithBobAliceAndCharlies(alice, bob, charlies) {
|
||||
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);
|
||||
}
|
||||
|
||||
async function checkPaginatedDisplayNames(alice, charlies) {
|
||||
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, charlies.log.username);
|
||||
}
|
||||
|
||||
async function checkMemberList(alice, charlies) {
|
||||
alice.log.step(`checks the memberlist contains herself, bob and ${charlies.log.username}`);
|
||||
const displayNames = (await getMembersInMemberlist(alice)).map((m) => m.displayName);
|
||||
assert(displayNames.includes("alice"));
|
||||
assert(displayNames.includes("bob"));
|
||||
charlies.sessions.forEach((charly) => {
|
||||
assert(displayNames.includes(charly.displayName()),
|
||||
`${charly.displayName()} should be in the member list, ` +
|
||||
`only have ${displayNames}`);
|
||||
});
|
||||
alice.log.done();
|
||||
}
|
||||
|
||||
async function checkMemberListLacksCharlies(session, charlies) {
|
||||
session.log.step(`checks the memberlist doesn't contain ${charlies.log.username}`);
|
||||
const displayNames = (await getMembersInMemberlist(session)).map((m) => m.displayName);
|
||||
charlies.sessions.forEach((charly) => {
|
||||
assert(!displayNames.includes(charly.displayName()),
|
||||
`${charly.displayName()} should not be in the member list, ` +
|
||||
`only have ${displayNames}`);
|
||||
});
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
async function joinCharliesWhileAliceIsOffline(alice, charly6to10) {
|
||||
await alice.setOffline(true);
|
||||
await delay(1000);
|
||||
const members6to10 = await charly6to10.join(alias);
|
||||
const member6 = members6to10.rooms[0];
|
||||
member6.log.step("sends 20 messages").mute();
|
||||
for(let i = 20; i >= 1; --i) {
|
||||
await member6.talk("where is charly?");
|
||||
}
|
||||
member6.log.unmute().done();
|
||||
const catchupPromise = alice.waitForNextSuccessfulSync();
|
||||
await alice.setOffline(false);
|
||||
await catchupPromise;
|
||||
await delay(2000);
|
||||
}
|
222
test/end-to-end-tests/src/session.js
Normal file
222
test/end-to-end-tests/src/session.js
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const puppeteer = require('puppeteer');
|
||||
const Logger = require('./logger');
|
||||
const LogBuffer = require('./logbuffer');
|
||||
const {delay} = require('./util');
|
||||
|
||||
const DEFAULT_TIMEOUT = 20000;
|
||||
|
||||
module.exports = class RiotSession {
|
||||
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`);
|
||||
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, hsUrl, throttleCpuFactor = 1) {
|
||||
const browser = await puppeteer.launch(puppeteerOptions);
|
||||
const page = await browser.newPage();
|
||||
await page.setViewport({
|
||||
width: 1280,
|
||||
height: 800
|
||||
});
|
||||
if (throttleCpuFactor !== 1) {
|
||||
const client = await page.target().createCDPSession();
|
||||
console.log("throttling cpu by a factor of", throttleCpuFactor);
|
||||
await client.send('Emulation.setCPUThrottlingRate', { rate: throttleCpuFactor });
|
||||
}
|
||||
return new RiotSession(browser, page, username, riotserver, hsUrl);
|
||||
}
|
||||
|
||||
async tryGetInnertext(selector) {
|
||||
const field = await this.page.$(selector);
|
||||
if (field != null) {
|
||||
const text_handle = await field.getProperty('innerText');
|
||||
return await text_handle.jsonValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async getElementProperty(handle, property) {
|
||||
const propHandle = await handle.getProperty(property);
|
||||
return await propHandle.jsonValue();
|
||||
}
|
||||
|
||||
innerText(field) {
|
||||
return this.getElementProperty(field, 'innerText');
|
||||
}
|
||||
|
||||
getOuterHTML(element_handle) {
|
||||
return this.getElementProperty(field, 'outerHTML');
|
||||
}
|
||||
|
||||
consoleLogs() {
|
||||
return this.consoleLog.buffer;
|
||||
}
|
||||
|
||||
networkLogs() {
|
||||
return this.networkLog.buffer;
|
||||
}
|
||||
|
||||
logXHRRequests() {
|
||||
let buffer = "";
|
||||
this.page.on('requestfinished', async (req) => {
|
||||
const type = req.resourceType();
|
||||
const response = await req.response();
|
||||
//if (type === 'xhr' || type === 'fetch') {
|
||||
buffer += `${type} ${response.status()} ${req.method()} ${req.url()} \n`;
|
||||
// if (req.method() === "POST") {
|
||||
// buffer += " Post data: " + req.postData();
|
||||
// }
|
||||
//}
|
||||
});
|
||||
return {
|
||||
logs() {
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async printElements(label, elements) {
|
||||
console.log(label, await Promise.all(elements.map(getOuterHTML)));
|
||||
}
|
||||
|
||||
async replaceInputText(input, text) {
|
||||
// click 3 times to select all text
|
||||
await input.click({clickCount: 3});
|
||||
// waiting here solves not having selected all the text by the 3x click above,
|
||||
// presumably because of the Field label animation.
|
||||
await this.delay(300);
|
||||
// then remove it with backspace
|
||||
await input.press('Backspace');
|
||||
// and type the new text
|
||||
await input.type(text);
|
||||
}
|
||||
|
||||
query(selector, timeout = DEFAULT_TIMEOUT) {
|
||||
return this.page.waitForSelector(selector, {visible: true, timeout});
|
||||
}
|
||||
|
||||
async queryAll(selector) {
|
||||
const timeout = DEFAULT_TIMEOUT;
|
||||
await this.query(selector, timeout);
|
||||
return await this.page.$$(selector);
|
||||
}
|
||||
|
||||
waitForReload() {
|
||||
const timeout = DEFAULT_TIMEOUT;
|
||||
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() {
|
||||
const timeout = DEFAULT_TIMEOUT;
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
this.browser.removeListener('targetcreated', callback);
|
||||
reject(new Error(`timeout of ${timeout}ms for waitForNewPage elapsed`));
|
||||
}, timeout);
|
||||
|
||||
const callback = async (target) => {
|
||||
if (target.type() !== 'page') {
|
||||
return;
|
||||
}
|
||||
this.browser.removeListener('targetcreated', callback);
|
||||
clearTimeout(timeoutHandle);
|
||||
const page = await target.page();
|
||||
resolve(page);
|
||||
};
|
||||
|
||||
this.browser.on('targetcreated', callback);
|
||||
});
|
||||
}
|
||||
|
||||
/** wait for a /sync request started after this call that gets a 200 response */
|
||||
async waitForNextSuccessfulSync() {
|
||||
const syncUrls = [];
|
||||
function onRequest(request) {
|
||||
if (request.url().indexOf("/sync") !== -1) {
|
||||
syncUrls.push(request.url());
|
||||
}
|
||||
}
|
||||
|
||||
this.page.on('request', onRequest);
|
||||
|
||||
await this.page.waitForResponse((response) => {
|
||||
return syncUrls.includes(response.request().url()) && response.status() === 200;
|
||||
});
|
||||
|
||||
this.page.removeListener('request', onRequest);
|
||||
}
|
||||
|
||||
goto(url) {
|
||||
return this.page.goto(url);
|
||||
}
|
||||
|
||||
url(path) {
|
||||
return this.riotserver + path;
|
||||
}
|
||||
|
||||
delay(ms) {
|
||||
return delay(ms);
|
||||
}
|
||||
|
||||
async setOffline(enabled) {
|
||||
const description = enabled ? "offline" : "back online";
|
||||
this.log.step(`goes ${description}`);
|
||||
await this.page.setOfflineMode(enabled);
|
||||
this.log.done();
|
||||
}
|
||||
|
||||
close() {
|
||||
return this.browser.close();
|
||||
}
|
||||
|
||||
async poll(callback, interval = 100) {
|
||||
const timeout = DEFAULT_TIMEOUT;
|
||||
let waited = 0;
|
||||
while(waited < timeout) {
|
||||
await this.delay(interval);
|
||||
waited += interval;
|
||||
if (await callback()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
2
test/end-to-end-tests/src/usecases/README.md
Normal file
2
test/end-to-end-tests/src/usecases/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
use cases contains the detailed DOM interactions to perform a given use case, may also do some assertions.
|
||||
use cases are often used in multiple scenarios.
|
38
test/end-to-end-tests/src/usecases/accept-invite.js
Normal file
38
test/end-to-end-tests/src/usecases/accept-invite.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
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');
|
||||
const {acceptDialogMaybe} = require('./dialog');
|
||||
|
||||
module.exports = async function acceptInvite(session, name) {
|
||||
session.log.step(`accepts "${name}" invite`);
|
||||
//TODO: brittle selector
|
||||
const invitesHandles = await session.queryAll('.mx_RoomTile_name.mx_RoomTile_invite');
|
||||
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();
|
||||
|
||||
const acceptInvitationLink = await session.query(".mx_RoomPreviewBar_Invite .mx_AccessibleButton_kind_primary");
|
||||
await acceptInvitationLink.click();
|
||||
|
||||
session.log.done();
|
||||
}
|
48
test/end-to-end-tests/src/usecases/create-room.js
Normal file
48
test/end-to-end-tests/src/usecases/create-room.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
async function openRoomDirectory(session) {
|
||||
const roomDirectoryButton = await session.query('.mx_LeftPanel_explore .mx_AccessibleButton');
|
||||
await roomDirectoryButton.click();
|
||||
}
|
||||
|
||||
async function createRoom(session, roomName) {
|
||||
session.log.step(`creates room "${roomName}"`);
|
||||
|
||||
const roomListHeaders = await session.queryAll('.mx_RoomSubList_labelContainer');
|
||||
const roomListHeaderLabels = await Promise.all(roomListHeaders.map(h => session.innerText(h)));
|
||||
const roomsIndex = roomListHeaderLabels.findIndex(l => l.toLowerCase().includes("rooms"));
|
||||
if (roomsIndex === -1) {
|
||||
throw new Error("could not find room list section that contains rooms in header");
|
||||
}
|
||||
const roomsHeader = roomListHeaders[roomsIndex];
|
||||
const addRoomButton = await roomsHeader.$(".mx_RoomSubList_addRoom");
|
||||
await addRoomButton.click();
|
||||
|
||||
|
||||
const roomNameInput = await session.query('.mx_CreateRoomDialog_name input');
|
||||
await session.replaceInputText(roomNameInput, roomName);
|
||||
|
||||
const createButton = await session.query('.mx_Dialog_primary');
|
||||
await createButton.click();
|
||||
|
||||
await session.query('.mx_MessageComposer');
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
module.exports = {openRoomDirectory, createRoom};
|
50
test/end-to-end-tests/src/usecases/dialog.js
Normal file
50
test/end-to-end-tests/src/usecases/dialog.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
async function assertDialog(session, expectedTitle) {
|
||||
const titleElement = await session.query(".mx_Dialog .mx_Dialog_title");
|
||||
const dialogHeader = await session.innerText(titleElement);
|
||||
assert(dialogHeader, expectedTitle);
|
||||
}
|
||||
|
||||
async function acceptDialog(session, expectedTitle) {
|
||||
const foundDialog = await acceptDialogMaybe(session, expectedTitle);
|
||||
if (!foundDialog) {
|
||||
throw new Error("could not find a dialog");
|
||||
}
|
||||
}
|
||||
|
||||
async function acceptDialogMaybe(session, expectedTitle) {
|
||||
let primaryButton = null;
|
||||
try {
|
||||
primaryButton = await session.query(".mx_Dialog .mx_Dialog_primary");
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
if (expectedTitle) {
|
||||
await assertDialog(session, expectedTitle);
|
||||
}
|
||||
await primaryButton.click();
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
assertDialog,
|
||||
acceptDialog,
|
||||
acceptDialogMaybe,
|
||||
};
|
30
test/end-to-end-tests/src/usecases/invite.js
Normal file
30
test/end-to-end-tests/src/usecases/invite.js
Normal file
|
@ -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 assert = require('assert');
|
||||
|
||||
module.exports = async function invite(session, userId) {
|
||||
session.log.step(`invites "${userId}" to room`);
|
||||
await session.delay(1000);
|
||||
const inviteButton = await session.query(".mx_MemberList_invite");
|
||||
await inviteButton.click();
|
||||
const inviteTextArea = await session.query(".mx_AddressPickerDialog textarea");
|
||||
await inviteTextArea.type(userId);
|
||||
await inviteTextArea.press("Enter");
|
||||
const confirmButton = await session.query(".mx_Dialog_primary");
|
||||
await confirmButton.click();
|
||||
session.log.done();
|
||||
}
|
30
test/end-to-end-tests/src/usecases/join.js
Normal file
30
test/end-to-end-tests/src/usecases/join.js
Normal file
|
@ -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 assert = require('assert');
|
||||
const {openRoomDirectory} = require('./create-room');
|
||||
|
||||
module.exports = async function join(session, roomName) {
|
||||
session.log.step(`joins room "${roomName}"`);
|
||||
await openRoomDirectory(session);
|
||||
const roomInput = await session.query('.mx_DirectorySearchBox input');
|
||||
await session.replaceInputText(roomInput, roomName);
|
||||
|
||||
const joinFirstLink = await session.query('.mx_RoomDirectory_table .mx_RoomDirectory_join .mx_AccessibleButton');
|
||||
await joinFirstLink.click();
|
||||
await session.query('.mx_MessageComposer');
|
||||
session.log.done();
|
||||
}
|
70
test/end-to-end-tests/src/usecases/memberlist.js
Normal file
70
test/end-to-end-tests/src/usecases/memberlist.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
async function openMemberInfo(session, name) {
|
||||
const membersAndNames = await getMembersInMemberlist(session);
|
||||
const matchingLabel = membersAndNames.filter((m) => {
|
||||
return m.displayName === name;
|
||||
}).map((m) => m.label)[0];
|
||||
await matchingLabel.click();
|
||||
};
|
||||
|
||||
module.exports.openMemberInfo = openMemberInfo;
|
||||
|
||||
module.exports.verifyDeviceForUser = async function(session, name, expectedDevice) {
|
||||
session.log.step(`verifies e2e device for ${name}`);
|
||||
const membersAndNames = await getMembersInMemberlist(session);
|
||||
const matchingLabel = membersAndNames.filter((m) => {
|
||||
return m.displayName === name;
|
||||
}).map((m) => m.label)[0];
|
||||
await matchingLabel.click();
|
||||
// click verify in member info
|
||||
const firstVerifyButton = await session.query(".mx_MemberDeviceInfo_verify");
|
||||
await firstVerifyButton.click();
|
||||
// expect "Verify device" dialog and click "Begin Verification"
|
||||
const dialogHeader = await session.innerText(await session.query(".mx_Dialog .mx_Dialog_title"));
|
||||
assert(dialogHeader, "Verify device");
|
||||
const beginVerificationButton = await session.query(".mx_Dialog .mx_Dialog_primary")
|
||||
await beginVerificationButton.click();
|
||||
// get emoji SAS labels
|
||||
const sasLabelElements = await session.queryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label");
|
||||
const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e)));
|
||||
console.log("my sas labels", sasLabels);
|
||||
|
||||
|
||||
const dialogCodeFields = await session.queryAll(".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();
|
||||
}
|
||||
|
||||
async function getMembersInMemberlist(session) {
|
||||
const memberNameElements = await session.queryAll(".mx_MemberList .mx_EntityTile_name");
|
||||
return Promise.all(memberNameElements.map(async (el) => {
|
||||
return {label: el, displayName: await session.innerText(el)};
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports.getMembersInMemberlist = getMembersInMemberlist;
|
99
test/end-to-end-tests/src/usecases/room-settings.js
Normal file
99
test/end-to-end-tests/src/usecases/room-settings.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
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');
|
||||
const {acceptDialog} = require('./dialog');
|
||||
|
||||
async function setSettingsToggle(session, toggle, enabled) {
|
||||
const className = await session.getElementProperty(toggle, "className");
|
||||
const checked = className.includes("mx_ToggleSwitch_on");
|
||||
if (checked !== enabled) {
|
||||
await toggle.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, possibly because the header is being rerendered
|
||||
/// click doesn't do anything otherwise
|
||||
await session.delay(1000);
|
||||
const settingsButton = await session.query(".mx_RoomHeader .mx_AccessibleButton[title=Settings]");
|
||||
await settingsButton.click();
|
||||
//find tabs
|
||||
const tabButtons = await session.queryAll(".mx_RoomSettingsDialog .mx_TabbedView_tabLabel");
|
||||
const tabLabels = await Promise.all(tabButtons.map(t => session.innerText(t)));
|
||||
const securityTabButton = tabButtons[tabLabels.findIndex(l => l.toLowerCase().includes("security"))];
|
||||
|
||||
const generalSwitches = await session.queryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch");
|
||||
const isDirectory = generalSwitches[0];
|
||||
|
||||
if (typeof settings.directory === "boolean") {
|
||||
session.log.step(`sets directory listing to ${settings.directory}`);
|
||||
await setSettingsToggle(session, isDirectory, settings.directory);
|
||||
}
|
||||
|
||||
if (settings.alias) {
|
||||
session.log.step(`sets alias to ${settings.alias}`);
|
||||
const aliasField = await session.query(".mx_RoomSettingsDialog .mx_AliasSettings input[type=text]");
|
||||
await session.replaceInputText(aliasField, settings.alias);
|
||||
const addButton = await session.query(".mx_RoomSettingsDialog .mx_AliasSettings .mx_AccessibleButton");
|
||||
await addButton.click();
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
securityTabButton.click();
|
||||
await session.delay(500);
|
||||
const securitySwitches = await session.queryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch");
|
||||
const e2eEncryptionToggle = securitySwitches[0];
|
||||
|
||||
if (typeof settings.encryption === "boolean") {
|
||||
session.log.step(`sets room e2e encryption to ${settings.encryption}`);
|
||||
const clicked = await setSettingsToggle(session, e2eEncryptionToggle, settings.encryption);
|
||||
// if enabling, accept beta warning dialog
|
||||
if (clicked && settings.encryption) {
|
||||
await acceptDialog(session, "Enable encryption?");
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.visibility) {
|
||||
session.log.step(`sets visibility to ${settings.visibility}`);
|
||||
const radios = await session.queryAll(".mx_RoomSettingsDialog 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 closeButton = await session.query(".mx_RoomSettingsDialog .mx_Dialog_cancelButton");
|
||||
await closeButton.click();
|
||||
|
||||
session.log.endGroup();
|
||||
}
|
34
test/end-to-end-tests/src/usecases/send-message.js
Normal file
34
test/end-to-end-tests/src/usecases/send-message.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
module.exports = async function sendMessage(session, message) {
|
||||
session.log.step(`writes "${message}" in room`);
|
||||
// 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.query('.mx_MessageComposer_editor');
|
||||
// sometimes the focus that type() does internally doesn't seem to work
|
||||
// and calling click before seems to fix it 🤷
|
||||
await composer.click();
|
||||
await composer.type(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.query(".mx_EventTile_last:not(.mx_EventTile_sending)");
|
||||
session.log.done();
|
||||
}
|
53
test/end-to-end-tests/src/usecases/settings.js
Normal file
53
test/end-to-end-tests/src/usecases/settings.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
async function openSettings(session, section) {
|
||||
const menuButton = await session.query(".mx_TopLeftMenuButton_name");
|
||||
await menuButton.click();
|
||||
const settingsItem = await session.query(".mx_TopLeftMenu_icon_settings");
|
||||
await settingsItem.click();
|
||||
if (section) {
|
||||
const sectionButton = await session.query(`.mx_UserSettingsDialog .mx_TabbedView_tabLabels .mx_UserSettingsDialog_${section}Icon`);
|
||||
await sectionButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
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.query("#feature_lazyloading");
|
||||
await llCheckbox.click();
|
||||
await session.waitForReload();
|
||||
const closeButton = await session.query(".mx_RoomHeader_cancelButton");
|
||||
await closeButton.click();
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
module.exports.getE2EDeviceFromSettings = async function(session) {
|
||||
session.log.step(`gets e2e device/key from settings`);
|
||||
await openSettings(session, "security");
|
||||
const deviceAndKey = await session.queryAll(".mx_SettingsTab_section .mx_SecurityUserSettingsTab_deviceInfo 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_UserSettingsDialog .mx_Dialog_cancelButton");
|
||||
await closeButton.click();
|
||||
session.log.done();
|
||||
return {id, key};
|
||||
}
|
90
test/end-to-end-tests/src/usecases/signup.js
Normal file
90
test/end-to-end-tests/src/usecases/signup.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
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 signup(session, username, password, homeserver) {
|
||||
session.log.step("signs up");
|
||||
await session.goto(session.url('/#/register'));
|
||||
// change the homeserver by clicking the advanced section
|
||||
if (homeserver) {
|
||||
const advancedButton = await session.query('.mx_ServerTypeSelector_type_Advanced');
|
||||
await advancedButton.click();
|
||||
|
||||
// depending on what HS is configured as the default, the advanced registration
|
||||
// goes the HS/IS entry directly (for matrix.org) or takes you to the user/pass entry (not matrix.org).
|
||||
// To work with both, we look for the "Change" link in the user/pass entry but don't fail when we can't find it
|
||||
// As this link should be visible immediately, and to not slow down the case where it isn't present,
|
||||
// pick a lower timeout of 5000ms
|
||||
try {
|
||||
const changeHsField = await session.query('.mx_AuthBody_editServerDetails', 5000);
|
||||
if (changeHsField) {
|
||||
await changeHsField.click();
|
||||
}
|
||||
} catch (err) {}
|
||||
|
||||
const hsInputField = await session.query('#mx_ServerConfig_hsUrl');
|
||||
await session.replaceInputText(hsInputField, homeserver);
|
||||
const nextButton = await session.query('.mx_Login_submit');
|
||||
// accept homeserver
|
||||
await nextButton.click();
|
||||
}
|
||||
//fill out form
|
||||
const usernameField = await session.query("#mx_RegistrationForm_username");
|
||||
const passwordField = await session.query("#mx_RegistrationForm_password");
|
||||
const passwordRepeatField = await session.query("#mx_RegistrationForm_passwordConfirm");
|
||||
await session.replaceInputText(usernameField, username);
|
||||
await session.replaceInputText(passwordField, password);
|
||||
await session.replaceInputText(passwordRepeatField, password);
|
||||
//wait 300ms because Registration/ServerConfig have a 250ms
|
||||
//delay to internally set the homeserver url
|
||||
//see Registration::render and ServerConfig::props::delayTimeMs
|
||||
await session.delay(300);
|
||||
/// 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();
|
||||
// Password validation is async, wait for it to complete before submit
|
||||
await session.query(".mx_Field_valid #mx_RegistrationForm_password");
|
||||
//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.query('.mx_QuestionDialog button.mx_Dialog_primary');
|
||||
await continueButton.click();
|
||||
|
||||
//find the privacy policy checkbox and check it
|
||||
const policyCheckbox = await session.query('.mx_InteractiveAuthEntryComponents_termsPolicy input');
|
||||
await policyCheckbox.click();
|
||||
|
||||
//now click the 'Accept' button to agree to the privacy policy
|
||||
const acceptButton = await session.query('.mx_InteractiveAuthEntryComponents_termsSubmit');
|
||||
await acceptButton.click();
|
||||
|
||||
//wait for registration to finish so the hash gets set
|
||||
//onhashchange better?
|
||||
|
||||
const foundHomeUrl = await session.poll(async () => {
|
||||
const url = session.page.url();
|
||||
return url === session.url('/#/home');
|
||||
});
|
||||
assert(foundHomeUrl);
|
||||
session.log.done();
|
||||
}
|
143
test/end-to-end-tests/src/usecases/timeline.js
Normal file
143
test/end-to-end-tests/src/usecases/timeline.js
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
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 () => {
|
||||
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 {
|
||||
const timelineScrollView = document.querySelector(".mx_RoomView_timeline .mx_ScrollPanel");
|
||||
if (timelineScrollView && 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
|
||||
|
||||
async function getLastMessage() {
|
||||
const lastTile = await getLastEventTile(session);
|
||||
return getMessageFromEventTile(lastTile);
|
||||
}
|
||||
|
||||
let lastMessage;
|
||||
await session.poll(async () => {
|
||||
try {
|
||||
lastMessage = await getLastMessage();
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
// stop polling when found the expected message
|
||||
return lastMessage &&
|
||||
lastMessage.body === expectedMessage.body &&
|
||||
lastMessage.sender === expectedMessage.sender;
|
||||
});
|
||||
assertMessage(lastMessage, 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);
|
||||
timelineMessages.reduce((prevSender, m) => {
|
||||
if (m.continuation) {
|
||||
m.sender = prevSender;
|
||||
return prevSender;
|
||||
} else {
|
||||
return m.sender;
|
||||
}
|
||||
});
|
||||
|
||||
expectedMessages.forEach((expectedMessage) => {
|
||||
const foundMessage = timelineMessages.find((message) => {
|
||||
return message.sender === expectedMessage.sender &&
|
||||
message.body === expectedMessage.body;
|
||||
});
|
||||
try {
|
||||
assertMessage(foundMessage, expectedMessage);
|
||||
} catch(err) {
|
||||
console.log("timelineMessages", timelineMessages);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
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 .mx_EventTile");
|
||||
}
|
||||
|
||||
async function getMessageFromEventTile(eventTile) {
|
||||
const senderElement = await eventTile.$(".mx_SenderProfile_name");
|
||||
const className = await (await eventTile.getProperty("className")).jsonValue();
|
||||
const classNames = className.split(" ");
|
||||
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();
|
||||
|
||||
return {
|
||||
sender,
|
||||
body,
|
||||
encrypted: classNames.includes("mx_EventTile_verified"),
|
||||
continuation: classNames.includes("mx_EventTile_continuation"),
|
||||
};
|
||||
}
|
68
test/end-to-end-tests/src/usecases/verify.js
Normal file
68
test/end-to-end-tests/src/usecases/verify.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright 2019 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');
|
||||
const {openMemberInfo} = require("./memberlist");
|
||||
const {assertDialog, acceptDialog} = require("./dialog");
|
||||
|
||||
async function assertVerified(session) {
|
||||
const dialogSubTitle = await session.innerText(await session.query(".mx_Dialog h2"));
|
||||
assert(dialogSubTitle, "Verified!");
|
||||
}
|
||||
|
||||
async function startVerification(session, name) {
|
||||
await openMemberInfo(session, name);
|
||||
// click verify in member info
|
||||
const firstVerifyButton = await session.query(".mx_MemberDeviceInfo_verify");
|
||||
await firstVerifyButton.click();
|
||||
}
|
||||
|
||||
async function getSasCodes(session) {
|
||||
const sasLabelElements = await session.queryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label");
|
||||
const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e)));
|
||||
return sasLabels;
|
||||
}
|
||||
|
||||
module.exports.startSasVerifcation = async function(session, name) {
|
||||
await startVerification(session, name);
|
||||
// expect "Verify device" dialog and click "Begin Verification"
|
||||
await assertDialog(session, "Verify device");
|
||||
// click "Begin Verification"
|
||||
await acceptDialog(session);
|
||||
const sasCodes = await getSasCodes(session);
|
||||
// click "Verify"
|
||||
await acceptDialog(session);
|
||||
await assertVerified(session);
|
||||
// click "Got it" when verification is done
|
||||
await acceptDialog(session);
|
||||
return sasCodes;
|
||||
};
|
||||
|
||||
module.exports.acceptSasVerification = async function(session, name) {
|
||||
await assertDialog(session, "Incoming Verification Request");
|
||||
const opponentLabelElement = await session.query(".mx_IncomingSasDialog_opponentProfile h2");
|
||||
const opponentLabel = await session.innerText(opponentLabelElement);
|
||||
assert(opponentLabel, name);
|
||||
// click "Continue" button
|
||||
await acceptDialog(session);
|
||||
const sasCodes = await getSasCodes(session);
|
||||
// click "Verify"
|
||||
await acceptDialog(session);
|
||||
await assertVerified(session);
|
||||
// click "Got it" when verification is done
|
||||
await acceptDialog(session);
|
||||
return sasCodes;
|
||||
};
|
27
test/end-to-end-tests/src/util.js
Normal file
27
test/end-to-end-tests/src/util.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
module.exports.range = function(start, amount, step = 1) {
|
||||
const r = [];
|
||||
for (let i = 0; i < amount; ++i) {
|
||||
r.push(start + (i * step));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
module.exports.delay = function(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue