Add tests for RoomSettings

For setting:
 - name
 - topic
 - history visibility
 - power levels

Testing RoomSettings required more stubbing on the matrix client.

The power level tests should be failing at this commit, with
fixes being made in upcoming commits.

Some tests are marked as known failures that we should fix but
aren't necessarily bugs:
 - SettingStore.setValue is used when saving despite the user not
   having made a change.
 - Testing directory publicity changes cannot be tested because we
   update state asynchronously in componentWillMount (which we do
   not block on in beforeEach).

Also, we needed to use `export default` to make sure everything
uses the same client peg and client.
This commit is contained in:
Luke Barnard 2018-02-28 14:52:53 +00:00
parent 3552800d19
commit d91d1932f4
3 changed files with 206 additions and 2 deletions

View file

@ -175,4 +175,4 @@ class MatrixClientPeg {
if (!global.mxMatrixClientPeg) { if (!global.mxMatrixClientPeg) {
global.mxMatrixClientPeg = new MatrixClientPeg(); global.mxMatrixClientPeg = new MatrixClientPeg();
} }
module.exports = global.mxMatrixClientPeg; export default global.mxMatrixClientPeg;

View file

@ -0,0 +1,192 @@
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import ReactDOM from 'react-dom';
import expect, {createSpy} from 'expect';
import sinon from 'sinon';
import Promise from 'bluebird';
import * as testUtils from '../../../test-utils';
import sdk from 'matrix-react-sdk';
const WrappedRoomSettings = testUtils.wrapInMatrixClientContext(sdk.getComponent('views.rooms.RoomSettings'));
import MatrixClientPeg from '../../../../src/MatrixClientPeg';
import SettingsStore from '../../../../src/settings/SettingsStore';
describe('RoomSettings', () => {
let parentDiv = null;
let sandbox = null;
let client = null;
let roomSettings = null;
const room = testUtils.mkStubRoom('!DdJkzRliezrwpNebLk:matrix.org');
function expectSentStateEvent(roomId, eventType, expectedEventContent) {
let found = false;
for (const call of client.sendStateEvent.calls) {
const [
actualRoomId,
actualEventType,
actualEventContent,
] = call.arguments.slice(0, 3);
if (roomId === actualRoomId && actualEventType === eventType) {
expect(actualEventContent).toEqual(expectedEventContent);
found = true;
break;
}
}
expect(found).toBe(true);
}
beforeEach(function(done) {
testUtils.beforeEach(this);
sandbox = testUtils.stubClient();
client = MatrixClientPeg.get();
client.credentials = {userId: '@me:domain.com'};
client.setRoomName = createSpy().andReturn(Promise.resolve());
client.setRoomTopic = createSpy().andReturn(Promise.resolve());
client.setRoomDirectoryVisibility = createSpy().andReturn(Promise.resolve());
// Covers any room state event (e.g. name, avatar, topic)
client.sendStateEvent = createSpy().andReturn(Promise.resolve());
// Covers room tagging
client.setRoomTag = createSpy().andReturn(Promise.resolve());
client.deleteRoomTag = createSpy().andReturn(Promise.resolve());
// Covers any setting in the SettingsStore
// (including local client settings not stored via matrix)
SettingsStore.setValue = createSpy().andReturn(Promise.resolve());
parentDiv = document.createElement('div');
document.body.appendChild(parentDiv);
const gatherWrappedRef = (r) => {roomSettings = r;};
// get use wrappedRef because we're using wrapInMatrixClientContext
ReactDOM.render(
<WrappedRoomSettings
wrappedRef={gatherWrappedRef}
room={room}
/>,
parentDiv,
done,
);
});
afterEach((done) => {
if (parentDiv) {
ReactDOM.unmountComponentAtNode(parentDiv);
parentDiv.remove();
parentDiv = null;
}
sandbox.restore();
done();
});
it('should not set when no setting is changed', (done) => {
roomSettings.save().then(() => {
expect(client.sendStateEvent).toNotHaveBeenCalled();
expect(client.setRoomTag).toNotHaveBeenCalled();
expect(client.deleteRoomTag).toNotHaveBeenCalled();
done();
});
});
// XXX: Apparently we do call SettingsStore.setValue
xit('should not settings via the SettingsStore when no setting is changed', (done) => {
roomSettings.save().then(() => {
expect(SettingsStore.setValue).toNotHaveBeenCalled();
done();
});
});
it('should set room name when it has changed', (done) => {
const name = "My Room Name";
roomSettings.setName(name);
roomSettings.save().then(() => {
expect(client.setRoomName.calls[0].arguments.slice(0, 2))
.toEqual(['!DdJkzRliezrwpNebLk:matrix.org', name]);
done();
});
});
it('should set room topic when it has changed', (done) => {
const topic = "this is a topic";
roomSettings.setTopic(topic);
roomSettings.save().then(() => {
expect(client.setRoomTopic.calls[0].arguments.slice(0, 2))
.toEqual(['!DdJkzRliezrwpNebLk:matrix.org', topic]);
done();
});
});
it('should set history visibility when it has changed', (done) => {
const historyVisibility = "translucent";
roomSettings.setState({
history_visibility: historyVisibility,
});
roomSettings.save().then(() => {
expectSentStateEvent(
"!DdJkzRliezrwpNebLk:matrix.org",
"m.room.history_visibility", {history_visibility: historyVisibility},
);
done();
});
});
// XXX: Can't test this because we `getRoomDirectoryVisibility` in `componentWillMount`
xit('should set room directory publicity when set to true', (done) => {
const isRoomPublished = true;
roomSettings.setState({
isRoomPublished,
}, () => {
roomSettings.save().then(() => {
expect(client.setRoomDirectoryVisibility.calls[0].arguments.slice(0, 2))
.toEqual("!DdJkzRliezrwpNebLk:matrix.org", isRoomPublished ? "public" : "private");
done();
});
});
});
it('should set power levels when changed', (done) => {
roomSettings.onPowerLevelsChanged(42, "invite");
roomSettings.save().then(() => {
expectSentStateEvent(
"!DdJkzRliezrwpNebLk:matrix.org",
"m.room.power_levels", { invite: 42 },
);
done();
});
});
it('should set event power levels when changed', (done) => {
roomSettings.onPowerLevelsChanged(42, "event_levels_m.room.message");
roomSettings.save().then(() => {
// We expect all state events to be set to the state_default (50)
// See powerLevelDescriptors in RoomSettings
expectSentStateEvent(
"!DdJkzRliezrwpNebLk:matrix.org",
"m.room.power_levels", {
events: {
'm.room.message': 42,
'm.room.avatar': 50,
'm.room.name': 50,
'm.room.canonical_alias': 50,
'm.room.history_visibility': 50,
'm.room.power_levels': 50,
'm.room.topic': 50,
'im.vector.modular.widgets': 50,
},
},
);
done();
});
});
});

View file

@ -68,6 +68,8 @@ export function createTestClient() {
return { return {
getHomeserverUrl: sinon.stub(), getHomeserverUrl: sinon.stub(),
getIdentityServerUrl: sinon.stub(), getIdentityServerUrl: sinon.stub(),
getDomain: sinon.stub().returns("matrix.rog"),
getUserId: sinon.stub().returns("@userId:matrix.rog"),
getPushActionsForEvent: sinon.stub(), getPushActionsForEvent: sinon.stub(),
getRoom: sinon.stub().returns(mkStubRoom()), getRoom: sinon.stub().returns(mkStubRoom()),
@ -81,6 +83,7 @@ export function createTestClient() {
paginateEventTimeline: sinon.stub().returns(Promise.resolve()), paginateEventTimeline: sinon.stub().returns(Promise.resolve()),
sendReadReceipt: sinon.stub().returns(Promise.resolve()), sendReadReceipt: sinon.stub().returns(Promise.resolve()),
getRoomIdForAlias: sinon.stub().returns(Promise.resolve()), getRoomIdForAlias: sinon.stub().returns(Promise.resolve()),
getRoomDirectoryVisibility: sinon.stub().returns(Promise.resolve()),
getProfileInfo: sinon.stub().returns(Promise.resolve({})), getProfileInfo: sinon.stub().returns(Promise.resolve({})),
getAccountData: (type) => { getAccountData: (type) => {
return mkEvent({ return mkEvent({
@ -244,6 +247,7 @@ export function mkStubRoom(roomId = null) {
roomId: roomId, roomId: roomId,
getAvatarUrl: () => 'mxc://avatar.url/image.png', getAvatarUrl: () => 'mxc://avatar.url/image.png',
}), }),
getMembersWithMembership: sinon.stub().returns([]),
getJoinedMembers: sinon.stub().returns([]), getJoinedMembers: sinon.stub().returns([]),
getPendingEvents: () => [], getPendingEvents: () => [],
getLiveTimeline: () => stubTimeline, getLiveTimeline: () => stubTimeline,
@ -252,8 +256,16 @@ export function mkStubRoom(roomId = null) {
hasMembershipState: () => null, hasMembershipState: () => null,
currentState: { currentState: {
getStateEvents: sinon.stub(), getStateEvents: sinon.stub(),
mayClientSendStateEvent: sinon.stub().returns(true),
maySendStateEvent: sinon.stub().returns(true),
members: [], members: [],
}, },
tags: {
"m.favourite": {
order: 0.5,
},
},
setBlacklistUnverifiedDevices: sinon.stub(),
}; };
} }
@ -284,7 +296,7 @@ export function wrapInMatrixClientContext(WrappedComponent) {
} }
render() { render() {
return <WrappedComponent {...this.props} />; return <WrappedComponent ref={this.props.wrappedRef} {...this.props} />;
} }
} }
return Wrapper; return Wrapper;