From d91d1932f48cc641bf9acc50875a616b1232fa4d Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 28 Feb 2018 14:52:53 +0000 Subject: [PATCH] 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. --- src/MatrixClientPeg.js | 2 +- .../views/rooms/RoomSettings-test.js | 192 ++++++++++++++++++ test/test-utils.js | 14 +- 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 test/components/views/rooms/RoomSettings-test.js diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 14dfa91fa4..99841c986e 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -175,4 +175,4 @@ class MatrixClientPeg { if (!global.mxMatrixClientPeg) { global.mxMatrixClientPeg = new MatrixClientPeg(); } -module.exports = global.mxMatrixClientPeg; +export default global.mxMatrixClientPeg; diff --git a/test/components/views/rooms/RoomSettings-test.js b/test/components/views/rooms/RoomSettings-test.js new file mode 100644 index 0000000000..12fb734bf4 --- /dev/null +++ b/test/components/views/rooms/RoomSettings-test.js @@ -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( + , + 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(); + }); + }); +}); diff --git a/test/test-utils.js b/test/test-utils.js index 5753c02665..b593761bd4 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -68,6 +68,8 @@ export function createTestClient() { return { getHomeserverUrl: sinon.stub(), getIdentityServerUrl: sinon.stub(), + getDomain: sinon.stub().returns("matrix.rog"), + getUserId: sinon.stub().returns("@userId:matrix.rog"), getPushActionsForEvent: sinon.stub(), getRoom: sinon.stub().returns(mkStubRoom()), @@ -81,6 +83,7 @@ export function createTestClient() { paginateEventTimeline: sinon.stub().returns(Promise.resolve()), sendReadReceipt: sinon.stub().returns(Promise.resolve()), getRoomIdForAlias: sinon.stub().returns(Promise.resolve()), + getRoomDirectoryVisibility: sinon.stub().returns(Promise.resolve()), getProfileInfo: sinon.stub().returns(Promise.resolve({})), getAccountData: (type) => { return mkEvent({ @@ -244,6 +247,7 @@ export function mkStubRoom(roomId = null) { roomId: roomId, getAvatarUrl: () => 'mxc://avatar.url/image.png', }), + getMembersWithMembership: sinon.stub().returns([]), getJoinedMembers: sinon.stub().returns([]), getPendingEvents: () => [], getLiveTimeline: () => stubTimeline, @@ -252,8 +256,16 @@ export function mkStubRoom(roomId = null) { hasMembershipState: () => null, currentState: { getStateEvents: sinon.stub(), + mayClientSendStateEvent: sinon.stub().returns(true), + maySendStateEvent: sinon.stub().returns(true), members: [], }, + tags: { + "m.favourite": { + order: 0.5, + }, + }, + setBlacklistUnverifiedDevices: sinon.stub(), }; } @@ -284,7 +296,7 @@ export function wrapInMatrixClientContext(WrappedComponent) { } render() { - return ; + return ; } } return Wrapper;