Fix tests and add general safety

We don't need the fake clock anymore, but we do have to wait for async actions to complete before moving forward.

This also exposes a number of functions for the store to be puppetted with.
This commit is contained in:
Travis Ralston 2020-07-07 15:45:59 -06:00
parent c774b88bda
commit f89fcd1fe9
2 changed files with 55 additions and 28 deletions

View file

@ -72,6 +72,34 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
return this._matrixClient; return this._matrixClient;
} }
// 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 = new Algorithm();
this.algorithm.on(LIST_UPDATED_EVENT, 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.
console.log("Regenerating room lists: Startup");
await this.readAndCacheSettingsFromStore();
await this.regenerateAllLists();
this.onRVSUpdate(); // fake an RVS update to adjust sticky room, if needed
}
// TODO: Remove enabled flag with the old RoomListStore: https://github.com/vector-im/riot-web/issues/14367 // TODO: Remove enabled flag with the old RoomListStore: https://github.com/vector-im/riot-web/issues/14367
private checkEnabled() { private checkEnabled() {
this.enabled = SettingsStore.getValue("feature_new_room_list"); this.enabled = SettingsStore.getValue("feature_new_room_list");
@ -115,17 +143,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
return; return;
} }
// TODO: Remove with https://github.com/vector-im/riot-web/issues/14367 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();
this.onRVSUpdate(); // fake an RVS update to adjust sticky room, if needed
} }
// TODO: Remove this once the RoomListStore becomes default // TODO: Remove this once the RoomListStore becomes default
@ -372,7 +390,8 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
this.emit(LISTS_UPDATE_EVENT, this); this.emit(LISTS_UPDATE_EVENT, this);
}; };
private async regenerateAllLists() { // This is only exposed externally for the tests. Do not call this within the app.
public async regenerateAllLists() {
console.warn("Regenerating all room lists"); console.warn("Regenerating all room lists");
const sorts: ITagSortingMap = {}; const sorts: ITagSortingMap = {};

View file

@ -15,11 +15,17 @@ 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} from "../../../../src/stores/room-list/RoomListStore2";
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,15 +48,13 @@ describe('RoomList', () => {
let myMember; let myMember;
let myOtherMember; let myOtherMember;
beforeEach(function() { beforeEach(async function(done) {
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');
@ -102,16 +105,22 @@ 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 RoomListStore.instance.resetLayouts();
await RoomListStore.instance.resetStore();
done(); done();
}); });
@ -127,6 +136,7 @@ describe('RoomList', () => {
try { try {
const roomTiles = ReactTestUtils.scryRenderedComponentsWithType(containingSubList, RoomTile); const roomTiles = ReactTestUtils.scryRenderedComponentsWithType(containingSubList, RoomTile);
console.info({roomTiles: roomTiles.length}); console.info({roomTiles: roomTiles.length});
console.log("IS SAME?", room === roomTiles[0].props.room, room, roomTiles[0].props.room);
expectedRoomTile = roomTiles.find((tile) => tile.props.room === room); expectedRoomTile = roomTiles.find((tile) => tile.props.room === room);
} catch (err) { } catch (err) {
// truncate the error message because it's spammy // truncate the error message because it's spammy
@ -162,17 +172,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: {
oldTagId, newTagId, 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 +274,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,16 +288,13 @@ 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();
// By default, the test will
expectRoomInSubList(otherRoom, (s) => s.props.tagId === DefaultTagID.Untagged); expectRoomInSubList(otherRoom, (s) => s.props.tagId === DefaultTagID.Untagged);
}); });