More integration tests for medium groups

pull/1134/head
Maxim Shishmarev 6 years ago
parent 2a0130ff04
commit fcadcd780e

@ -21,8 +21,8 @@ chai.use(chaiAsPromised);
chai.config.includeStack = true; chai.config.includeStack = true;
// From https://github.com/chaijs/chai/issues/200 // From https://github.com/chaijs/chai/issues/200
chai.use(function (_chai, _) { chai.use((_chai, _) => {
_chai.Assertion.addMethod('withMessage', function (msg) { _chai.Assertion.addMethod('withMessage', msg => {
_.flag(this, 'message', msg); _.flag(this, 'message', msg);
}); });
}); });
@ -250,7 +250,6 @@ module.exports = {
}, },
async makeFriends(app1, client2) { async makeFriends(app1, client2) {
const [app2, pubkey2] = client2; const [app2, pubkey2] = client2;
/** add each other as friends */ /** add each other as friends */
@ -259,11 +258,7 @@ module.exports = {
await app1.client.element(ConversationPage.contactsButtonSection).click(); await app1.client.element(ConversationPage.contactsButtonSection).click();
await app1.client.element(ConversationPage.addContactButton).click(); await app1.client.element(ConversationPage.addContactButton).click();
await this.setValueWrapper( await this.setValueWrapper(app1, ConversationPage.sessionIDInput, pubkey2);
app1,
ConversationPage.sessionIDInput,
pubkey2
);
await app1.client.element(ConversationPage.nextButton).click(); await app1.client.element(ConversationPage.nextButton).click();
await app1.client.waitForExist( await app1.client.waitForExist(
ConversationPage.sendFriendRequestTextarea, ConversationPage.sendFriendRequestTextarea,
@ -310,10 +305,6 @@ module.exports = {
ConversationPage.acceptedFriendRequestMessage, ConversationPage.acceptedFriendRequestMessage,
5000 5000
); );
// click away to close the current pane and make further FR possible
await app1.client.element(ConversationPage.globeButtonSection).click();
}, },
async startAppsAsFriends() { async startAppsAsFriends() {
@ -340,7 +331,6 @@ module.exports = {
}, },
async addFriendToNewClosedGroup(members, useSenderKeys) { async addFriendToNewClosedGroup(members, useSenderKeys) {
const [app, ...others] = members; const [app, ...others] = members;
await this.setValueWrapper( await this.setValueWrapper(
@ -348,19 +338,26 @@ module.exports = {
ConversationPage.closedGroupNameTextarea, ConversationPage.closedGroupNameTextarea,
this.VALID_CLOSED_GROUP_NAME1 this.VALID_CLOSED_GROUP_NAME1
); );
await app.client await app.client
.element(ConversationPage.closedGroupNameTextarea) .element(ConversationPage.closedGroupNameTextarea)
.getValue() .getValue()
.should.eventually.equal(this.VALID_CLOSED_GROUP_NAME1); .should.eventually.equal(this.VALID_CLOSED_GROUP_NAME1);
// This assumes that app does not have any other friends
for (let i = 0; i < others.length; i += 1) {
// eslint-disable-next-line no-await-in-loop
await app.client await app.client
.element(ConversationPage.createClosedGroupMemberItem) .element(ConversationPage.createClosedGroupMemberItem(i))
.isVisible().should.eventually.be.true; .isVisible().should.eventually.be.true;
// select the first friend as a member of the groups being created // eslint-disable-next-line no-await-in-loop
await app.client await app.client
.element(ConversationPage.createClosedGroupMemberItem) .element(ConversationPage.createClosedGroupMemberItem(i))
.click(); .click();
}
await app.client await app.client
.element(ConversationPage.createClosedGroupMemberItemSelected) .element(ConversationPage.createClosedGroupMemberItemSelected)
.isVisible().should.eventually.be.true; .isVisible().should.eventually.be.true;
@ -384,8 +381,9 @@ module.exports = {
await app.client.isExisting( await app.client.isExisting(
ConversationPage.headerTitleGroupName(this.VALID_CLOSED_GROUP_NAME1) ConversationPage.headerTitleGroupName(this.VALID_CLOSED_GROUP_NAME1)
).should.eventually.be.true; ).should.eventually.be.true;
await app.client.element(ConversationPage.headerTitleMembers(2)).isVisible() await app.client
.should.eventually.be.true; .element(ConversationPage.headerTitleMembers(members.length))
.isVisible().should.eventually.be.true;
// validate overlay is closed // validate overlay is closed
await app.client await app.client
@ -575,6 +573,10 @@ module.exports = {
app1.webContents.executeJavaScript( app1.webContents.executeJavaScript(
'window.LokiMessageAPI = window.StubMessageAPI;' 'window.LokiMessageAPI = window.StubMessageAPI;'
); );
app1.webContents.executeJavaScript(
'window.LokiSnodeAPI = window.StubLokiSnodeAPI;'
);
}, },
logsContainsString: async (app1, str) => { logsContainsString: async (app1, str) => {
@ -589,13 +591,24 @@ module.exports = {
const { query } = url.parse(request.url, true); const { query } = url.parse(request.url, true);
const { pubkey, data, timestamp } = query; const { pubkey, data, timestamp } = query;
if (pubkey) { if (!pubkey) {
console.warn('NO PUBKEY');
response.writeHead(400, { 'Content-Type': 'text/html' });
response.end();
}
if (request.method === 'POST') { if (request.method === 'POST') {
if (ENABLE_LOG) { if (ENABLE_LOG) {
console.warn('POST', [data, timestamp]); console.warn(
'POST',
pubkey.substr(2, 3),
data.substr(4, 10),
timestamp
);
} }
let ori = this.messages[pubkey]; let ori = this.messages[pubkey];
if (!this.messages[pubkey]) { if (!this.messages[pubkey]) {
ori = []; ori = [];
} }
@ -605,19 +618,18 @@ module.exports = {
response.writeHead(200, { 'Content-Type': 'text/html' }); response.writeHead(200, { 'Content-Type': 'text/html' });
response.end(); response.end();
} else { } else {
const retrievedMessages = { messages: this.messages[pubkey] }; const retrievedMessages = { messages: this.messages[pubkey] || [] };
if (ENABLE_LOG) { if (ENABLE_LOG) {
console.warn('GET', pubkey, retrievedMessages); const messages = retrievedMessages.messages.map(m =>
m.data.substr(4, 10)
);
console.warn('GET', pubkey.substr(2, 3), messages);
} }
if (this.messages[pubkey]) {
response.writeHead(200, { 'Content-Type': 'application/json' }); response.writeHead(200, { 'Content-Type': 'application/json' });
response.write(JSON.stringify(retrievedMessages)); response.write(JSON.stringify(retrievedMessages));
this.messages[pubkey] = [];
}
response.end(); response.end();
} }
}
response.end();
}); });
this.stubSnode.listen(STUB_SNODE_SERVER_PORT); this.stubSnode.listen(STUB_SNODE_SERVER_PORT);
} else { } else {

@ -63,7 +63,8 @@ module.exports = {
closedGroupNameTextarea: commonPage.textAreaWithPlaceholder( closedGroupNameTextarea: commonPage.textAreaWithPlaceholder(
'Enter a group name' 'Enter a group name'
), ),
createClosedGroupMemberItem: commonPage.divWithClass('session-member-item'), createClosedGroupMemberItem: idx =>
commonPage.divWithClass(`session-member-item-${idx}`),
createClosedGroupSealedSenderToggle: commonPage.divWithClass( createClosedGroupSealedSenderToggle: commonPage.divWithClass(
'session-toggle' 'session-toggle'
), ),

@ -6,7 +6,6 @@ const common = require('./common');
const ConversationPage = require('./page-objects/conversation.page'); const ConversationPage = require('./page-objects/conversation.page');
async function generateAndSendMessage(app) { async function generateAndSendMessage(app) {
// send a message from app and validate it is received on app2 // send a message from app and validate it is received on app2
const textMessage = common.generateSendMessageText(); const textMessage = common.generateSendMessageText();
await app.client await app.client
@ -27,31 +26,24 @@ async function generateAndSendMessage(app) {
); );
return textMessage; return textMessage;
} }
describe('senderkeys', function() { async function makeFriendsPlusMessage(app, [app2, pubkey]) {
let app; await common.makeFriends(app, [app2, pubkey]);
let app2;
this.timeout(60000);
this.slow(30000);
beforeEach(async () => { // Send something back so that `app` can see our name
await common.killallElectron(); const text = await generateAndSendMessage(app2);
await common.stopStubSnodeServer(); await app.client.waitForExist(
ConversationPage.existingReceivedMessageText(text),
}); 8000
);
afterEach(async () => {
await common.stopApp(app);
await common.killallElectron();
await common.stopStubSnodeServer();
});
it('Two member group', async function() { // Click away so we can call this function again
await app.client.element(ConversationPage.globeButtonSection).click();
}
[app, app2] = await common.startAppsAsFriends(); async function testTwoMembers() {
const [app, app2] = await common.startAppsAsFriends();
await app.client.element(ConversationPage.globeButtonSection).click(); await app.client.element(ConversationPage.globeButtonSection).click();
await app.client.element(ConversationPage.createClosedGroupButton).click(); await app.client.element(ConversationPage.createClosedGroupButton).click();
@ -74,15 +66,13 @@ describe('senderkeys', function() {
// TODO: fix this. We can send messages back manually, not sure // TODO: fix this. We can send messages back manually, not sure
// why this test fails // why this test fails
// await app.client.waitForExist( await app.client.waitForExist(
// ConversationPage.existingReceivedMessageText(text2), ConversationPage.existingReceivedMessageText(text2),
// 10000 10000
// ); );
}
});
it('Three member group: test session requests', async function() {
async function testThreeMembers() {
// 1. Make three clients A, B, C // 1. Make three clients A, B, C
const app1Props = { const app1Props = {
@ -106,32 +96,64 @@ describe('senderkeys', function() {
const [app1, app2, app3] = await Promise.all([ const [app1, app2, app3] = await Promise.all([
common.startAndStub(app1Props), common.startAndStub(app1Props),
common.startAndStubN(app2Props, 2), common.startAndStubN(app2Props, 2),
common.startAndStubN(app3Props, 3) common.startAndStubN(app3Props, 3),
]); ]);
// 2. Make A friends with B and C (B and C are not friends) // 2. Make A friends with B and C (B and C are not friends)
await common.makeFriends(app1, [app2, common.TEST_PUBKEY2]); await makeFriendsPlusMessage(app1, [app2, common.TEST_PUBKEY2]);
await makeFriendsPlusMessage(app1, [app3, common.TEST_PUBKEY3]);
const useSenderKeys = true;
await app1.client.element(ConversationPage.globeButtonSection).click();
await app1.client.element(ConversationPage.createClosedGroupButton).click();
// 3. Add all three to the group
await common.makeFriends(app1, [app3, common.TEST_PUBKEY3]); await common.addFriendToNewClosedGroup([app1, app2, app3], useSenderKeys);
// const text1 = await generateAndSendMessage(app1); // 4. Test that all members can see the message from app1
const text1 = await generateAndSendMessage(app1);
await app2.client.waitForExist(
ConversationPage.existingReceivedMessageText(text1),
5000
);
await app3.client.waitForExist(
ConversationPage.existingReceivedMessageText(text1),
5000
);
// TODO: test that B and C can send messages to the group
// const text2 = await generateAndSendMessage(app3);
// // validate that the message has been added to the message list view
// await app2.client.waitForExist( // await app2.client.waitForExist(
// ConversationPage.existingReceivedMessageText(text1), // ConversationPage.existingReceivedMessageText(text2),
// 5000 // 5000
// ); // );
}
// // validate that the message has been added to the message list view describe('senderkeys', function() {
// await app3.client.waitForExist( let app;
// ConversationPage.existingReceivedMessageText(text1),
// 5000
// );
// TODO: test that B and C can send messages to the group this.timeout(600000);
this.slow(40000);
beforeEach(async () => {
await common.killallElectron();
await common.stopStubSnodeServer();
});
afterEach(async () => {
await common.stopApp(app);
await common.killallElectron();
await common.stopStubSnodeServer();
}); });
it('Two member group', testTwoMembers);
it('Three member group: test session requests', testThreeMembers);
}); });

@ -0,0 +1,10 @@
/* global log */
class StubLokiSnodeAPI {
// eslint-disable-next-line class-methods-use-this
async refreshSwarmNodesForPubKey(pubKey) {
log.info('refreshSwarmNodesForPubkey: ', pubKey);
}
}
module.exports = StubLokiSnodeAPI;

@ -1,4 +1,4 @@
/* global clearTimeout, dcodeIO, Buffer, TextDecoder, process */ /* global clearTimeout, dcodeIO, Buffer, TextDecoder, process, log */
const nodeFetch = require('node-fetch'); const nodeFetch = require('node-fetch');
class StubMessageAPI { class StubMessageAPI {
@ -26,6 +26,35 @@ class StubMessageAPI {
); );
} }
async pollForGroupId(groupId, onMessages) {
const get = {
method: 'GET',
};
const res = await nodeFetch(
`${this.baseUrl}/messages?pubkey=${groupId}`,
get
);
try {
const json = await res.json();
const modifiedMessages = json.messages.map(m => {
// eslint-disable-next-line no-param-reassign
m.conversationId = groupId;
return m;
});
onMessages(modifiedMessages || []);
} catch (e) {
log.error('invalid json for GROUP', e);
onMessages([]);
}
setTimeout(() => {
this.pollForGroupId(groupId, onMessages);
}, 1000);
}
async startLongPolling(numConnections, stopPolling, callback) { async startLongPolling(numConnections, stopPolling, callback) {
const ourPubkey = this.ourKey; const ourPubkey = this.ourKey;
@ -36,10 +65,15 @@ class StubMessageAPI {
`${this.baseUrl}/messages?pubkey=${ourPubkey}`, `${this.baseUrl}/messages?pubkey=${ourPubkey}`,
get get
); );
const json = await res.json();
// console.warn('STUBBED polling messages ', json.messages);
try {
const json = await res.json();
callback(json.messages || []); callback(json.messages || []);
} catch (e) {
log.error('invalid json: ', e);
callback([]);
}
// console.warn('STUBBED polling messages ', json.messages);
} }
} }

@ -37,6 +37,7 @@
"test-electron": "yarn grunt test", "test-electron": "yarn grunt test",
"test-integration": "ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js", "test-integration": "ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js",
"test-integration-parts": "ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'registration' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'openGroup' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'addFriends' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'linkDevice' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'closedGroup'", "test-integration-parts": "ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'registration' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'openGroup' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'addFriends' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'linkDevice' && ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'closedGroup'",
"test-medium-groups": "ELECTRON_DISABLE_SANDBOX=1 mocha --exit --timeout 10000 integration_test/integration_test.js --grep 'senderkeys'",
"test-node": "mocha --recursive --exit test/app test/modules ts/test libloki/test/node", "test-node": "mocha --recursive --exit test/app test/modules ts/test libloki/test/node",
"eslint": "eslint --cache .", "eslint": "eslint --cache .",
"eslint-fix": "eslint --fix .", "eslint-fix": "eslint --fix .",

@ -342,6 +342,7 @@ window.LokiMessageAPI = require('./js/modules/loki_message_api');
if (process.env.USE_STUBBED_NETWORK) { if (process.env.USE_STUBBED_NETWORK) {
window.StubMessageAPI = require('./integration_test/stubs/stub_message_api'); window.StubMessageAPI = require('./integration_test/stubs/stub_message_api');
window.StubAppDotNetApi = require('./integration_test/stubs/stub_app_dot_net_api'); window.StubAppDotNetApi = require('./integration_test/stubs/stub_app_dot_net_api');
window.StubLokiSnodeAPI = require('./integration_test/stubs/stub_loki_snode_api');
} }
window.LokiPublicChatAPI = require('./js/modules/loki_public_chat_api'); window.LokiPublicChatAPI = require('./js/modules/loki_public_chat_api');
@ -456,7 +457,7 @@ if (
}; };
/* eslint-enable global-require, import/no-extraneous-dependencies */ /* eslint-enable global-require, import/no-extraneous-dependencies */
window.lokiFeatureFlags = {}; window.lokiFeatureFlags = {};
window.lokiSnodeAPI = {}; // no need stub out each function here window.lokiSnodeAPI = new window.StubLokiSnodeAPI(); // no need stub out each function here
} }
if (config.environment.includes('test-integration')) { if (config.environment.includes('test-integration')) {
window.lokiFeatureFlags = { window.lokiFeatureFlags = {

@ -108,9 +108,10 @@ export class InviteFriendsDialog extends React.Component<Props, State> {
private renderMemberList() { private renderMemberList() {
const members = this.state.friendList; const members = this.state.friendList;
return members.map((member: ContactType) => ( return members.map((member: ContactType, index: number) => (
<SessionMemberListItem <SessionMemberListItem
member={member} member={member}
index={index}
isSelected={false} isSelected={false}
onSelect={(selectedMember: ContactType) => { onSelect={(selectedMember: ContactType) => {
this.onMemberClicked(selectedMember); this.onMemberClicked(selectedMember);

@ -147,9 +147,10 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> {
private renderMemberList() { private renderMemberList() {
const members = this.state.friendList; const members = this.state.friendList;
return members.map((member: ContactType) => ( return members.map((member: ContactType, index: number) => (
<SessionMemberListItem <SessionMemberListItem
member={member} member={member}
index={index}
isSelected={!member.checkmarked} isSelected={!member.checkmarked}
onSelect={this.onMemberClicked} onSelect={this.onMemberClicked}
onUnselect={this.onMemberClicked} onUnselect={this.onMemberClicked}

@ -123,6 +123,7 @@ export class LeftPaneSectionHeader extends React.Component<Props, State> {
count={notificationCount} count={notificationCount}
size={NotificationCountSize.ON_HEADER} size={NotificationCountSize.ON_HEADER}
onClick={this.props.buttonClicked} onClick={this.props.buttonClicked}
key="notificationCount"
/> />
); );
} }

@ -282,9 +282,10 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
} }
private renderMemberList(members: any) { private renderMemberList(members: any) {
return members.map((member: ContactType) => ( return members.map((member: ContactType, index: number) => (
<SessionMemberListItem <SessionMemberListItem
member={member} member={member}
index={index}
isSelected={false} isSelected={false}
key={member.id} key={member.id}
onSelect={(selectedMember: ContactType) => { onSelect={(selectedMember: ContactType) => {

@ -18,6 +18,7 @@ export interface ContactType {
interface Props { interface Props {
member: ContactType; member: ContactType;
index: number; // index in the list
isSelected: boolean; isSelected: boolean;
onSelect?: any; onSelect?: any;
onUnselect?: any; onUnselect?: any;
@ -54,7 +55,11 @@ export class SessionMemberListItem extends React.Component<Props, State> {
return ( return (
<div <div
className={classNames('session-member-item', isSelected && 'selected')} className={classNames(
`session-member-item-${this.props.index}`,
'session-member-item',
isSelected && 'selected'
)}
onClick={this.handleSelectionAction} onClick={this.handleSelectionAction}
role="button" role="button"
> >

Loading…
Cancel
Save