Merge pull request #4919 from matrix-org/travis/room-list/enable

Enable the new room list by default
This commit is contained in:
Travis Ralston 2020-07-13 06:56:25 -06:00 committed by GitHub
commit a70e575b96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 146 additions and 97 deletions

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
$tagPanelWidth: 70px; // only applies in this file, used for calculations $tagPanelWidth: 70px; // only applies in this file, used for calculations

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
.mx_RoomBreadcrumbs2 { .mx_RoomBreadcrumbs2 {
width: 100%; width: 100%;

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
.mx_RoomSublist2 { .mx_RoomSublist2 {
// The sublist is a column of rows, essentially // The sublist is a column of rows, essentially

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
// Note: the room tile expects to be in a flexbox column container // Note: the room tile expects to be in a flexbox column container
.mx_RoomTile2 { .mx_RoomTile2 {

View file

@ -35,8 +35,8 @@ import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomLi
import {Key} from "../../Keyboard"; import {Key} from "../../Keyboard";
import IndicatorScrollbar from "../structures/IndicatorScrollbar"; import IndicatorScrollbar from "../structures/IndicatorScrollbar";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/******************************************************************* /*******************************************************************
* CAUTION * * CAUTION *

View file

@ -668,8 +668,7 @@ class LoggedInView extends React.Component<IProps, IState> {
disabled={this.props.leftDisabled} disabled={this.props.leftDisabled}
/> />
); );
if (SettingsStore.isFeatureEnabled("feature_new_room_list")) { if (SettingsStore.getValue("feature_new_room_list")) {
// TODO: Supply props like collapsed and disabled to LeftPanel2
leftPanel = ( leftPanel = (
<LeftPanel2 <LeftPanel2
isMinimized={this.props.collapseLhs || false} isMinimized={this.props.collapseLhs || false}

View file

@ -25,7 +25,7 @@ import { Key } from "../../Keyboard";
import AccessibleButton from "../views/elements/AccessibleButton"; import AccessibleButton from "../views/elements/AccessibleButton";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
/******************************************************************* /*******************************************************************
* CAUTION * * CAUTION *

View file

@ -27,8 +27,8 @@ import RoomListStore from "../../../stores/room-list/RoomListStore2";
import { DefaultTagID } from "../../../stores/room-list/models"; import { DefaultTagID } from "../../../stores/room-list/models";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/******************************************************************* /*******************************************************************
* CAUTION * * CAUTION *

View file

@ -41,8 +41,8 @@ import { Action } from "../../../dispatcher/actions";
import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload"; import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/******************************************************************* /*******************************************************************
* CAUTION * * CAUTION *

View file

@ -48,8 +48,8 @@ import { polyfillTouchEvent } from "../../../@types/polyfill";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore"; import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/******************************************************************* /*******************************************************************
* CAUTION * * CAUTION *

View file

@ -55,8 +55,8 @@ import {ActionPayload} from "../../../dispatcher/payloads";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { NotificationState } from "../../../stores/notifications/NotificationState"; import { NotificationState } from "../../../stores/notifications/NotificationState";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231 // TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/******************************************************************* /*******************************************************************
* CAUTION * * CAUTION *

View file

@ -32,12 +32,12 @@ export default class PreferencesUserSettingsTab extends React.Component {
'breadcrumbs', 'breadcrumbs',
]; ];
// TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14367
static ROOM_LIST_2_SETTINGS = [ static ROOM_LIST_2_SETTINGS = [
'breadcrumbs', 'breadcrumbs',
]; ];
// TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14367
static eligibleRoomListSettings = () => { static eligibleRoomListSettings = () => {
if (RoomListStoreTempProxy.isUsingNewStore()) { if (RoomListStoreTempProxy.isUsingNewStore()) {
return PreferencesUserSettingsTab.ROOM_LIST_2_SETTINGS; return PreferencesUserSettingsTab.ROOM_LIST_2_SETTINGS;

View file

@ -147,7 +147,8 @@ export const SETTINGS = {
default: false, default: false,
}, },
"feature_new_room_list": { "feature_new_room_list": {
isFeature: true, // TODO: Remove setting: https://github.com/vector-im/riot-web/issues/14367
// XXX: We shouldn't have non-features appear like features.
displayName: _td("Use the improved room list (will refresh to apply changes)"), displayName: _td("Use the improved room list (will refresh to apply changes)"),
supportedLevels: LEVELS_FEATURE, supportedLevels: LEVELS_FEATURE,
default: true, default: true,

View file

@ -57,7 +57,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
protected async onAction(payload: ActionPayload) { protected async onAction(payload: ActionPayload) {
if (!this.matrixClient) return; if (!this.matrixClient) return;
// TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14367
if (!RoomListStoreTempProxy.isUsingNewStore()) return; if (!RoomListStoreTempProxy.isUsingNewStore()) return;
if (payload.action === 'setting_updated') { if (payload.action === 'setting_updated') {
@ -80,7 +80,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
} }
protected async onReady() { protected async onReady() {
// TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14367
if (!RoomListStoreTempProxy.isUsingNewStore()) return; if (!RoomListStoreTempProxy.isUsingNewStore()) return;
await this.updateRooms(); await this.updateRooms();
@ -91,7 +91,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
} }
protected async onNotReady() { protected async onNotReady() {
// TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14367
if (!RoomListStoreTempProxy.isUsingNewStore()) return; if (!RoomListStoreTempProxy.isUsingNewStore()) return;
this.matrixClient.removeListener("Room.myMembership", this.onMyMembership); this.matrixClient.removeListener("Room.myMembership", this.onMyMembership);

View file

@ -99,7 +99,7 @@ class RoomListStore extends Store {
} }
_checkDisabled() { _checkDisabled() {
this.disabled = SettingsStore.isFeatureEnabled("feature_new_room_list"); this.disabled = SettingsStore.getValue("feature_new_room_list");
if (this.disabled) { if (this.disabled) {
console.warn("👋 legacy room list store has been disabled"); console.warn("👋 legacy room list store has been disabled");
} }

View file

@ -192,7 +192,7 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
protected async onAction(payload: ActionPayload) { protected async onAction(payload: ActionPayload) {
if (!this.matrixClient) return; if (!this.matrixClient) return;
// TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14231 // TODO: Remove when new room list is made the default: https://github.com/vector-im/riot-web/issues/14367
if (!RoomListStoreTempProxy.isUsingNewStore()) return; if (!RoomListStoreTempProxy.isUsingNewStore()) return;
if (payload.action === 'MatrixActions.Room.timeline' || payload.action === 'MatrixActions.Event.decrypted') { if (payload.action === 'MatrixActions.Room.timeline' || payload.action === 'MatrixActions.Event.decrypted') {

View file

@ -46,6 +46,12 @@ interface IState {
export const LISTS_UPDATE_EVENT = "lists_update"; export const LISTS_UPDATE_EVENT = "lists_update";
export class RoomListStore2 extends AsyncStore<ActionPayload> { export class RoomListStore2 extends AsyncStore<ActionPayload> {
/**
* Set to true if you're running tests on the store. Should not be touched in
* any other environment.
*/
public static TEST_MODE = false;
private _matrixClient: MatrixClient; private _matrixClient: MatrixClient;
private initialListsGenerated = false; private initialListsGenerated = false;
private enabled = false; private enabled = false;
@ -77,9 +83,43 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
return this._matrixClient; return this._matrixClient;
} }
// TODO: Remove enabled flag with the old RoomListStore: https://github.com/vector-im/riot-web/issues/14231 // Intended for test usage
public async resetStore() {
await this.reset();
this.tagWatcher = new TagWatcher(this);
this.filterConditions = [];
this.initialListsGenerated = false;
this._matrixClient = null;
this.algorithm.off(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
this.algorithm.off(FILTER_CHANGED, this.onAlgorithmListUpdated);
this.algorithm = new Algorithm();
this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
this.algorithm.on(FILTER_CHANGED, this.onAlgorithmListUpdated);
}
// Public for test usage. Do not call this.
public async makeReady(client: MatrixClient) {
// TODO: Remove with https://github.com/vector-im/riot-web/issues/14367
this.checkEnabled();
if (!this.enabled) return;
this._matrixClient = client;
// Update any settings here, as some may have happened before we were logically ready.
// Update any settings here, as some may have happened before we were logically ready.
console.log("Regenerating room lists: Startup");
await this.readAndCacheSettingsFromStore();
await this.regenerateAllLists({trigger: false});
await this.handleRVSUpdate({trigger: false}); // fake an RVS update to adjust sticky room, if needed
this.updateFn.mark(); // we almost certainly want to trigger an update.
this.updateFn.trigger();
}
// TODO: Remove enabled flag with the old RoomListStore: https://github.com/vector-im/riot-web/issues/14367
private checkEnabled() { private checkEnabled() {
this.enabled = SettingsStore.isFeatureEnabled("feature_new_room_list"); this.enabled = SettingsStore.getValue("feature_new_room_list");
if (this.enabled) { if (this.enabled) {
console.log("⚡ new room list store engaged"); console.log("⚡ new room list store engaged");
} }
@ -99,7 +139,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
* be used if the calling code will manually trigger the update. * be used if the calling code will manually trigger the update.
*/ */
private async handleRVSUpdate({trigger = true}) { private async handleRVSUpdate({trigger = true}) {
if (!this.enabled) return; // TODO: Remove with https://github.com/vector-im/riot-web/issues/14231 if (!this.enabled) return; // TODO: Remove with https://github.com/vector-im/riot-web/issues/14367
if (!this.matrixClient) return; // We assume there won't be RVS updates without a client if (!this.matrixClient) return; // We assume there won't be RVS updates without a client
const activeRoomId = RoomViewStore.getRoomId(); const activeRoomId = RoomViewStore.getRoomId();
@ -122,7 +162,14 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
if (trigger) this.updateFn.trigger(); if (trigger) this.updateFn.trigger();
} }
protected onDispatch(payload: ActionPayload) { protected async onDispatch(payload: ActionPayload) {
// When we're running tests we can't reliably use setImmediate out of timing concerns.
// As such, we use a more synchronous model.
if (RoomListStore2.TEST_MODE) {
await this.onDispatchAsync(payload);
return;
}
// We do this to intentionally break out of the current event loop task, allowing // We do this to intentionally break out of the current event loop task, allowing
// us to instead wait for a more convenient time to run our updates. // us to instead wait for a more convenient time to run our updates.
setImmediate(() => this.onDispatchAsync(payload)); setImmediate(() => this.onDispatchAsync(payload));
@ -135,19 +182,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
return; return;
} }
// TODO: Remove with https://github.com/vector-im/riot-web/issues/14231 await this.makeReady(payload.matrixClient);
this.checkEnabled();
if (!this.enabled) return;
this._matrixClient = payload.matrixClient;
// Update any settings here, as some may have happened before we were logically ready.
console.log("Regenerating room lists: Startup");
await this.readAndCacheSettingsFromStore();
await this.regenerateAllLists({trigger: false});
await this.handleRVSUpdate({trigger: false}); // fake an RVS update to adjust sticky room, if needed
this.updateFn.trigger();
return; // no point in running the next conditions - they won't match return; // no point in running the next conditions - they won't match
} }
@ -496,10 +531,13 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
/** /**
* Regenerates the room whole room list, discarding any previous results. * Regenerates the room whole room list, discarding any previous results.
*
* Note: This is only exposed externally for the tests. Do not call this from within
* the app.
* @param trigger Set to false to prevent a list update from being sent. Should only * @param trigger Set to false to prevent a list update from being sent. Should only
* be used if the calling code will manually trigger the update. * be used if the calling code will manually trigger the update.
*/ */
private async regenerateAllLists({trigger = true}) { public async regenerateAllLists({trigger = true}) {
console.warn("Regenerating all room lists"); console.warn("Regenerating all room lists");
const sorts: ITagSortingMap = {}; const sorts: ITagSortingMap = {};

View file

@ -24,11 +24,11 @@ import { ITagMap } from "./algorithms/models";
* Temporary RoomListStore proxy. Should be replaced with RoomListStore2 when * Temporary RoomListStore proxy. Should be replaced with RoomListStore2 when
* it is available to everyone. * it is available to everyone.
* *
* TODO: Delete this: https://github.com/vector-im/riot-web/issues/14231 * TODO: Delete this: https://github.com/vector-im/riot-web/issues/14367
*/ */
export class RoomListStoreTempProxy { export class RoomListStoreTempProxy {
public static isUsingNewStore(): boolean { public static isUsingNewStore(): boolean {
return SettingsStore.isFeatureEnabled("feature_new_room_list"); return SettingsStore.getValue("feature_new_room_list");
} }
public static addListener(handler: () => void): RoomListStoreTempToken { public static addListener(handler: () => void): RoomListStoreTempToken {

View file

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import ReactTestUtils from 'react-dom/test-utils'; import ReactTestUtils from 'react-dom/test-utils';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import lolex from 'lolex';
import * as TestUtils from '../../../test-utils'; import * as TestUtils from '../../../test-utils';
@ -15,11 +14,18 @@ import GroupStore from '../../../../src/stores/GroupStore.js';
import { MatrixClient, Room, RoomMember } from 'matrix-js-sdk'; import { MatrixClient, Room, RoomMember } from 'matrix-js-sdk';
import {DefaultTagID} from "../../../../src/stores/room-list/models"; import {DefaultTagID} from "../../../../src/stores/room-list/models";
import RoomListStore, {LISTS_UPDATE_EVENT, RoomListStore2} from "../../../../src/stores/room-list/RoomListStore2";
import RoomListLayoutStore from "../../../../src/stores/room-list/RoomListLayoutStore";
function generateRoomId() { function generateRoomId() {
return '!' + Math.random().toString().slice(2, 10) + ':domain'; return '!' + Math.random().toString().slice(2, 10) + ':domain';
} }
function waitForRoomListStoreUpdate() {
return new Promise((resolve) => {
RoomListStore.instance.once(LISTS_UPDATE_EVENT, () => resolve());
});
}
describe('RoomList', () => { describe('RoomList', () => {
function createRoom(opts) { function createRoom(opts) {
@ -34,7 +40,6 @@ describe('RoomList', () => {
let client = null; let client = null;
let root = null; let root = null;
const myUserId = '@me:domain'; const myUserId = '@me:domain';
let clock = null;
const movingRoomId = '!someroomid'; const movingRoomId = '!someroomid';
let movingRoom; let movingRoom;
@ -43,25 +48,25 @@ describe('RoomList', () => {
let myMember; let myMember;
let myOtherMember; let myOtherMember;
beforeEach(function() { beforeEach(async function(done) {
RoomListStore2.TEST_MODE = true;
TestUtils.stubClient(); TestUtils.stubClient();
client = MatrixClientPeg.get(); client = MatrixClientPeg.get();
client.credentials = {userId: myUserId}; client.credentials = {userId: myUserId};
//revert this to prototype method as the test-utils monkey-patches this to return a hardcoded value //revert this to prototype method as the test-utils monkey-patches this to return a hardcoded value
client.getUserId = MatrixClient.prototype.getUserId; client.getUserId = MatrixClient.prototype.getUserId;
clock = lolex.install();
DMRoomMap.makeShared(); DMRoomMap.makeShared();
parentDiv = document.createElement('div'); parentDiv = document.createElement('div');
document.body.appendChild(parentDiv); document.body.appendChild(parentDiv);
const RoomList = sdk.getComponent('views.rooms.RoomList'); const RoomList = sdk.getComponent('views.rooms.RoomList2');
const WrappedRoomList = TestUtils.wrapInMatrixClientContext(RoomList); const WrappedRoomList = TestUtils.wrapInMatrixClientContext(RoomList);
root = ReactDOM.render( root = ReactDOM.render(
<DragDropContext> <DragDropContext>
<WrappedRoomList searchFilter="" /> <WrappedRoomList searchFilter="" onResize={() => {}} />
</DragDropContext> </DragDropContext>
, parentDiv); , parentDiv);
ReactTestUtils.findRenderedComponentWithType(root, RoomList); ReactTestUtils.findRenderedComponentWithType(root, RoomList);
@ -102,23 +107,29 @@ describe('RoomList', () => {
}); });
client.getRoom = (roomId) => roomMap[roomId]; client.getRoom = (roomId) => roomMap[roomId];
// Now that everything has been set up, prepare and update the store
await RoomListStore.instance.makeReady(client);
done();
}); });
afterEach((done) => { afterEach(async (done) => {
if (parentDiv) { if (parentDiv) {
ReactDOM.unmountComponentAtNode(parentDiv); ReactDOM.unmountComponentAtNode(parentDiv);
parentDiv.remove(); parentDiv.remove();
parentDiv = null; parentDiv = null;
} }
clock.uninstall(); await RoomListLayoutStore.instance.resetLayouts();
await RoomListStore.instance.resetStore();
done(); done();
}); });
function expectRoomInSubList(room, subListTest) { function expectRoomInSubList(room, subListTest) {
const RoomSubList = sdk.getComponent('structures.RoomSubList'); const RoomSubList = sdk.getComponent('views.rooms.RoomSublist2');
const RoomTile = sdk.getComponent('views.rooms.RoomTile'); const RoomTile = sdk.getComponent('views.rooms.RoomTile2');
const subLists = ReactTestUtils.scryRenderedComponentsWithType(root, RoomSubList); const subLists = ReactTestUtils.scryRenderedComponentsWithType(root, RoomSubList);
const containingSubList = subLists.find(subListTest); const containingSubList = subLists.find(subListTest);
@ -140,20 +151,20 @@ describe('RoomList', () => {
expect(expectedRoomTile.props.room).toBe(room); expect(expectedRoomTile.props.room).toBe(room);
} }
function expectCorrectMove(oldTag, newTag) { function expectCorrectMove(oldTagId, newTagId) {
const getTagSubListTest = (tag) => { const getTagSubListTest = (tagId) => {
if (tag === undefined) return (s) => s.props.label.endsWith('Rooms'); return (s) => s.props.tagId === tagId;
return (s) => s.props.tagName === tag;
}; };
// Default to finding the destination sublist with newTag // Default to finding the destination sublist with newTag
const destSubListTest = getTagSubListTest(newTag); const destSubListTest = getTagSubListTest(newTagId);
const srcSubListTest = getTagSubListTest(oldTag); const srcSubListTest = getTagSubListTest(oldTagId);
// Set up the room that will be moved such that it has the correct state for a room in // Set up the room that will be moved such that it has the correct state for a room in
// the section for oldTag // the section for oldTagId
if (['m.favourite', 'm.lowpriority'].includes(oldTag)) movingRoom.tags = {[oldTag]: {}}; if (oldTagId === DefaultTagID.Favourite || oldTagId === DefaultTagID.LowPriority) {
if (oldTag === DefaultTagID.DM) { movingRoom.tags = {[oldTagId]: {}};
} else if (oldTagId === DefaultTagID.DM) {
// Mock inverse m.direct // Mock inverse m.direct
DMRoomMap.shared().roomToUser = { DMRoomMap.shared().roomToUser = {
[movingRoom.roomId]: '@someotheruser:domain', [movingRoom.roomId]: '@someotheruser:domain',
@ -162,17 +173,12 @@ describe('RoomList', () => {
dis.dispatch({action: 'MatrixActions.sync', prevState: null, state: 'PREPARED', matrixClient: client}); dis.dispatch({action: 'MatrixActions.sync', prevState: null, state: 'PREPARED', matrixClient: client});
clock.runAll();
expectRoomInSubList(movingRoom, srcSubListTest); expectRoomInSubList(movingRoom, srcSubListTest);
dis.dispatch({action: 'RoomListActions.tagRoom.pending', request: { dis.dispatch({action: 'RoomListActions.tagRoom.pending', request: {
oldTag, newTag, room: movingRoom, oldTagId, newTagId, room: movingRoom,
}}); }});
// Run all setTimeouts for dispatches and room list rate limiting
clock.runAll();
expectRoomInSubList(movingRoom, destSubListTest); expectRoomInSubList(movingRoom, destSubListTest);
} }
@ -269,6 +275,12 @@ describe('RoomList', () => {
}; };
GroupStore._notifyListeners(); GroupStore._notifyListeners();
// We also have to mock the client's getGroup function for the room list to filter it.
// It's not smart enough to tell the difference between a real group and a template though.
client.getGroup = (groupId) => {
return {groupId};
};
// Select tag // Select tag
dis.dispatch({action: 'select_tag', tag: '+group:domain'}, true); dis.dispatch({action: 'select_tag', tag: '+group:domain'}, true);
} }
@ -277,17 +289,14 @@ describe('RoomList', () => {
setupSelectedTag(); setupSelectedTag();
}); });
it('displays the correct rooms when the groups rooms are changed', () => { it('displays the correct rooms when the groups rooms are changed', async () => {
GroupStore.getGroupRooms = (groupId) => { GroupStore.getGroupRooms = (groupId) => {
return [movingRoom, otherRoom]; return [movingRoom, otherRoom];
}; };
GroupStore._notifyListeners(); GroupStore._notifyListeners();
// Run through RoomList debouncing await waitForRoomListStoreUpdate();
clock.runAll(); expectRoomInSubList(otherRoom, (s) => s.props.tagId === DefaultTagID.Untagged);
// By default, the test will
expectRoomInSubList(otherRoom, (s) => s.props.label.endsWith('Rooms'));
}); });
itDoesCorrectOptimisticUpdatesForDraggedRoomTiles(); itDoesCorrectOptimisticUpdatesForDraggedRoomTiles();

View file

@ -15,10 +15,12 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const {findSublist} = require("./create-room");
module.exports = async function acceptInvite(session, name) { module.exports = async function acceptInvite(session, name) {
session.log.step(`accepts "${name}" invite`); session.log.step(`accepts "${name}" invite`);
//TODO: brittle selector const inviteSublist = await findSublist(session, "invites");
const invitesHandles = await session.queryAll('.mx_RoomTile_name.mx_RoomTile_invite'); const invitesHandles = await inviteSublist.$$(".mx_RoomTile2_name");
const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => { const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => {
const text = await session.innerText(inviteHandle); const text = await session.innerText(inviteHandle);
return {inviteHandle, text}; return {inviteHandle, text};

View file

@ -16,21 +16,27 @@ limitations under the License.
*/ */
async function openRoomDirectory(session) { async function openRoomDirectory(session) {
const roomDirectoryButton = await session.query('.mx_LeftPanel_explore .mx_AccessibleButton'); const roomDirectoryButton = await session.query('.mx_LeftPanel2_exploreButton');
await roomDirectoryButton.click(); await roomDirectoryButton.click();
} }
async function findSublist(session, name) {
const sublists = await session.queryAll('.mx_RoomSublist2');
for (const sublist of sublists) {
const header = await sublist.$('.mx_RoomSublist2_headerText');
const headerText = await session.innerText(header);
if (headerText.toLowerCase().includes(name.toLowerCase())) {
return sublist;
}
}
throw new Error(`could not find room list section that contains '${name}' in header`);
}
async function createRoom(session, roomName, encrypted=false) { async function createRoom(session, roomName, encrypted=false) {
session.log.step(`creates room "${roomName}"`); session.log.step(`creates room "${roomName}"`);
const roomListHeaders = await session.queryAll('.mx_RoomSubList_labelContainer'); const roomsSublist = await findSublist(session, "rooms");
const roomListHeaderLabels = await Promise.all(roomListHeaders.map(h => session.innerText(h))); const addRoomButton = await roomsSublist.$(".mx_RoomSublist2_auxButton");
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(); await addRoomButton.click();
const roomNameInput = await session.query('.mx_CreateRoomDialog_name input'); const roomNameInput = await session.query('.mx_CreateRoomDialog_name input');
@ -51,14 +57,8 @@ async function createRoom(session, roomName, encrypted=false) {
async function createDm(session, invitees) { async function createDm(session, invitees) {
session.log.step(`creates DM with ${JSON.stringify(invitees)}`); session.log.step(`creates DM with ${JSON.stringify(invitees)}`);
const roomListHeaders = await session.queryAll('.mx_RoomSubList_labelContainer'); const dmsSublist = await findSublist(session, "people");
const roomListHeaderLabels = await Promise.all(roomListHeaders.map(h => session.innerText(h))); const startChatButton = await dmsSublist.$(".mx_RoomSublist2_auxButton");
const dmsIndex = roomListHeaderLabels.findIndex(l => l.toLowerCase().includes('direct messages'));
if (dmsIndex === -1) {
throw new Error("could not find room list section that contains 'direct messages' in header");
}
const dmsHeader = roomListHeaders[dmsIndex];
const startChatButton = await dmsHeader.$(".mx_RoomSubList_addRoom");
await startChatButton.click(); await startChatButton.click();
const inviteesEditor = await session.query('.mx_InviteDialog_editor textarea'); const inviteesEditor = await session.query('.mx_InviteDialog_editor textarea');
@ -83,4 +83,4 @@ async function createDm(session, invitees) {
session.log.done(); session.log.done();
} }
module.exports = {openRoomDirectory, createRoom, createDm}; module.exports = {openRoomDirectory, findSublist, createRoom, createDm};