diff --git a/cypress/global.d.ts b/cypress/global.d.ts
index a3e91a2b44..de4c10a895 100644
--- a/cypress/global.d.ts
+++ b/cypress/global.d.ts
@@ -15,9 +15,17 @@ limitations under the License.
*/
import "matrix-js-sdk/src/@types/global";
-import type { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client";
-import type { MatrixScheduler, MemoryCryptoStore, MemoryStore, RoomStateEvent } from "matrix-js-sdk/src/matrix";
-import type { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member";
+import type {
+ MatrixClient,
+ ClientEvent,
+ MatrixScheduler,
+ MemoryCryptoStore,
+ MemoryStore,
+ Preset,
+ RoomStateEvent,
+ Visibility,
+ RoomMemberEvent,
+} from "matrix-js-sdk/src/matrix";
import type { WebStorageSessionStore } from "matrix-js-sdk/src/store/session/webstorage";
import type { MatrixDispatcher } from "../src/dispatcher/dispatcher";
import type PerformanceMonitor from "../src/performance";
@@ -42,6 +50,8 @@ declare global {
MemoryStore: typeof MemoryStore;
MemoryCryptoStore: typeof MemoryCryptoStore;
WebStorageSessionStore: typeof WebStorageSessionStore;
+ Visibility: typeof Visibility;
+ Preset: typeof Preset;
};
}
}
diff --git a/cypress/integration/11-room-directory/room-directory.spec.ts b/cypress/integration/11-room-directory/room-directory.spec.ts
new file mode 100644
index 0000000000..e7e3c5c9c8
--- /dev/null
+++ b/cypress/integration/11-room-directory/room-directory.spec.ts
@@ -0,0 +1,103 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+///
+
+import { SynapseInstance } from "../../plugins/synapsedocker";
+import { MatrixClient } from "../../global";
+
+describe("Room Directory", () => {
+ let synapse: SynapseInstance;
+
+ beforeEach(() => {
+ cy.startSynapse("default").then(data => {
+ synapse = data;
+
+ cy.initTestUser(synapse, "Ray");
+ cy.getBot(synapse, "Paul").as("bot");
+ });
+ });
+
+ afterEach(() => {
+ cy.stopSynapse(synapse);
+ });
+
+ it("should allow admin to add alias & publish room to directory", () => {
+ cy.window({ log: false }).then(win => {
+ cy.createRoom({
+ name: "Gaming",
+ preset: win.matrixcs.Preset.PublicChat,
+ }).as("roomId");
+ });
+
+ cy.viewRoomByName("Gaming");
+ cy.openRoomSettings();
+
+ // First add a local address `gaming`
+ cy.contains(".mx_SettingsFieldset", "Local Addresses").within(() => {
+ cy.get(".mx_Field input").type("gaming");
+ cy.contains(".mx_AccessibleButton", "Add").click();
+ cy.get(".mx_EditableItem_item").should("contain", "#gaming:localhost");
+ });
+
+ // Publish into the public rooms directory
+ cy.contains(".mx_SettingsFieldset", "Published Addresses").within(() => {
+ cy.get("#canonicalAlias").find(":selected").should("contain", "#gaming:localhost");
+ cy.get(`[aria-label="Publish this room to the public in localhost's room directory?"]`).click()
+ .should("have.attr", "aria-checked", "true");
+ });
+
+ cy.closeDialog();
+
+ cy.all([
+ cy.get("@bot"),
+ cy.get("@roomId"),
+ ]).then(async ([bot, roomId]) => {
+ const resp = await bot.publicRooms({});
+ expect(resp.total_room_count_estimate).to.equal(1);
+ expect(resp.chunk).to.have.length(1);
+ expect(resp.chunk[0].room_id).to.equal(roomId);
+ });
+ });
+
+ it("should allow finding published rooms in directory", () => {
+ const name = "This is a public room";
+ cy.all([
+ cy.window({ log: false }),
+ cy.get("@bot"),
+ ]).then(([win, bot]) => {
+ bot.createRoom({
+ visibility: win.matrixcs.Visibility.Public,
+ name,
+ room_alias_name: "test1234",
+ });
+ });
+
+ cy.get('[role="button"][aria-label="Explore rooms"]').click();
+
+ cy.get('.mx_RoomDirectory_dialogWrapper [name="dirsearch"]').type("Unknown Room");
+ cy.get(".mx_RoomDirectory_dialogWrapper h5").should("contain", 'No results for "Unknown Room"');
+ cy.get(".mx_RoomDirectory_dialogWrapper").percySnapshotElement("Room Directory - filtered no results");
+
+ cy.get('.mx_RoomDirectory_dialogWrapper [name="dirsearch"]').type("{selectAll}{backspace}test1234");
+ cy.get(".mx_RoomDirectory_dialogWrapper").contains(".mx_RoomDirectory_listItem", name)
+ .should("exist").as("resultRow");
+ cy.get(".mx_RoomDirectory_dialogWrapper").percySnapshotElement("Room Directory - filtered one result");
+ cy.get("@resultRow").find(".mx_AccessibleButton").contains("Join").click();
+
+ cy.url().should('contain', `/#/room/#test1234:localhost`);
+ });
+});
diff --git a/cypress/support/percy.ts b/cypress/support/percy.ts
index 19f60451e1..f190e7a514 100644
--- a/cypress/support/percy.ts
+++ b/cypress/support/percy.ts
@@ -37,7 +37,7 @@ declare global {
}
}
-Cypress.Commands.add("percySnapshotElement", { prevSubject: true }, (subject, name, options) => {
+Cypress.Commands.add("percySnapshotElement", { prevSubject: "element" }, (subject, name, options) => {
cy.percySnapshot(name, {
domTransformation: documentClone => scope(documentClone, subject.selector),
...options,
diff --git a/cypress/support/settings.ts b/cypress/support/settings.ts
index 4be44e2711..aed0631354 100644
--- a/cypress/support/settings.ts
+++ b/cypress/support/settings.ts
@@ -33,16 +33,22 @@ declare global {
*/
openUserSettings(tab?: string): Chainable>;
+ /**
+ * Open room settings (via room header menu), returning a handle to the resulting dialog.
+ * @param tab the name of the tab to switch to after opening, optional.
+ */
+ openRoomSettings(tab?: string): Chainable>;
+
/**
* Switch settings tab to the one by the given name, ideally call this in the context of the dialog.
* @param tab the name of the tab to switch to.
*/
- switchTabUserSettings(tab: string): Chainable>;
+ switchTab(tab: string): Chainable>;
/**
- * Close user settings, ideally call this in the context of the dialog.
+ * Close dialog, ideally call this in the context of the dialog.
*/
- closeUserSettings(): Chainable>;
+ closeDialog(): Chainable>;
/**
* Join the given beta, the `Labs` tab must already be opened,
@@ -72,18 +78,30 @@ Cypress.Commands.add("openUserSettings", (tab?: string): Chainable {
if (tab) {
- cy.switchTabUserSettings(tab);
+ cy.switchTab(tab);
}
});
});
-Cypress.Commands.add("switchTabUserSettings", (tab: string): Chainable> => {
+Cypress.Commands.add("openRoomSettings", (tab?: string): Chainable> => {
+ cy.get(".mx_RoomHeader_name").click();
+ cy.get(".mx_RoomTile_contextMenu").within(() => {
+ cy.get('[aria-label="Settings"]').click();
+ });
+ return cy.get(".mx_RoomSettingsDialog").within(() => {
+ if (tab) {
+ cy.switchTab(tab);
+ }
+ });
+});
+
+Cypress.Commands.add("switchTab", (tab: string): Chainable> => {
return cy.get(".mx_TabbedView_tabLabels").within(() => {
cy.get(".mx_TabbedView_tabLabel").contains(tab).click();
});
});
-Cypress.Commands.add("closeUserSettings", (): Chainable> => {
+Cypress.Commands.add("closeDialog", (): Chainable> => {
return cy.get('[aria-label="Close dialog"]').click();
});
diff --git a/res/css/views/avatars/_BaseAvatar.scss b/res/css/views/avatars/_BaseAvatar.scss
index 16261f000e..802a4235c1 100644
--- a/res/css/views/avatars/_BaseAvatar.scss
+++ b/res/css/views/avatars/_BaseAvatar.scss
@@ -52,3 +52,12 @@ limitations under the License.
vertical-align: top;
background-color: $background;
}
+
+// Percy screenshot test specific CSS
+@media only percy {
+ .mx_BaseAvatar_initial,
+ .mx_BaseAvatar_initial + .mx_BaseAvatar_image {
+ // Stick the default room avatar colour, so it doesn't cause a false diff on the screenshot
+ background-color: $username-variant2-color !important;
+ }
+}
diff --git a/test/end-to-end-tests/src/scenario.ts b/test/end-to-end-tests/src/scenario.ts
index 31855f29e8..1c81205e27 100644
--- a/test/end-to-end-tests/src/scenario.ts
+++ b/test/end-to-end-tests/src/scenario.ts
@@ -18,7 +18,6 @@ limitations under the License.
import { range } from './util';
import { signup } from './usecases/signup';
import { toastScenarios } from './scenarios/toast';
-import { roomDirectoryScenarios } from './scenarios/directory';
import { lazyLoadingScenarios } from './scenarios/lazy-loading';
import { e2eEncryptionScenarios } from './scenarios/e2e-encryption';
import { ElementSession } from "./session";
@@ -45,7 +44,6 @@ export async function scenario(createSession: (s: string) => Promise