Apply prettier formatting

This commit is contained in:
Michael Weimann 2022-12-12 12:24:14 +01:00
parent 1cac306093
commit 526645c791
No known key found for this signature in database
GPG key ID: 53F535A266BB9584
1576 changed files with 65385 additions and 62478 deletions

View file

@ -23,7 +23,7 @@ describe("Composer", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
});
});
@ -42,26 +42,26 @@ describe("Composer", () => {
it("sends a message when you click send or press Enter", () => {
// Type a message
cy.get('div[contenteditable=true]').type('my message 0');
cy.get("div[contenteditable=true]").type("my message 0");
// It has not been sent yet
cy.contains('.mx_EventTile_body', 'my message 0').should('not.exist');
cy.contains(".mx_EventTile_body", "my message 0").should("not.exist");
// Click send
cy.get('div[aria-label="Send message"]').click();
// It has been sent
cy.contains('.mx_EventTile_body', 'my message 0');
cy.contains(".mx_EventTile_body", "my message 0");
// Type another and press Enter afterwards
cy.get('div[contenteditable=true]').type('my message 1{enter}');
cy.get("div[contenteditable=true]").type("my message 1{enter}");
// It was sent
cy.contains('.mx_EventTile_body', 'my message 1');
cy.contains(".mx_EventTile_body", "my message 1");
});
it("can write formatted text", () => {
cy.get('div[contenteditable=true]').type('my bold{ctrl+b} message');
cy.get("div[contenteditable=true]").type("my bold{ctrl+b} message");
cy.get('div[aria-label="Send message"]').click();
// Note: both "bold" and "message" are bold, which is probably surprising
cy.contains('.mx_EventTile_body strong', 'bold message');
cy.contains(".mx_EventTile_body strong", "bold message");
});
it("should allow user to input emoji via graphical picker", () => {
@ -74,7 +74,7 @@ describe("Composer", () => {
});
cy.get(".mx_ContextualMenu_background").click(); // Close emoji picker
cy.get('div[contenteditable=true]').type("{enter}"); // Send message
cy.get("div[contenteditable=true]").type("{enter}"); // Send message
cy.contains(".mx_EventTile_body", "😇");
});
@ -86,14 +86,14 @@ describe("Composer", () => {
it("only sends when you press Ctrl+Enter", () => {
// Type a message and press Enter
cy.get('div[contenteditable=true]').type('my message 3{enter}');
cy.get("div[contenteditable=true]").type("my message 3{enter}");
// It has not been sent yet
cy.contains('.mx_EventTile_body', 'my message 3').should('not.exist');
cy.contains(".mx_EventTile_body", "my message 3").should("not.exist");
// Press Ctrl+Enter
cy.get('div[contenteditable=true]').type('{ctrl+enter}');
cy.get("div[contenteditable=true]").type("{ctrl+enter}");
// It was sent
cy.contains('.mx_EventTile_body', 'my message 3');
cy.contains(".mx_EventTile_body", "my message 3");
});
});
});
@ -109,28 +109,28 @@ describe("Composer", () => {
it("sends a message when you click send or press Enter", () => {
// Type a message
cy.get('div[contenteditable=true]').type('my message 0');
cy.get("div[contenteditable=true]").type("my message 0");
// It has not been sent yet
cy.contains('.mx_EventTile_body', 'my message 0').should('not.exist');
cy.contains(".mx_EventTile_body", "my message 0").should("not.exist");
// Click send
cy.get('div[aria-label="Send message"]').click();
// It has been sent
cy.contains('.mx_EventTile_body', 'my message 0');
cy.contains(".mx_EventTile_body", "my message 0");
// Type another
cy.get('div[contenteditable=true]').type('my message 1');
cy.get("div[contenteditable=true]").type("my message 1");
// Press enter. Would be nice to just use {enter} but we can't because Cypress
// does not trigger an insertParagraph when you do that.
cy.get('div[contenteditable=true]').trigger('input', { inputType: "insertParagraph" });
cy.get("div[contenteditable=true]").trigger("input", { inputType: "insertParagraph" });
// It was sent
cy.contains('.mx_EventTile_body', 'my message 1');
cy.contains(".mx_EventTile_body", "my message 1");
});
it("can write formatted text", () => {
cy.get('div[contenteditable=true]').type('my {ctrl+b}bold{ctrl+b} message');
cy.get("div[contenteditable=true]").type("my {ctrl+b}bold{ctrl+b} message");
cy.get('div[aria-label="Send message"]').click();
cy.contains('.mx_EventTile_body strong', 'bold');
cy.contains(".mx_EventTile_body strong", "bold");
});
describe("when Ctrl+Enter is required to send", () => {
@ -140,15 +140,15 @@ describe("Composer", () => {
it("only sends when you press Ctrl+Enter", () => {
// Type a message and press Enter
cy.get('div[contenteditable=true]').type('my message 3');
cy.get('div[contenteditable=true]').trigger('input', { inputType: "insertParagraph" });
cy.get("div[contenteditable=true]").type("my message 3");
cy.get("div[contenteditable=true]").trigger("input", { inputType: "insertParagraph" });
// It has not been sent yet
cy.contains('.mx_EventTile_body', 'my message 3').should('not.exist');
cy.contains(".mx_EventTile_body", "my message 3").should("not.exist");
// Press Ctrl+Enter
cy.get('div[contenteditable=true]').type('{ctrl+enter}');
cy.get("div[contenteditable=true]").type("{ctrl+enter}");
// It was sent
cy.contains('.mx_EventTile_body', 'my message 3');
cy.contains(".mx_EventTile_body", "my message 3");
});
});
});

View file

@ -29,7 +29,7 @@ describe("Create Room", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Jim");

View file

@ -28,7 +28,7 @@ interface CryptoTestContext extends Mocha.Context {
}
const waitForVerificationRequest = (cli: MatrixClient): Promise<VerificationRequest> => {
return new Promise<VerificationRequest>(resolve => {
return new Promise<VerificationRequest>((resolve) => {
const onVerificationRequestEvent = (request: VerificationRequest) => {
// @ts-ignore CryptoEvent is not exported to window.matrixcs; using the string value here
cli.off("crypto.verification.request", onVerificationRequestEvent);
@ -49,7 +49,7 @@ const checkDMRoom = () => {
cy.contains(".mx_RoomView_body .mx_cryptoEvent", "Encryption enabled").should("exist");
};
const startDMWithBob = function(this: CryptoTestContext) {
const startDMWithBob = function (this: CryptoTestContext) {
cy.get('.mx_RoomList [aria-label="Start chat"]').click();
cy.get('[data-testid="invite-dialog-input"]').type(this.bob.getUserId());
cy.contains(".mx_InviteDialog_tile_nameStack_name", "Bob").click();
@ -57,11 +57,13 @@ const startDMWithBob = function(this: CryptoTestContext) {
cy.get(".mx_InviteDialog_goButton").click();
};
const testMessages = function(this: CryptoTestContext) {
const testMessages = function (this: CryptoTestContext) {
// check the invite message
cy.contains(".mx_EventTile_body", "Hey!").closest(".mx_EventTile").within(() => {
cy.get(".mx_EventTile_e2eIcon_warning").should("not.exist");
});
cy.contains(".mx_EventTile_body", "Hey!")
.closest(".mx_EventTile")
.within(() => {
cy.get(".mx_EventTile_e2eIcon_warning").should("not.exist");
});
// Bob sends a response
cy.get<Room>("@bobsRoom").then((room) => {
@ -72,28 +74,30 @@ const testMessages = function(this: CryptoTestContext) {
.should("not.have.descendants", ".mx_EventTile_e2eIcon_warning");
};
const bobJoin = function(this: CryptoTestContext) {
cy.window({ log: false }).then(async win => {
const bobRooms = this.bob.getRooms();
if (!bobRooms.length) {
await new Promise<void>(resolve => {
const onMembership = (_event) => {
this.bob.off(win.matrixcs.RoomMemberEvent.Membership, onMembership);
resolve();
};
this.bob.on(win.matrixcs.RoomMemberEvent.Membership, onMembership);
});
}
}).then(() => {
cy.botJoinRoomByName(this.bob, "Alice").as("bobsRoom");
});
const bobJoin = function (this: CryptoTestContext) {
cy.window({ log: false })
.then(async (win) => {
const bobRooms = this.bob.getRooms();
if (!bobRooms.length) {
await new Promise<void>((resolve) => {
const onMembership = (_event) => {
this.bob.off(win.matrixcs.RoomMemberEvent.Membership, onMembership);
resolve();
};
this.bob.on(win.matrixcs.RoomMemberEvent.Membership, onMembership);
});
}
})
.then(() => {
cy.botJoinRoomByName(this.bob, "Alice").as("bobsRoom");
});
cy.contains(".mx_TextualEvent", "Bob joined the room").should("exist");
};
/** configure the given MatrixClient to auto-accept any invites */
function autoJoin(client: MatrixClient) {
cy.window({ log: false }).then(async win => {
cy.window({ log: false }).then(async (win) => {
client.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => {
if (member.membership === "invite" && member.userId === client.getUserId()) {
client.joinRoom(member.roomId);
@ -103,21 +107,23 @@ function autoJoin(client: MatrixClient) {
}
const handleVerificationRequest = (request: VerificationRequest): Chainable<EmojiMapping[]> => {
return cy.wrap(new Promise<EmojiMapping[]>((resolve) => {
const onShowSas = (event: ISasEvent) => {
verifier.off("show_sas", onShowSas);
event.confirm();
verifier.done();
resolve(event.sas.emoji);
};
return cy.wrap(
new Promise<EmojiMapping[]>((resolve) => {
const onShowSas = (event: ISasEvent) => {
verifier.off("show_sas", onShowSas);
event.confirm();
verifier.done();
resolve(event.sas.emoji);
};
const verifier = request.beginKeyVerification("m.sas.v1");
verifier.on("show_sas", onShowSas);
verifier.verify();
}));
const verifier = request.beginKeyVerification("m.sas.v1");
verifier.on("show_sas", onShowSas);
verifier.verify();
}),
);
};
const verify = function(this: CryptoTestContext) {
const verify = function (this: CryptoTestContext) {
const bobsVerificationRequestPromise = waitForVerificationRequest(this.bob);
openRoomInfo().within(() => {
@ -125,14 +131,16 @@ const verify = function(this: CryptoTestContext) {
cy.contains(".mx_EntityTile_name", "Bob").click();
cy.contains(".mx_UserInfo_verifyButton", "Verify").click();
cy.contains(".mx_AccessibleButton", "Start Verification").click();
cy.wrap(bobsVerificationRequestPromise).then((verificationRequest: VerificationRequest) => {
verificationRequest.accept();
return verificationRequest;
}).as("bobsVerificationRequest");
cy.wrap(bobsVerificationRequestPromise)
.then((verificationRequest: VerificationRequest) => {
verificationRequest.accept();
return verificationRequest;
})
.as("bobsVerificationRequest");
cy.contains(".mx_AccessibleButton", "Verify by emoji").click();
cy.get<VerificationRequest>("@bobsVerificationRequest").then((request: VerificationRequest) => {
return handleVerificationRequest(request).then((emojis: EmojiMapping[]) => {
cy.get('.mx_VerificationShowSas_emojiSas_block').then((emojiBlocks) => {
cy.get(".mx_VerificationShowSas_emojiSas_block").then((emojiBlocks) => {
emojis.forEach((emoji: EmojiMapping, index: number) => {
expect(emojiBlocks[index].textContent.toLowerCase()).to.eq(emoji[0] + emoji[1]);
});
@ -145,15 +153,17 @@ const verify = function(this: CryptoTestContext) {
});
};
describe("Cryptography", function() {
beforeEach(function() {
cy.startSynapse("default").as("synapse").then((synapse: SynapseInstance) => {
cy.initTestUser(synapse, "Alice");
cy.getBot(synapse, { displayName: "Bob", autoAcceptInvites: false }).as("bob");
});
describe("Cryptography", function () {
beforeEach(function () {
cy.startSynapse("default")
.as("synapse")
.then((synapse: SynapseInstance) => {
cy.initTestUser(synapse, "Alice");
cy.getBot(synapse, { displayName: "Bob", autoAcceptInvites: false }).as("bob");
});
});
afterEach(function(this: CryptoTestContext) {
afterEach(function (this: CryptoTestContext) {
cy.stopSynapse(this.synapse);
});
@ -172,27 +182,24 @@ describe("Cryptography", function() {
return;
});
it("creating a DM should work, being e2e-encrypted / user verification", function(this: CryptoTestContext) {
it("creating a DM should work, being e2e-encrypted / user verification", function (this: CryptoTestContext) {
cy.bootstrapCrossSigning();
startDMWithBob.call(this);
// send first message
cy.get(".mx_BasicMessageComposer_input")
.click()
.should("have.focus")
.type("Hey!{enter}");
cy.get(".mx_BasicMessageComposer_input").click().should("have.focus").type("Hey!{enter}");
checkDMRoom();
bobJoin.call(this);
testMessages.call(this);
verify.call(this);
});
it("should allow verification when there is no existing DM", function(this: CryptoTestContext) {
it("should allow verification when there is no existing DM", function (this: CryptoTestContext) {
cy.bootstrapCrossSigning();
autoJoin(this.bob);
/* we need to have a room with the other user present, so we can open the verification panel */
let roomId: string;
cy.createRoom({ name: "TestRoom", invite: [this.bob.getUserId()] }).then(_room1Id => {
cy.createRoom({ name: "TestRoom", invite: [this.bob.getUserId()] }).then((_room1Id) => {
roomId = _room1Id;
cy.log(`Created test room ${roomId}`);
cy.visit(`/#/room/${roomId}`);

View file

@ -24,19 +24,14 @@ import { SynapseInstance } from "../../plugins/synapsedocker";
import Chainable = Cypress.Chainable;
const sendEvent = (roomId: string): Chainable<ISendEventResponse> => {
return cy.sendEvent(
roomId,
null,
"m.room.message" as EventType,
MessageEvent.from("Message").serialize().content,
);
return cy.sendEvent(roomId, null, "m.room.message" as EventType, MessageEvent.from("Message").serialize().content);
};
describe("Editing", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Edith").then(() => {
cy.injectAxe();
@ -50,7 +45,7 @@ describe("Editing", () => {
});
it("should close the composer when clicking save after making a change and undoing it", () => {
cy.get<string>("@roomId").then(roomId => {
cy.get<string>("@roomId").then((roomId) => {
sendEvent(roomId);
cy.visit("/#/room/" + roomId);
});

View file

@ -77,18 +77,18 @@ describe("Integration Manager: Get OpenID Token", () => {
let integrationManagerUrl: string;
beforeEach(() => {
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then(url => {
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
integrationManagerUrl = url;
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
cy.window().then(win => {
cy.window().then((win) => {
win.localStorage.setItem("mx_scalar_token", INTEGRATION_MANAGER_TOKEN);
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
});
}).then(user => {
}).then((user) => {
testUser = user;
});
@ -107,8 +107,8 @@ describe("Integration Manager: Get OpenID Token", () => {
}).as("integrationManager");
// Succeed when checking the token is valid
cy.intercept(`${integrationManagerUrl}/account?scalar_token=${INTEGRATION_MANAGER_TOKEN}*`, req => {
req.continue(res => {
cy.intercept(`${integrationManagerUrl}/account?scalar_token=${INTEGRATION_MANAGER_TOKEN}*`, (req) => {
req.continue((res) => {
return res.send(200, {
user_id: testUser.userId,
});
@ -127,16 +127,14 @@ describe("Integration Manager: Get OpenID Token", () => {
});
it("should successfully obtain an openID token", () => {
cy.all([
cy.get<{}>("@integrationManager"),
]).then(() => {
cy.all([cy.get<{}>("@integrationManager")]).then(() => {
cy.viewRoomByName(ROOM_NAME);
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl);
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
cy.get("#message-response").should('include.text', 'access_token');
cy.get("#message-response").should("include.text", "access_token");
});
});
});

View file

@ -87,8 +87,9 @@ function expectKickedMessage(shouldExist: boolean) {
cy.get(".mx_GenericEventListSummary_toggle[aria-expanded=false]").click({ multiple: true });
// Check for the event message (or lack thereof)
cy.contains(".mx_EventTile_line", `${USER_DISPLAY_NAME} removed ${BOT_DISPLAY_NAME}: ${KICK_REASON}`)
.should(shouldExist ? "exist" : "not.exist");
cy.contains(".mx_EventTile_line", `${USER_DISPLAY_NAME} removed ${BOT_DISPLAY_NAME}: ${KICK_REASON}`).should(
shouldExist ? "exist" : "not.exist",
);
}
describe("Integration Manager: Kick", () => {
@ -97,18 +98,18 @@ describe("Integration Manager: Kick", () => {
let integrationManagerUrl: string;
beforeEach(() => {
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then(url => {
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
integrationManagerUrl = url;
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
cy.window().then(win => {
cy.window().then((win) => {
win.localStorage.setItem("mx_scalar_token", INTEGRATION_MANAGER_TOKEN);
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
});
}).then(user => {
}).then((user) => {
testUser = user;
});
@ -127,8 +128,8 @@ describe("Integration Manager: Kick", () => {
}).as("integrationManager");
// Succeed when checking the token is valid
cy.intercept(`${integrationManagerUrl}/account?scalar_token=${INTEGRATION_MANAGER_TOKEN}*`, req => {
req.continue(res => {
cy.intercept(`${integrationManagerUrl}/account?scalar_token=${INTEGRATION_MANAGER_TOKEN}*`, (req) => {
req.continue((res) => {
return res.send(200, {
user_id: testUser.userId,
});
@ -149,103 +150,100 @@ describe("Integration Manager: Kick", () => {
});
it("should kick the target", () => {
cy.all([
cy.get<MatrixClient>("@bob"),
cy.get<string>("@roomId"),
cy.get<{}>("@integrationManager"),
]).then(([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`).should('exist');
cy.all([cy.get<MatrixClient>("@bob"), cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(
([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`).should("exist");
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(true);
});
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(true);
},
);
});
it("should not kick the target if lacking permissions", () => {
cy.all([
cy.get<MatrixClient>("@bob"),
cy.get<string>("@roomId"),
cy.get<{}>("@integrationManager"),
]).then(([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`).should('exist');
cy.getClient().then(async client => {
await client.sendStateEvent(roomId, 'm.room.power_levels', {
kick: 50,
users: {
[testUser.userId]: 0,
},
});
}).then(() => {
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(false);
});
});
cy.all([cy.get<MatrixClient>("@bob"), cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(
([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`).should("exist");
cy.getClient()
.then(async (client) => {
await client.sendStateEvent(roomId, "m.room.power_levels", {
kick: 50,
users: {
[testUser.userId]: 0,
},
});
})
.then(() => {
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(false);
});
},
);
});
it("should no-op if the target already left", () => {
cy.all([
cy.get<MatrixClient>("@bob"),
cy.get<string>("@roomId"),
cy.get<{}>("@integrationManager"),
]).then(([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`).should('exist').then(async () => {
await targetUser.leave(roomId);
}).then(() => {
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(false);
});
});
cy.all([cy.get<MatrixClient>("@bob"), cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(
([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`)
.should("exist")
.then(async () => {
await targetUser.leave(roomId);
})
.then(() => {
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(false);
});
},
);
});
it("should no-op if the target was banned", () => {
cy.all([
cy.get<MatrixClient>("@bob"),
cy.get<string>("@roomId"),
cy.get<{}>("@integrationManager"),
]).then(([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`).should('exist');
cy.getClient().then(async client => {
await client.ban(roomId, targetUserId);
}).then(() => {
cy.all([cy.get<MatrixClient>("@bob"), cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(
([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
cy.inviteUser(roomId, targetUserId);
cy.contains(`${BOT_DISPLAY_NAME} joined the room`).should("exist");
cy.getClient()
.then(async (client) => {
await client.ban(roomId, targetUserId);
})
.then(() => {
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(false);
});
},
);
});
it("should no-op if the target was never a room member", () => {
cy.all([cy.get<MatrixClient>("@bob"), cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(
([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(false);
});
});
});
it("should no-op if the target was never a room member", () => {
cy.all([
cy.get<MatrixClient>("@bob"),
cy.get<string>("@roomId"),
cy.get<{}>("@integrationManager"),
]).then(([targetUser, roomId]) => {
const targetUserId = targetUser.getUserId();
cy.viewRoomByName(ROOM_NAME);
openIntegrationManager();
sendActionFromIntegrationManager(integrationManagerUrl, roomId, targetUserId);
closeIntegrationManager(integrationManagerUrl);
expectKickedMessage(false);
});
},
);
});
});

View file

@ -31,11 +31,11 @@ describe("Lazy Loading", () => {
const charlies: Charly[] = [];
beforeEach(() => {
cy.window().then(win => {
cy.window().then((win) => {
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Alice");
@ -44,7 +44,7 @@ describe("Lazy Loading", () => {
displayName: "Bob",
startClient: false,
autoAcceptInvites: false,
}).then(_bob => {
}).then((_bob) => {
bob = _bob;
});
@ -54,7 +54,7 @@ describe("Lazy Loading", () => {
displayName,
startClient: false,
autoAcceptInvites: false,
}).then(client => {
}).then((client) => {
charlies[i - 1] = { displayName, client };
});
}
@ -71,15 +71,22 @@ describe("Lazy Loading", () => {
const charlyMsg2 = "how's it going??";
function setupRoomWithBobAliceAndCharlies(charlies: Charly[]) {
cy.window({ log: false }).then(win => {
return cy.wrap(bob.createRoom({
name,
room_alias_name: "lltest",
visibility: win.matrixcs.Visibility.Public,
}).then(r => r.room_id), { log: false }).as("roomId");
cy.window({ log: false }).then((win) => {
return cy
.wrap(
bob
.createRoom({
name,
room_alias_name: "lltest",
visibility: win.matrixcs.Visibility.Public,
})
.then((r) => r.room_id),
{ log: false },
)
.as("roomId");
});
cy.get<string>("@roomId").then(async roomId => {
cy.get<string>("@roomId").then(async (roomId) => {
for (const charly of charlies) {
await charly.client.joinRoom(alias);
}
@ -122,13 +129,13 @@ describe("Lazy Loading", () => {
function checkMemberList(charlies: Charly[]) {
getMemberInMemberlist("Alice").should("exist");
getMemberInMemberlist("Bob").should("exist");
charlies.forEach(charly => {
charlies.forEach((charly) => {
getMemberInMemberlist(charly.displayName).should("exist");
});
}
function checkMemberListLacksCharlies(charlies: Charly[]) {
charlies.forEach(charly => {
charlies.forEach((charly) => {
getMemberInMemberlist(charly.displayName).should("not.exist");
});
}
@ -136,7 +143,7 @@ describe("Lazy Loading", () => {
function joinCharliesWhileAliceIsOffline(charlies: Charly[]) {
cy.goOffline();
cy.get<string>("@roomId").then(async roomId => {
cy.get<string>("@roomId").then(async (roomId) => {
for (const charly of charlies) {
await charly.client.joinRoom(alias);
}
@ -163,7 +170,7 @@ describe("Lazy Loading", () => {
joinCharliesWhileAliceIsOffline(charly6to10);
checkMemberList(charly6to10);
cy.get<string>("@roomId").then(async roomId => {
cy.get<string>("@roomId").then(async (roomId) => {
for (const charly of charlies) {
await charly.client.leave(roomId);
}

View file

@ -31,10 +31,10 @@ describe("Location sharing", () => {
};
beforeEach(() => {
cy.window().then(win => {
cy.window().then((win) => {
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Tom");
@ -47,31 +47,28 @@ describe("Location sharing", () => {
it("sends and displays pin drop location message successfully", () => {
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.visit('/#/room/' + roomId);
cy.visit("/#/room/" + roomId);
});
cy.openMessageComposerOptions().within(() => {
cy.get('[aria-label="Location"]').click();
});
selectLocationShareTypeOption('Pin').click();
selectLocationShareTypeOption("Pin").click();
cy.get('#mx_LocationPicker_map').click('center');
cy.get("#mx_LocationPicker_map").click("center");
submitShareLocation();
cy.get(".mx_RoomView_body .mx_EventTile .mx_MLocationBody", { timeout: 10000 })
.should('exist')
.click();
cy.get(".mx_RoomView_body .mx_EventTile .mx_MLocationBody", { timeout: 10000 }).should("exist").click();
// clicking location tile opens maximised map
cy.get('.mx_LocationViewDialog_wrapper').should('exist');
cy.get(".mx_LocationViewDialog_wrapper").should("exist");
cy.get('[aria-label="Close dialog"]').click();
cy.get('.mx_Marker')
.should('exist');
cy.get(".mx_Marker").should("exist");
});
});

View file

@ -24,7 +24,7 @@ describe("Consent", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("consent").then(data => {
cy.startSynapse("consent").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Bob");
@ -37,7 +37,7 @@ describe("Consent", () => {
it("should prompt the user to consent to terms when server deems it necessary", () => {
// Attempt to create a room using the js-sdk which should return an error with `M_CONSENT_NOT_GIVEN`
cy.window().then(win => {
cy.window().then((win) => {
win.mxMatrixClientPeg.matrixClient.createRoom({}).catch(() => {});
// Stub `window.open` - clicking the primary button below will call it
@ -50,7 +50,7 @@ describe("Consent", () => {
cy.get(".mx_Dialog_primary").click();
});
cy.get<SinonStub>("@windowOpen").then(stub => {
cy.get<SinonStub>("@windowOpen").then((stub) => {
const url = stub.getCall(0).args[0];
// Go to Synapse's consent page and accept it

View file

@ -34,7 +34,7 @@ describe("Login", () => {
const password = "p4s5W0rD";
beforeEach(() => {
cy.startSynapse("consent").then(data => {
cy.startSynapse("consent").then((data) => {
synapse = data;
cy.registerUser(synapse, username, password);
cy.visit("/#/login");
@ -52,19 +52,19 @@ describe("Login", () => {
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
cy.get(".mx_ServerPickerDialog_continue").click();
// wait for the dialog to go away
cy.get('.mx_ServerPickerDialog').should('not.exist');
cy.get(".mx_ServerPickerDialog").should("not.exist");
cy.get("#mx_LoginForm_username").type(username);
cy.get("#mx_LoginForm_password").type(password);
cy.get(".mx_Login_submit").click();
cy.url().should('contain', '/#/home', { timeout: 30000 });
cy.url().should("contain", "/#/home", { timeout: 30000 });
});
});
describe("logout", () => {
beforeEach(() => {
cy.startSynapse("consent").then(data => {
cy.startSynapse("consent").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Erin");
});

View file

@ -33,17 +33,17 @@ describe("Polls", () => {
};
const createPoll = ({ title, options }: CreatePollOptions) => {
if (options.length < 2) {
throw new Error('Poll must have at least two options');
throw new Error("Poll must have at least two options");
}
cy.get('.mx_PollCreateDialog').within((pollCreateDialog) => {
cy.get('#poll-topic-input').type(title);
cy.get(".mx_PollCreateDialog").within((pollCreateDialog) => {
cy.get("#poll-topic-input").type(title);
options.forEach((option, index) => {
const optionId = `#pollcreate_option_${index}`;
// click 'add option' button if needed
if (pollCreateDialog.find(optionId).length === 0) {
cy.get('.mx_PollCreateDialog_addOption').scrollIntoView().click();
cy.get(".mx_PollCreateDialog_addOption").scrollIntoView().click();
}
cy.get(optionId).scrollIntoView().type(option);
});
@ -56,34 +56,32 @@ describe("Polls", () => {
};
const getPollOption = (pollId: string, optionText: string): Chainable<JQuery> => {
return getPollTile(pollId).contains('.mx_MPollBody_option .mx_StyledRadioButton', optionText);
return getPollTile(pollId).contains(".mx_MPollBody_option .mx_StyledRadioButton", optionText);
};
const expectPollOptionVoteCount = (pollId: string, optionText: string, votes: number): void => {
getPollOption(pollId, optionText).within(() => {
cy.get('.mx_MPollBody_optionVoteCount').should('contain', `${votes} vote`);
cy.get(".mx_MPollBody_optionVoteCount").should("contain", `${votes} vote`);
});
};
const botVoteForOption = (bot: MatrixClient, roomId: string, pollId: string, optionText: string): void => {
getPollOption(pollId, optionText).within(ref => {
cy.get('input[type="radio"]').invoke('attr', 'value').then(optionId => {
const pollVote = PollResponseEvent.from([optionId], pollId).serialize();
bot.sendEvent(
roomId,
pollVote.type,
pollVote.content,
);
});
getPollOption(pollId, optionText).within((ref) => {
cy.get('input[type="radio"]')
.invoke("attr", "value")
.then((optionId) => {
const pollVote = PollResponseEvent.from([optionId], pollId).serialize();
bot.sendEvent(roomId, pollVote.type, pollVote.content);
});
});
};
beforeEach(() => {
cy.enableLabsFeature("feature_thread");
cy.window().then(win => {
cy.window().then((win) => {
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Tom");
@ -96,15 +94,15 @@ describe("Polls", () => {
it("should be creatable and votable", () => {
let bot: MatrixClient;
cy.getBot(synapse, { displayName: "BotBob" }).then(_bot => {
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
bot = _bot;
});
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.inviteUser(roomId, bot.getUserId());
cy.visit('/#/room/' + roomId);
cy.visit("/#/room/" + roomId);
// wait until Bob joined
cy.contains(".mx_TextualEvent", "BotBob joined the room").should("exist");
});
@ -113,34 +111,35 @@ describe("Polls", () => {
cy.get('[aria-label="Poll"]').click();
});
cy.get('.mx_CompoundDialog').percySnapshotElement('Polls Composer');
cy.get(".mx_CompoundDialog").percySnapshotElement("Polls Composer");
const pollParams = {
title: 'Does the polls feature work?',
options: ['Yes', 'No', 'Maybe'],
title: "Does the polls feature work?",
options: ["Yes", "No", "Maybe"],
};
createPoll(pollParams);
// Wait for message to send, get its ID and save as @pollId
cy.contains(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", pollParams.title)
.invoke("attr", "data-scroll-tokens").as("pollId");
.invoke("attr", "data-scroll-tokens")
.as("pollId");
cy.get<string>("@pollId").then(pollId => {
getPollTile(pollId).percySnapshotElement('Polls Timeline tile - no votes', { percyCSS: hideTimestampCSS });
cy.get<string>("@pollId").then((pollId) => {
getPollTile(pollId).percySnapshotElement("Polls Timeline tile - no votes", { percyCSS: hideTimestampCSS });
// Bot votes 'Maybe' in the poll
botVoteForOption(bot, roomId, pollId, pollParams.options[2]);
// no votes shown until I vote, check bots vote has arrived
cy.get('.mx_MPollBody_totalVotes').should('contain', '1 vote cast');
cy.get(".mx_MPollBody_totalVotes").should("contain", "1 vote cast");
// vote 'Maybe'
getPollOption(pollId, pollParams.options[2]).click('topLeft');
getPollOption(pollId, pollParams.options[2]).click("topLeft");
// both me and bot have voted Maybe
expectPollOptionVoteCount(pollId, pollParams.options[2], 2);
// change my vote to 'Yes'
getPollOption(pollId, pollParams.options[0]).click('topLeft');
getPollOption(pollId, pollParams.options[0]).click("topLeft");
// 1 vote for yes
expectPollOptionVoteCount(pollId, pollParams.options[0], 1);
@ -161,15 +160,15 @@ describe("Polls", () => {
it("should be editable from context menu if no votes have been cast", () => {
let bot: MatrixClient;
cy.getBot(synapse, { displayName: "BotBob" }).then(_bot => {
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
bot = _bot;
});
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.inviteUser(roomId, bot.getUserId());
cy.visit('/#/room/' + roomId);
cy.visit("/#/room/" + roomId);
});
cy.openMessageComposerOptions().within(() => {
@ -177,40 +176,42 @@ describe("Polls", () => {
});
const pollParams = {
title: 'Does the polls feature work?',
options: ['Yes', 'No', 'Maybe'],
title: "Does the polls feature work?",
options: ["Yes", "No", "Maybe"],
};
createPoll(pollParams);
// Wait for message to send, get its ID and save as @pollId
cy.get(".mx_RoomView_body .mx_EventTile").contains(".mx_EventTile[data-scroll-tokens]", pollParams.title)
.invoke("attr", "data-scroll-tokens").as("pollId");
cy.get(".mx_RoomView_body .mx_EventTile")
.contains(".mx_EventTile[data-scroll-tokens]", pollParams.title)
.invoke("attr", "data-scroll-tokens")
.as("pollId");
cy.get<string>("@pollId").then(pollId => {
cy.get<string>("@pollId").then((pollId) => {
// Open context menu
getPollTile(pollId).rightclick();
// Select edit item
cy.get('.mx_ContextualMenu').within(() => {
cy.get(".mx_ContextualMenu").within(() => {
cy.get('[aria-label="Edit"]').click();
});
// Expect poll editing dialog
cy.get('.mx_PollCreateDialog');
cy.get(".mx_PollCreateDialog");
});
});
it("should not be editable from context menu if votes have been cast", () => {
let bot: MatrixClient;
cy.getBot(synapse, { displayName: "BotBob" }).then(_bot => {
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
bot = _bot;
});
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.inviteUser(roomId, bot.getUserId());
cy.visit('/#/room/' + roomId);
cy.visit("/#/room/" + roomId);
});
cy.openMessageComposerOptions().within(() => {
@ -218,51 +219,53 @@ describe("Polls", () => {
});
const pollParams = {
title: 'Does the polls feature work?',
options: ['Yes', 'No', 'Maybe'],
title: "Does the polls feature work?",
options: ["Yes", "No", "Maybe"],
};
createPoll(pollParams);
// Wait for message to send, get its ID and save as @pollId
cy.get(".mx_RoomView_body .mx_EventTile").contains(".mx_EventTile[data-scroll-tokens]", pollParams.title)
.invoke("attr", "data-scroll-tokens").as("pollId");
cy.get(".mx_RoomView_body .mx_EventTile")
.contains(".mx_EventTile[data-scroll-tokens]", pollParams.title)
.invoke("attr", "data-scroll-tokens")
.as("pollId");
cy.get<string>("@pollId").then(pollId => {
cy.get<string>("@pollId").then((pollId) => {
// Bot votes 'Maybe' in the poll
botVoteForOption(bot, roomId, pollId, pollParams.options[2]);
// wait for bot's vote to arrive
cy.get('.mx_MPollBody_totalVotes').should('contain', '1 vote cast');
cy.get(".mx_MPollBody_totalVotes").should("contain", "1 vote cast");
// Open context menu
getPollTile(pollId).rightclick();
// Select edit item
cy.get('.mx_ContextualMenu').within(() => {
cy.get(".mx_ContextualMenu").within(() => {
cy.get('[aria-label="Edit"]').click();
});
// Expect error dialog
cy.get('.mx_ErrorDialog');
cy.get(".mx_ErrorDialog");
});
});
it("should be displayed correctly in thread panel", () => {
let botBob: MatrixClient;
let botCharlie: MatrixClient;
cy.getBot(synapse, { displayName: "BotBob" }).then(_bot => {
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
botBob = _bot;
});
cy.getBot(synapse, { displayName: "BotCharlie" }).then(_bot => {
cy.getBot(synapse, { displayName: "BotCharlie" }).then((_bot) => {
botCharlie = _bot;
});
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.inviteUser(roomId, botBob.getUserId());
cy.inviteUser(roomId, botCharlie.getUserId());
cy.visit('/#/room/' + roomId);
cy.visit("/#/room/" + roomId);
// wait until the bots joined
cy.contains(".mx_TextualEvent", "and one other were invited and joined").should("exist");
});
@ -272,16 +275,17 @@ describe("Polls", () => {
});
const pollParams = {
title: 'Does the polls feature work?',
options: ['Yes', 'No', 'Maybe'],
title: "Does the polls feature work?",
options: ["Yes", "No", "Maybe"],
};
createPoll(pollParams);
// Wait for message to send, get its ID and save as @pollId
cy.contains(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", pollParams.title)
.invoke("attr", "data-scroll-tokens").as("pollId");
.invoke("attr", "data-scroll-tokens")
.as("pollId");
cy.get<string>("@pollId").then(pollId => {
cy.get<string>("@pollId").then((pollId) => {
// Bob starts thread on the poll
botBob.sendMessage(roomId, pollId, {
body: "Hello there",
@ -297,22 +301,22 @@ describe("Polls", () => {
botVoteForOption(botCharlie, roomId, pollId, pollParams.options[1]);
// no votes shown until I vote, check votes have arrived in main tl
cy.get('.mx_RoomView_body .mx_MPollBody_totalVotes').should('contain', '2 votes cast');
cy.get(".mx_RoomView_body .mx_MPollBody_totalVotes").should("contain", "2 votes cast");
// and thread view
cy.get('.mx_ThreadView .mx_MPollBody_totalVotes').should('contain', '2 votes cast');
cy.get(".mx_ThreadView .mx_MPollBody_totalVotes").should("contain", "2 votes cast");
cy.get('.mx_RoomView_body').within(() => {
cy.get(".mx_RoomView_body").within(() => {
// vote 'Maybe' in the main timeline poll
getPollOption(pollId, pollParams.options[2]).click('topLeft');
getPollOption(pollId, pollParams.options[2]).click("topLeft");
// both me and bob have voted Maybe
expectPollOptionVoteCount(pollId, pollParams.options[2], 2);
});
cy.get('.mx_ThreadView').within(() => {
cy.get(".mx_ThreadView").within(() => {
// votes updated in thread view too
expectPollOptionVoteCount(pollId, pollParams.options[2], 2);
// change my vote to 'Yes'
getPollOption(pollId, pollParams.options[0]).click('topLeft');
getPollOption(pollId, pollParams.options[0]).click("topLeft");
});
// Bob updates vote to 'No'
@ -329,11 +333,11 @@ describe("Polls", () => {
};
// check counts are correct in main timeline tile
cy.get('.mx_RoomView_body').within(() => {
cy.get(".mx_RoomView_body").within(() => {
expectVoteCounts();
});
// and in thread view tile
cy.get('.mx_ThreadView').within(() => {
cy.get(".mx_ThreadView").within(() => {
expectVoteCounts();
});
});

View file

@ -24,7 +24,7 @@ describe("Registration", () => {
beforeEach(() => {
cy.stubDefaultServer();
cy.visit("/#/register");
cy.startSynapse("consent").then(data => {
cy.startSynapse("consent").then((data) => {
synapse = data;
});
});
@ -45,7 +45,7 @@ describe("Registration", () => {
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
cy.get(".mx_ServerPickerDialog_continue").click();
// wait for the dialog to go away
cy.get('.mx_ServerPickerDialog').should('not.exist');
cy.get(".mx_ServerPickerDialog").should("not.exist");
cy.get("#mx_RegistrationForm_username").should("be.visible");
// Hide the server text as it contains the randomly allocated Synapse port
@ -75,12 +75,14 @@ describe("Registration", () => {
cy.checkA11y();
cy.get(".mx_UseCaseSelection_skip .mx_AccessibleButton").click();
cy.url().should('contain', '/#/home');
cy.url().should("contain", "/#/home");
cy.get('[aria-label="User menu"]').click();
cy.get('[aria-label="Security & Privacy"]').click();
cy.get(".mx_DevicesPanel_myDevice .mx_DevicesPanel_deviceTrust .mx_E2EIcon")
.should("have.class", "mx_E2EIcon_verified");
cy.get(".mx_DevicesPanel_myDevice .mx_DevicesPanel_deviceTrust .mx_E2EIcon").should(
"have.class",
"mx_E2EIcon_verified",
);
});
it("should require username to fulfil requirements and be available", () => {
@ -89,7 +91,7 @@ describe("Registration", () => {
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
cy.get(".mx_ServerPickerDialog_continue").click();
// wait for the dialog to go away
cy.get('.mx_ServerPickerDialog').should('not.exist');
cy.get(".mx_ServerPickerDialog").should("not.exist");
cy.get("#mx_RegistrationForm_username").should("be.visible");

View file

@ -22,7 +22,7 @@ describe("Pills", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Sally");
@ -33,7 +33,7 @@ describe("Pills", () => {
cy.stopSynapse(synapse);
});
it('should navigate clicks internally to the app', () => {
it("should navigate clicks internally to the app", () => {
const messageRoom = "Send Messages Here";
const targetLocalpart = "aliasssssssssssss";
cy.createRoom({
@ -43,34 +43,35 @@ describe("Pills", () => {
cy.createRoom({
name: messageRoom,
}).as("messageRoomId");
cy.all([
cy.get<string>("@targetRoomId"),
cy.get<string>("@messageRoomId"),
]).then(([targetRoomId, messageRoomId]) => { // discard the target room ID - we don't need it
cy.viewRoomByName(messageRoom);
cy.url().should("contain", `/#/room/${messageRoomId}`);
cy.all([cy.get<string>("@targetRoomId"), cy.get<string>("@messageRoomId")]).then(
([targetRoomId, messageRoomId]) => {
// discard the target room ID - we don't need it
cy.viewRoomByName(messageRoom);
cy.url().should("contain", `/#/room/${messageRoomId}`);
// send a message using the built-in room mention functionality (autocomplete)
cy.get(".mx_SendMessageComposer .mx_BasicMessageComposer_input")
.type(`Hello world! Join here: #${targetLocalpart.substring(0, 3)}`);
cy.get(".mx_Autocomplete_Completion_title").click();
cy.get(".mx_MessageComposer_sendMessage").click();
// send a message using the built-in room mention functionality (autocomplete)
cy.get(".mx_SendMessageComposer .mx_BasicMessageComposer_input").type(
`Hello world! Join here: #${targetLocalpart.substring(0, 3)}`,
);
cy.get(".mx_Autocomplete_Completion_title").click();
cy.get(".mx_MessageComposer_sendMessage").click();
// find the pill in the timeline and click it
cy.get(".mx_EventTile_body .mx_Pill").click();
// find the pill in the timeline and click it
cy.get(".mx_EventTile_body .mx_Pill").click();
const localUrl = `/#/room/#${targetLocalpart}:`;
// verify we landed at a sane place
cy.url().should("contain", localUrl);
const localUrl = `/#/room/#${targetLocalpart}:`;
// verify we landed at a sane place
cy.url().should("contain", localUrl);
cy.wait(250); // let the room list settle
cy.wait(250); // let the room list settle
// go back to the message room and try to click on the pill text, as a user would
cy.viewRoomByName(messageRoom);
cy.get(".mx_EventTile_body .mx_Pill .mx_Pill_linkText")
.should("have.css", "pointer-events", "none")
.click({ force: true }); // force is to ensure we bypass pointer-events
cy.url().should("contain", localUrl);
});
// go back to the message room and try to click on the pill text, as a user would
cy.viewRoomByName(messageRoom);
cy.get(".mx_EventTile_body .mx_Pill .mx_Pill_linkText")
.should("have.css", "pointer-events", "none")
.click({ force: true }); // force is to ensure we bypass pointer-events
cy.url().should("contain", localUrl);
},
);
});
});

View file

@ -46,7 +46,7 @@ describe("RightPanel", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, NAME).then(() =>
cy.window({ log: false }).then(() => {

View file

@ -23,7 +23,7 @@ describe("Room Directory", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Ray");
@ -36,7 +36,7 @@ describe("Room Directory", () => {
});
it("should allow admin to add alias & publish room to directory", () => {
cy.window({ log: false }).then(win => {
cy.window({ log: false }).then((win) => {
cy.createRoom({
name: "Gaming",
preset: win.matrixcs.Preset.PublicChat,
@ -56,16 +56,14 @@ describe("Room Directory", () => {
// 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()
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<MatrixClient>("@bot"),
cy.get<string>("@roomId"),
]).then(async ([bot, roomId]) => {
cy.all([cy.get<MatrixClient>("@bot"), cy.get<string>("@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);
@ -75,10 +73,7 @@ describe("Room Directory", () => {
it("should allow finding published rooms in directory", () => {
const name = "This is a public room";
cy.all([
cy.window({ log: false }),
cy.get<MatrixClient>("@bot"),
]).then(([win, bot]) => {
cy.all([cy.window({ log: false }), cy.get<MatrixClient>("@bot")]).then(([win, bot]) => {
bot.createRoom({
visibility: win.matrixcs.Visibility.Public,
name,
@ -89,16 +84,17 @@ describe("Room Directory", () => {
cy.get('[role="button"][aria-label="Explore rooms"]').click();
cy.get('.mx_SpotlightDialog [aria-label="Search"]').type("Unknown Room");
cy.get(".mx_SpotlightDialog .mx_SpotlightDialog_otherSearches_messageSearchText")
.should("contain", "can't find the room you're looking for");
cy.get(".mx_SpotlightDialog .mx_SpotlightDialog_otherSearches_messageSearchText").should(
"contain",
"can't find the room you're looking for",
);
cy.get(".mx_SpotlightDialog_wrapper").percySnapshotElement("Room Directory - filtered no results");
cy.get('.mx_SpotlightDialog [aria-label="Search"]').type("{selectAll}{backspace}test1234");
cy.contains(".mx_SpotlightDialog .mx_SpotlightDialog_result_publicRoomName", name)
.should("exist");
cy.contains(".mx_SpotlightDialog .mx_SpotlightDialog_result_publicRoomName", name).should("exist");
cy.get(".mx_SpotlightDialog_wrapper").percySnapshotElement("Room Directory - filtered one result");
cy.get(".mx_SpotlightDialog .mx_SpotlightDialog_option").find(".mx_AccessibleButton").contains("Join").click();
cy.url().should('contain', `/#/room/#test1234:localhost`);
cy.url().should("contain", `/#/room/#test1234:localhost`);
});
});

View file

@ -25,17 +25,20 @@ describe("Device manager", () => {
beforeEach(() => {
cy.enableLabsFeature("feature_new_device_manager");
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Alice").then(credentials => {
user = credentials;
}).then(() => {
// create some extra sessions to manage
return cy.loginUser(synapse, user.username, user.password);
}).then(() => {
return cy.loginUser(synapse, user.username, user.password);
});
cy.initTestUser(synapse, "Alice")
.then((credentials) => {
user = credentials;
})
.then(() => {
// create some extra sessions to manage
return cy.loginUser(synapse, user.username, user.password);
})
.then(() => {
return cy.loginUser(synapse, user.username, user.password);
});
});
});
@ -45,72 +48,74 @@ describe("Device manager", () => {
it("should display sessions", () => {
cy.openUserSettings("Sessions");
cy.contains('Current session').should('exist');
cy.contains("Current session").should("exist");
cy.get('[data-testid="current-session-section"]').within(() => {
cy.contains('Unverified session').should('exist');
cy.contains("Unverified session").should("exist");
});
// current session details opened
cy.get('[data-testid="current-session-toggle-details"]').click();
cy.contains('Session details').should('exist');
cy.contains("Session details").should("exist");
// close current session details
cy.get('[data-testid="current-session-toggle-details"]').click();
cy.contains('Session details').should('not.exist');
cy.contains("Session details").should("not.exist");
cy.get('[data-testid="security-recommendations-section"]').within(() => {
cy.contains('Security recommendations').should('exist');
cy.get('[data-testid="unverified-devices-cta"]').should('have.text', 'View all (3)').click();
cy.contains("Security recommendations").should("exist");
cy.get('[data-testid="unverified-devices-cta"]').should("have.text", "View all (3)").click();
});
/**
* Other sessions section
*/
cy.contains('Other sessions').should('exist');
cy.contains("Other sessions").should("exist");
// filter applied after clicking through from security recommendations
cy.get('[aria-label="Filter devices"]').should('have.text', 'Show: Unverified');
cy.get('.mx_FilteredDeviceList_list').find('.mx_FilteredDeviceList_listItem').should('have.length', 3);
cy.get('[aria-label="Filter devices"]').should("have.text", "Show: Unverified");
cy.get(".mx_FilteredDeviceList_list").find(".mx_FilteredDeviceList_listItem").should("have.length", 3);
// select two sessions
cy.get('.mx_FilteredDeviceList_list .mx_FilteredDeviceList_listItem .mx_Checkbox').first().click();
cy.get('.mx_FilteredDeviceList_list .mx_FilteredDeviceList_listItem .mx_Checkbox').last().click();
cy.get(".mx_FilteredDeviceList_list .mx_FilteredDeviceList_listItem .mx_Checkbox").first().click();
cy.get(".mx_FilteredDeviceList_list .mx_FilteredDeviceList_listItem .mx_Checkbox").last().click();
// sign out from list selection action buttons
cy.get('[data-testid="sign-out-selection-cta"]').click();
cy.get('[data-testid="dialog-primary-button"]').click();
// list updated after sign out
cy.get('.mx_FilteredDeviceList_list').find('.mx_FilteredDeviceList_listItem').should('have.length', 1);
cy.get(".mx_FilteredDeviceList_list").find(".mx_FilteredDeviceList_listItem").should("have.length", 1);
// security recommendation count updated
cy.get('[data-testid="unverified-devices-cta"]').should('have.text', 'View all (1)');
cy.get('[data-testid="unverified-devices-cta"]').should("have.text", "View all (1)");
const sessionName = `Alice's device`;
// open the first session
cy.get('.mx_FilteredDeviceList_list .mx_FilteredDeviceList_listItem').first().within(() => {
cy.get('[aria-label="Show details"]').click();
cy.get(".mx_FilteredDeviceList_list .mx_FilteredDeviceList_listItem")
.first()
.within(() => {
cy.get('[aria-label="Show details"]').click();
cy.contains('Session details').should('exist');
cy.contains("Session details").should("exist");
cy.get('[data-testid="device-heading-rename-cta"]').click();
cy.get('[data-testid="device-rename-input"]').type(sessionName);
cy.get('[data-testid="device-rename-submit-cta"]').click();
// there should be a spinner while device updates
cy.get(".mx_Spinner").should("exist");
// wait for spinner to complete
cy.get(".mx_Spinner").should("not.exist");
cy.get('[data-testid="device-heading-rename-cta"]').click();
cy.get('[data-testid="device-rename-input"]').type(sessionName);
cy.get('[data-testid="device-rename-submit-cta"]').click();
// there should be a spinner while device updates
cy.get(".mx_Spinner").should("exist");
// wait for spinner to complete
cy.get(".mx_Spinner").should("not.exist");
// session name updated in details
cy.get('.mx_DeviceDetailHeading h3').should('have.text', sessionName);
// and main list item
cy.get('.mx_DeviceTile h4').should('have.text', sessionName);
// session name updated in details
cy.get(".mx_DeviceDetailHeading h3").should("have.text", sessionName);
// and main list item
cy.get(".mx_DeviceTile h4").should("have.text", sessionName);
// sign out using the device details sign out
cy.get('[data-testid="device-detail-sign-out-cta"]').click();
});
// sign out using the device details sign out
cy.get('[data-testid="device-detail-sign-out-cta"]').click();
});
// confirm the signout
cy.get('[data-testid="dialog-primary-button"]').click();
// no other sessions or security recommendations sections when only one session
cy.contains('Other sessions').should('not.exist');
cy.get('[data-testid="security-recommendations-section"]').should('not.exist');
cy.contains("Other sessions").should("not.exist");
cy.get('[data-testid="security-recommendations-section"]').should("not.exist");
});
});

View file

@ -21,7 +21,7 @@ import { SynapseInstance } from "../../plugins/synapsedocker";
function seedLabs(synapse: SynapseInstance, labsVal: boolean | null): void {
cy.initTestUser(synapse, "Sally", () => {
// seed labs flag
cy.window({ log: false }).then(win => {
cy.window({ log: false }).then((win) => {
if (typeof labsVal === "boolean") {
// stringify boolean
win.localStorage.setItem("mx_labs_feature_feature_hidden_read_receipts", `${labsVal}`);
@ -64,7 +64,7 @@ describe("Hidden Read Receipts Setting Migration", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
});
});
@ -73,17 +73,17 @@ describe("Hidden Read Receipts Setting Migration", () => {
cy.stopSynapse(synapse);
});
it('should not migrate the lack of a labs flag', () => {
it("should not migrate the lack of a labs flag", () => {
seedLabs(synapse, null);
testForVal(null);
});
it('should migrate labsHiddenRR=false as sendRR=true', () => {
it("should migrate labsHiddenRR=false as sendRR=true", () => {
seedLabs(synapse, false);
testForVal(true);
});
it('should migrate labsHiddenRR=true as sendRR=false', () => {
it("should migrate labsHiddenRR=true as sendRR=false", () => {
seedLabs(synapse, true);
testForVal(false);
});

View file

@ -26,18 +26,17 @@ import { ProxyInstance } from "../../plugins/sliding-sync";
describe("Sliding Sync", () => {
beforeEach(() => {
cy.startSynapse("default").as("synapse").then(synapse => {
cy.startProxy(synapse).as("proxy");
});
cy.startSynapse("default")
.as("synapse")
.then((synapse) => {
cy.startProxy(synapse).as("proxy");
});
cy.all([
cy.get<SynapseInstance>("@synapse"),
cy.get<ProxyInstance>("@proxy"),
]).then(([synapse, proxy]) => {
cy.all([cy.get<SynapseInstance>("@synapse"), cy.get<ProxyInstance>("@proxy")]).then(([synapse, proxy]) => {
cy.enableLabsFeature("feature_sliding_sync");
cy.intercept("/config.json?cachebuster=*", req => {
return req.continue(res => {
cy.intercept("/config.json?cachebuster=*", (req) => {
return req.continue((res) => {
res.send(200, {
...res.body,
setting_defaults: {
@ -62,11 +61,16 @@ describe("Sliding Sync", () => {
// assert order
const checkOrder = (wantOrder: string[]) => {
cy.contains(".mx_RoomSublist", "Rooms").find(".mx_RoomTile_title").should((elements) => {
expect(_.map(elements, (e) => {
return e.textContent;
}), "rooms are sorted").to.deep.equal(wantOrder);
});
cy.contains(".mx_RoomSublist", "Rooms")
.find(".mx_RoomTile_title")
.should((elements) => {
expect(
_.map(elements, (e) => {
return e.textContent;
}),
"rooms are sorted",
).to.deep.equal(wantOrder);
});
};
const bumpRoom = (alias: string) => {
// Send a message into the given room, this should bump the room to the top
@ -80,9 +84,11 @@ describe("Sliding Sync", () => {
const createAndJoinBob = () => {
// create a Bob user
cy.get<SynapseInstance>("@synapse").then((synapse) => {
return cy.getBot(synapse, {
displayName: "Bob",
}).as("bob");
return cy
.getBot(synapse, {
displayName: "Bob",
})
.as("bob");
});
// invite Bob to Test Room and accept then send a message.
@ -95,7 +101,7 @@ describe("Sliding Sync", () => {
// sanity check everything works
it("should correctly render expected messages", () => {
cy.get<string>("@roomId").then(roomId => cy.visit("/#/room/" + roomId));
cy.get<string>("@roomId").then((roomId) => cy.visit("/#/room/" + roomId));
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.IRC);
// Wait until configuration is finished
@ -114,54 +120,52 @@ describe("Sliding Sync", () => {
cy.createRoom({ name: "Pineapple" }).then(() => cy.contains(".mx_RoomSublist", "Pineapple"));
cy.createRoom({ name: "Orange" }).then(() => cy.contains(".mx_RoomSublist", "Orange"));
// check the rooms are in the right order
cy.get(".mx_RoomTile").should('have.length', 4); // due to the Test Room in beforeEach
checkOrder([
"Orange", "Pineapple", "Apple", "Test Room",
]);
cy.get(".mx_RoomTile").should("have.length", 4); // due to the Test Room in beforeEach
checkOrder(["Orange", "Pineapple", "Apple", "Test Room"]);
cy.contains(".mx_RoomSublist", "Rooms").find(".mx_RoomSublist_menuButton").click({ force: true });
cy.contains("A-Z").click();
cy.get('.mx_StyledRadioButton_checked').should("contain.text", "A-Z");
checkOrder([
"Apple", "Orange", "Pineapple", "Test Room",
]);
cy.get(".mx_StyledRadioButton_checked").should("contain.text", "A-Z");
checkOrder(["Apple", "Orange", "Pineapple", "Test Room"]);
});
it("should move rooms around as new events arrive", () => {
// create rooms and check room names are correct
cy.createRoom({ name: "Apple" }).as("roomA").then(() => cy.contains(".mx_RoomSublist", "Apple"));
cy.createRoom({ name: "Pineapple" }).as("roomP").then(() => cy.contains(".mx_RoomSublist", "Pineapple"));
cy.createRoom({ name: "Orange" }).as("roomO").then(() => cy.contains(".mx_RoomSublist", "Orange"));
cy.createRoom({ name: "Apple" })
.as("roomA")
.then(() => cy.contains(".mx_RoomSublist", "Apple"));
cy.createRoom({ name: "Pineapple" })
.as("roomP")
.then(() => cy.contains(".mx_RoomSublist", "Pineapple"));
cy.createRoom({ name: "Orange" })
.as("roomO")
.then(() => cy.contains(".mx_RoomSublist", "Orange"));
// Select the Test Room
cy.contains(".mx_RoomTile", "Test Room").click();
checkOrder([
"Orange", "Pineapple", "Apple", "Test Room",
]);
checkOrder(["Orange", "Pineapple", "Apple", "Test Room"]);
bumpRoom("@roomA");
checkOrder([
"Apple", "Orange", "Pineapple", "Test Room",
]);
checkOrder(["Apple", "Orange", "Pineapple", "Test Room"]);
bumpRoom("@roomO");
checkOrder([
"Orange", "Apple", "Pineapple", "Test Room",
]);
checkOrder(["Orange", "Apple", "Pineapple", "Test Room"]);
bumpRoom("@roomO");
checkOrder([
"Orange", "Apple", "Pineapple", "Test Room",
]);
checkOrder(["Orange", "Apple", "Pineapple", "Test Room"]);
bumpRoom("@roomP");
checkOrder([
"Pineapple", "Orange", "Apple", "Test Room",
]);
checkOrder(["Pineapple", "Orange", "Apple", "Test Room"]);
});
it("should not move the selected room: it should be sticky", () => {
// create rooms and check room names are correct
cy.createRoom({ name: "Apple" }).as("roomA").then(() => cy.contains(".mx_RoomSublist", "Apple"));
cy.createRoom({ name: "Pineapple" }).as("roomP").then(() => cy.contains(".mx_RoomSublist", "Pineapple"));
cy.createRoom({ name: "Orange" }).as("roomO").then(() => cy.contains(".mx_RoomSublist", "Orange"));
cy.createRoom({ name: "Apple" })
.as("roomA")
.then(() => cy.contains(".mx_RoomSublist", "Apple"));
cy.createRoom({ name: "Pineapple" })
.as("roomP")
.then(() => cy.contains(".mx_RoomSublist", "Pineapple"));
cy.createRoom({ name: "Orange" })
.as("roomO")
.then(() => cy.contains(".mx_RoomSublist", "Orange"));
// Given a list of Orange, Pineapple, Apple - if Pineapple is active and a message is sent in Apple, the list should
// turn into Apple, Pineapple, Orange - the index position of Pineapple never changes even though the list should technically
@ -169,23 +173,17 @@ describe("Sliding Sync", () => {
// Select the Pineapple room
cy.contains(".mx_RoomTile", "Pineapple").click();
checkOrder([
"Orange", "Pineapple", "Apple", "Test Room",
]);
checkOrder(["Orange", "Pineapple", "Apple", "Test Room"]);
// Move Apple
bumpRoom("@roomA");
checkOrder([
"Apple", "Pineapple", "Orange", "Test Room",
]);
checkOrder(["Apple", "Pineapple", "Orange", "Test Room"]);
// Select the Test Room
cy.contains(".mx_RoomTile", "Test Room").click();
// the rooms reshuffle to match reality
checkOrder([
"Apple", "Orange", "Pineapple", "Test Room",
]);
checkOrder(["Apple", "Orange", "Pineapple", "Test Room"]);
});
it("should show the right unread notifications", () => {
@ -212,7 +210,8 @@ describe("Sliding Sync", () => {
cy.contains(".mx_RoomTile", "Test Room").should("not.have.class", "mx_NotificationBadge_count");
});
it("should not show unread indicators", () => { // TODO: for now. Later we should.
it("should not show unread indicators", () => {
// TODO: for now. Later we should.
createAndJoinBob();
// disable notifs in this room (TODO: CS API call?)
@ -223,17 +222,13 @@ describe("Sliding Sync", () => {
cy.createRoom({
name: "Dummy",
});
checkOrder([
"Dummy", "Test Room",
]);
checkOrder(["Dummy", "Test Room"]);
cy.all([cy.get<string>("@roomId"), cy.get<MatrixClient>("@bob")]).then(([roomId, bob]) => {
return bob.sendTextMessage(roomId, "Do you read me?");
});
// wait for this message to arrive, tell by the room list resorting
checkOrder([
"Test Room", "Dummy",
]);
checkOrder(["Test Room", "Dummy"]);
cy.contains(".mx_RoomTile", "Test Room").get(".mx_NotificationBadge").should("not.exist");
});
@ -242,13 +237,18 @@ describe("Sliding Sync", () => {
cy.get(".mx_UserMenu_userAvatar").click();
cy.contains("All settings").click();
cy.contains("Preferences").click();
cy.contains(".mx_SettingsFlag", "Show timestamps in 12 hour format").should("exist").find(
".mx_ToggleSwitch_on").should("not.exist");
cy.contains(".mx_SettingsFlag", "Show timestamps in 12 hour format").should("exist").find(
".mx_ToggleSwitch_ball").click();
cy.contains(".mx_SettingsFlag", "Show timestamps in 12 hour format", { timeout: 2000 }).should("exist").find(
".mx_ToggleSwitch_on", { timeout: 2000 },
).should("exist");
cy.contains(".mx_SettingsFlag", "Show timestamps in 12 hour format")
.should("exist")
.find(".mx_ToggleSwitch_on")
.should("not.exist");
cy.contains(".mx_SettingsFlag", "Show timestamps in 12 hour format")
.should("exist")
.find(".mx_ToggleSwitch_ball")
.click();
cy.contains(".mx_SettingsFlag", "Show timestamps in 12 hour format", { timeout: 2000 })
.should("exist")
.find(".mx_ToggleSwitch_on", { timeout: 2000 })
.should("exist");
});
it("should show and be able to accept/reject/rescind invites", () => {
@ -263,50 +263,56 @@ describe("Sliding Sync", () => {
// - roomJoin: will join this room
// - roomReject: will reject the invite
// - roomRescind: will make Bob rescind the invite
let roomJoin; let roomReject; let roomRescind; let bobClient;
cy.get<MatrixClient>("@bob").then((bob) => {
bobClient = bob;
return Promise.all([
bob.createRoom({ name: "Join" }),
bob.createRoom({ name: "Reject" }),
bob.createRoom({ name: "Rescind" }),
]);
}).then(([join, reject, rescind]) => {
roomJoin = join.room_id;
roomReject = reject.room_id;
roomRescind = rescind.room_id;
return Promise.all([
bobClient.invite(roomJoin, clientUserId),
bobClient.invite(roomReject, clientUserId),
bobClient.invite(roomRescind, clientUserId),
]);
});
let roomJoin;
let roomReject;
let roomRescind;
let bobClient;
cy.get<MatrixClient>("@bob")
.then((bob) => {
bobClient = bob;
return Promise.all([
bob.createRoom({ name: "Join" }),
bob.createRoom({ name: "Reject" }),
bob.createRoom({ name: "Rescind" }),
]);
})
.then(([join, reject, rescind]) => {
roomJoin = join.room_id;
roomReject = reject.room_id;
roomRescind = rescind.room_id;
return Promise.all([
bobClient.invite(roomJoin, clientUserId),
bobClient.invite(roomReject, clientUserId),
bobClient.invite(roomRescind, clientUserId),
]);
});
// wait for them all to be on the UI
cy.get(".mx_RoomTile").should('have.length', 4); // due to the Test Room in beforeEach
cy.get(".mx_RoomTile").should("have.length", 4); // due to the Test Room in beforeEach
cy.contains(".mx_RoomTile", "Join").click();
cy.contains(".mx_AccessibleButton", "Accept").click();
checkOrder([
"Join", "Test Room",
]);
checkOrder(["Join", "Test Room"]);
cy.contains(".mx_RoomTile", "Reject").click();
cy.contains(".mx_RoomView .mx_AccessibleButton", "Reject").click();
// wait for the rejected room to disappear
cy.get(".mx_RoomTile").should('have.length', 3);
cy.get(".mx_RoomTile").should("have.length", 3);
// check the lists are correct
checkOrder([
"Join", "Test Room",
]);
cy.contains(".mx_RoomSublist", "Invites").find(".mx_RoomTile_title").should((elements) => {
expect(_.map(elements, (e) => {
return e.textContent;
}), "rooms are sorted").to.deep.equal(["Rescind"]);
});
checkOrder(["Join", "Test Room"]);
cy.contains(".mx_RoomSublist", "Invites")
.find(".mx_RoomTile_title")
.should((elements) => {
expect(
_.map(elements, (e) => {
return e.textContent;
}),
"rooms are sorted",
).to.deep.equal(["Rescind"]);
});
// now rescind the invite
cy.get<MatrixClient>("@bob").then((bob) => {
@ -314,19 +320,19 @@ describe("Sliding Sync", () => {
});
// wait for the rescind to take effect and check the joined list once more
cy.get(".mx_RoomTile").should('have.length', 2);
checkOrder([
"Join", "Test Room",
]);
cy.get(".mx_RoomTile").should("have.length", 2);
checkOrder(["Join", "Test Room"]);
});
it("should show a favourite DM only in the favourite sublist", () => {
cy.createRoom({
name: "Favourite DM",
is_direct: true,
}).as("room").then(roomId => {
cy.getClient().then(cli => cli.setRoomTag(roomId, "m.favourite", { order: 0.5 }));
});
})
.as("room")
.then((roomId) => {
cy.getClient().then((cli) => cli.setRoomTag(roomId, "m.favourite", { order: 0.5 }));
});
cy.contains('.mx_RoomSublist[aria-label="Favourites"] .mx_RoomTile', "Favourite DM").should("exist");
cy.contains('.mx_RoomSublist[aria-label="People"] .mx_RoomTile', "Favourite DM").should("not.exist");
@ -335,7 +341,9 @@ describe("Sliding Sync", () => {
// Regression test for a bug in SS mode, but would be useful to have in non-SS mode too.
// This ensures we are setting RoomViewStore state correctly.
it("should clear the reply to field when swapping rooms", () => {
cy.createRoom({ name: "Other Room" }).as("roomA").then(() => cy.contains(".mx_RoomSublist", "Other Room"));
cy.createRoom({ name: "Other Room" })
.as("roomA")
.then(() => cy.contains(".mx_RoomSublist", "Other Room"));
cy.get<string>("@roomId").then((roomId) => {
return cy.sendEvent(roomId, null, "m.room.message", {
body: "Hello world",
@ -346,9 +354,9 @@ describe("Sliding Sync", () => {
cy.contains(".mx_RoomTile", "Test Room").click();
cy.get(".mx_ReplyPreview").should("not.exist");
// click reply-to on the Hello World message
cy.contains(".mx_EventTile", "Hello world").find('.mx_AccessibleButton[aria-label="Reply"]').click(
{ force: true },
);
cy.contains(".mx_EventTile", "Hello world")
.find('.mx_AccessibleButton[aria-label="Reply"]')
.click({ force: true });
// check it's visible
cy.get(".mx_ReplyPreview").should("exist");
// now click Other Room
@ -365,28 +373,31 @@ describe("Sliding Sync", () => {
it("should not cancel replies when permalinks are clicked ", () => {
cy.get<string>("@roomId").then((roomId) => {
// we require a first message as you cannot click the permalink text with the avatar in the way
return cy.sendEvent(roomId, null, "m.room.message", {
body: "First message",
msgtype: "m.text",
}).then(() => {
return cy.sendEvent(roomId, null, "m.room.message", {
body: "Permalink me",
return cy
.sendEvent(roomId, null, "m.room.message", {
body: "First message",
msgtype: "m.text",
})
.then(() => {
return cy.sendEvent(roomId, null, "m.room.message", {
body: "Permalink me",
msgtype: "m.text",
});
})
.then(() => {
cy.sendEvent(roomId, null, "m.room.message", {
body: "Reply to me",
msgtype: "m.text",
});
});
}).then(() => {
cy.sendEvent(roomId, null, "m.room.message", {
body: "Reply to me",
msgtype: "m.text",
});
});
});
// select the room
cy.contains(".mx_RoomTile", "Test Room").click();
cy.get(".mx_ReplyPreview").should("not.exist");
// click reply-to on the Reply to me message
cy.contains(".mx_EventTile", "Reply to me").find('.mx_AccessibleButton[aria-label="Reply"]').click(
{ force: true },
);
cy.contains(".mx_EventTile", "Reply to me")
.find('.mx_AccessibleButton[aria-label="Reply"]')
.click({ force: true });
// check it's visible
cy.get(".mx_ReplyPreview").should("exist");
// now click on the permalink for Permalink me

View file

@ -37,12 +37,14 @@ function spaceCreateOptions(spaceName: string): ICreateRoomOpts {
creation_content: {
type: "m.space",
},
initial_state: [{
type: "m.room.name",
content: {
name: spaceName,
initial_state: [
{
type: "m.room.name",
content: {
name: spaceName,
},
},
}],
],
};
}
@ -61,10 +63,10 @@ describe("Spaces", () => {
let user: UserCredentials;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Sue").then(_user => {
cy.initTestUser(synapse, "Sue").then((_user) => {
user = _user;
cy.mockClipboard();
});
@ -78,8 +80,10 @@ describe("Spaces", () => {
it("should allow user to create public space", () => {
openSpaceCreateMenu().within(() => {
cy.get(".mx_SpaceCreateMenuType_public").click();
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
.selectFile("cypress/fixtures/riot.png", { force: true });
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]').selectFile(
"cypress/fixtures/riot.png",
{ force: true },
);
cy.get('input[label="Name"]').type("Let's have a Riot");
cy.get('input[label="Address"]').should("have.value", "lets-have-a-riot");
cy.get('textarea[label="Description"]').type("This is a space to reminisce Riot.im!");
@ -108,8 +112,10 @@ describe("Spaces", () => {
it("should allow user to create private space", () => {
openSpaceCreateMenu().within(() => {
cy.get(".mx_SpaceCreateMenuType_private").click();
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
.selectFile("cypress/fixtures/riot.png", { force: true });
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]').selectFile(
"cypress/fixtures/riot.png",
{ force: true },
);
cy.get('input[label="Name"]').type("This is not a Riot");
cy.get('input[label="Address"]').should("not.exist");
cy.get('textarea[label="Description"]').type("This is a private space of mourning Riot.im...");
@ -145,8 +151,10 @@ describe("Spaces", () => {
openSpaceCreateMenu().within(() => {
cy.get(".mx_SpaceCreateMenuType_private").click();
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
.selectFile("cypress/fixtures/riot.png", { force: true });
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]').selectFile(
"cypress/fixtures/riot.png",
{ force: true },
);
cy.get('input[label="Address"]').should("not.exist");
cy.get('textarea[label="Description"]').type("This is a personal space to mourn Riot.im...");
cy.get('input[label="Name"]').type("This is my Riot{enter}");
@ -163,7 +171,7 @@ describe("Spaces", () => {
it("should allow user to invite another to a space", () => {
let bot: MatrixClient;
cy.getBot(synapse, { displayName: "BotBob" }).then(_bot => {
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
bot = _bot;
});
@ -198,13 +206,17 @@ describe("Spaces", () => {
});
cy.getSpacePanelButton("My Space").should("exist");
cy.getBot(synapse, { displayName: "BotBob" }).then({ timeout: 10000 }, async bot => {
cy.getBot(synapse, { displayName: "BotBob" }).then({ timeout: 10000 }, async (bot) => {
const { room_id: roomId } = await bot.createRoom(spaceCreateOptions("Space Space"));
await bot.invite(roomId, user.userId);
});
// Assert that `Space Space` is above `My Space` due to it being an invite
cy.getSpacePanelButton("Space Space").should("exist")
.parent().next().find('.mx_SpaceButton[aria-label="My Space"]').should("exist");
cy.getSpacePanelButton("Space Space")
.should("exist")
.parent()
.next()
.find('.mx_SpaceButton[aria-label="My Space"]')
.should("exist");
});
it("should include rooms in space home", () => {
@ -216,16 +228,10 @@ describe("Spaces", () => {
}).as("roomId2");
const spaceName = "Spacey Mc. Space Space";
cy.all([
cy.get<string>("@roomId1"),
cy.get<string>("@roomId2"),
]).then(([roomId1, roomId2]) => {
cy.all([cy.get<string>("@roomId1"), cy.get<string>("@roomId2")]).then(([roomId1, roomId2]) => {
cy.createSpace({
name: spaceName,
initial_state: [
spaceChildInitialState(roomId1),
spaceChildInitialState(roomId2),
],
initial_state: [spaceChildInitialState(roomId1), spaceChildInitialState(roomId2)],
}).as("spaceId");
});
@ -244,12 +250,10 @@ describe("Spaces", () => {
cy.createSpace({
name: "Child Space",
initial_state: [],
}).then(spaceId => {
}).then((spaceId) => {
cy.createSpace({
name: "Root Space",
initial_state: [
spaceChildInitialState(spaceId),
],
initial_state: [spaceChildInitialState(spaceId)],
}).as("spaceId");
});
cy.get('.mx_SpacePanel .mx_SpaceButton[aria-label="Root Space"]').should("exist");
@ -258,7 +262,7 @@ describe("Spaces", () => {
const axeOptions = {
rules: {
// Disable this check as it triggers on nested roving tab index elements which are in practice fine
'nested-interactive': {
"nested-interactive": {
enabled: false,
},
},
@ -269,8 +273,10 @@ describe("Spaces", () => {
cy.get(".mx_SpaceButton_toggleCollapse").click({ force: true });
cy.get(".mx_SpacePanel:not(.collapsed)").should("exist");
cy.contains(".mx_SpaceItem", "Root Space").should("exist")
.contains(".mx_SpaceItem", "Child Space").should("exist");
cy.contains(".mx_SpaceItem", "Root Space")
.should("exist")
.contains(".mx_SpaceItem", "Child Space")
.should("exist");
cy.checkA11y(undefined, axeOptions);
cy.get(".mx_SpacePanel").percySnapshotElement("Space panel expanded", { widths: [258] });

View file

@ -26,7 +26,7 @@ import Shadow = Cypress.Shadow;
export enum Filter {
People = "people",
PublicRooms = "public_rooms"
PublicRooms = "public_rooms",
}
declare global {
@ -37,78 +37,86 @@ declare global {
* Opens the spotlight dialog
*/
openSpotlightDialog(
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>>;
spotlightDialog(
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>>;
spotlightFilter(
filter: Filter | null,
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>>;
spotlightSearch(
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>>;
spotlightResults(
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>>;
roomHeaderName(
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>>;
startDM(name: string): Chainable<void>;
}
}
}
Cypress.Commands.add("openSpotlightDialog", (
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>> => {
cy.get('.mx_RoomSearch_spotlightTrigger', options).click({ force: true });
return cy.spotlightDialog(options);
});
Cypress.Commands.add(
"openSpotlightDialog",
(options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>> => {
cy.get(".mx_RoomSearch_spotlightTrigger", options).click({ force: true });
return cy.spotlightDialog(options);
},
);
Cypress.Commands.add("spotlightDialog", (
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>> => {
return cy.get('[role=dialog][aria-label="Search Dialog"]', options);
});
Cypress.Commands.add(
"spotlightDialog",
(options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>> => {
return cy.get('[role=dialog][aria-label="Search Dialog"]', options);
},
);
Cypress.Commands.add("spotlightFilter", (
filter: Filter | null,
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>> => {
let selector: string;
switch (filter) {
case Filter.People:
selector = "#mx_SpotlightDialog_button_startChat";
break;
case Filter.PublicRooms:
selector = "#mx_SpotlightDialog_button_explorePublicRooms";
break;
default:
selector = ".mx_SpotlightDialog_filter";
break;
}
return cy.get(selector, options).click();
});
Cypress.Commands.add(
"spotlightFilter",
(
filter: Filter | null,
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>> => {
let selector: string;
switch (filter) {
case Filter.People:
selector = "#mx_SpotlightDialog_button_startChat";
break;
case Filter.PublicRooms:
selector = "#mx_SpotlightDialog_button_explorePublicRooms";
break;
default:
selector = ".mx_SpotlightDialog_filter";
break;
}
return cy.get(selector, options).click();
},
);
Cypress.Commands.add("spotlightSearch", (
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>> => {
return cy.get(".mx_SpotlightDialog_searchBox input", options);
});
Cypress.Commands.add(
"spotlightSearch",
(options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>> => {
return cy.get(".mx_SpotlightDialog_searchBox input", options);
},
);
Cypress.Commands.add("spotlightResults", (
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>> => {
return cy.get(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option", options);
});
Cypress.Commands.add(
"spotlightResults",
(options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>> => {
return cy.get(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option", options);
},
);
Cypress.Commands.add("roomHeaderName", (
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
): Chainable<JQuery<HTMLElement>> => {
return cy.get(".mx_RoomHeader_nametext", options);
});
Cypress.Commands.add(
"roomHeaderName",
(options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>> => {
return cy.get(".mx_RoomHeader_nametext", options);
},
);
Cypress.Commands.add("startDM", (name: string) => {
cy.openSpotlightDialog().within(() => {
@ -121,9 +129,7 @@ Cypress.Commands.add("startDM", (name: string) => {
cy.spotlightResults().eq(0).click();
});
// send first message to start DM
cy.get(".mx_BasicMessageComposer_input")
.should("have.focus")
.type("Hey!{enter}");
cy.get(".mx_BasicMessageComposer_input").should("have.focus").type("Hey!{enter}");
// The DM room is created at this point, this can take a little bit of time
cy.contains(".mx_EventTile_body", "Hey!", { timeout: 30000 });
cy.contains(".mx_RoomSublist[aria-label=People]", name);
@ -148,46 +154,52 @@ describe("Spotlight", () => {
let room3Id: string;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Jim").then(() =>
cy.getBot(synapse, { displayName: bot1Name }).then(_bot1 => {
bot1 = _bot1;
}),
).then(() =>
cy.getBot(synapse, { displayName: bot2Name }).then(_bot2 => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
bot2 = _bot2;
}),
).then(() =>
cy.window({ log: false }).then(({ matrixcs: { Visibility } }) => {
cy.createRoom({ name: room1Name, visibility: Visibility.Public }).then(_room1Id => {
room1Id = _room1Id;
bot1.joinRoom(room1Id);
cy.visit("/#/room/" + room1Id);
});
bot2.createRoom({ name: room2Name, visibility: Visibility.Public })
.then(({ room_id: _room2Id }) => {
room2Id = _room2Id;
bot2.invite(room2Id, bot1.getUserId());
cy.initTestUser(synapse, "Jim")
.then(() =>
cy.getBot(synapse, { displayName: bot1Name }).then((_bot1) => {
bot1 = _bot1;
}),
)
.then(() =>
cy.getBot(synapse, { displayName: bot2Name }).then((_bot2) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
bot2 = _bot2;
}),
)
.then(() =>
cy.window({ log: false }).then(({ matrixcs: { Visibility } }) => {
cy.createRoom({ name: room1Name, visibility: Visibility.Public }).then((_room1Id) => {
room1Id = _room1Id;
bot1.joinRoom(room1Id);
cy.visit("/#/room/" + room1Id);
});
bot2.createRoom({
name: room3Name,
visibility: Visibility.Public, initial_state: [{
type: "m.room.history_visibility",
state_key: "",
content: {
history_visibility: "world_readable",
bot2.createRoom({ name: room2Name, visibility: Visibility.Public }).then(
({ room_id: _room2Id }) => {
room2Id = _room2Id;
bot2.invite(room2Id, bot1.getUserId());
},
}],
}).then(({ room_id: _room3Id }) => {
room3Id = _room3Id;
bot2.invite(room3Id, bot1.getUserId());
});
}),
).then(() =>
cy.get('.mx_RoomSublist_skeletonUI').should('not.exist'),
);
);
bot2.createRoom({
name: room3Name,
visibility: Visibility.Public,
initial_state: [
{
type: "m.room.history_visibility",
state_key: "",
content: {
history_visibility: "world_readable",
},
},
],
}).then(({ room_id: _room3Id }) => {
room3Id = _room3Id;
bot2.invite(room3Id, bot1.getUserId());
});
}),
)
.then(() => cy.get(".mx_RoomSublist_skeletonUI").should("not.exist"));
});
});
@ -216,63 +228,71 @@ describe("Spotlight", () => {
});
it("should find joined rooms", () => {
cy.openSpotlightDialog().within(() => {
cy.spotlightSearch().clear().type(room1Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room1Name);
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room1Id);
}).then(() => {
cy.roomHeaderName().should("contain", room1Name);
});
cy.openSpotlightDialog()
.within(() => {
cy.spotlightSearch().clear().type(room1Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room1Name);
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room1Id);
})
.then(() => {
cy.roomHeaderName().should("contain", room1Name);
});
});
it("should find known public rooms", () => {
cy.openSpotlightDialog().within(() => {
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room1Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room1Name);
cy.spotlightResults().eq(0).should("contain", "View");
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room1Id);
}).then(() => {
cy.roomHeaderName().should("contain", room1Name);
});
cy.openSpotlightDialog()
.within(() => {
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room1Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room1Name);
cy.spotlightResults().eq(0).should("contain", "View");
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room1Id);
})
.then(() => {
cy.roomHeaderName().should("contain", room1Name);
});
});
it("should find unknown public rooms", () => {
cy.openSpotlightDialog().within(() => {
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room2Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room2Name);
cy.spotlightResults().eq(0).should("contain", "Join");
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room2Id);
}).then(() => {
cy.get(".mx_RoomView_MessageList").should("have.length", 1);
cy.roomHeaderName().should("contain", room2Name);
});
cy.openSpotlightDialog()
.within(() => {
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room2Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room2Name);
cy.spotlightResults().eq(0).should("contain", "Join");
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room2Id);
})
.then(() => {
cy.get(".mx_RoomView_MessageList").should("have.length", 1);
cy.roomHeaderName().should("contain", room2Name);
});
});
it("should find unknown public world readable rooms", () => {
cy.openSpotlightDialog().within(() => {
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room3Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room3Name);
cy.spotlightResults().eq(0).should("contain", "View");
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room3Id);
}).then(() => {
cy.get(".mx_RoomPreviewBar_actions .mx_AccessibleButton").click();
cy.roomHeaderName().should("contain", room3Name);
});
cy.openSpotlightDialog()
.within(() => {
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room3Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room3Name);
cy.spotlightResults().eq(0).should("contain", "View");
cy.spotlightResults().eq(0).click();
cy.url().should("contain", room3Id);
})
.then(() => {
cy.get(".mx_RoomPreviewBar_actions .mx_AccessibleButton").click();
cy.roomHeaderName().should("contain", room3Name);
});
});
// TODO: We currently cant test finding rooms on other homeservers/other protocols
@ -299,29 +319,33 @@ describe("Spotlight", () => {
});
*/
it("should find known people", () => {
cy.openSpotlightDialog().within(() => {
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot1Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", bot1Name);
cy.spotlightResults().eq(0).click();
}).then(() => {
cy.roomHeaderName().should("contain", bot1Name);
});
cy.openSpotlightDialog()
.within(() => {
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot1Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", bot1Name);
cy.spotlightResults().eq(0).click();
})
.then(() => {
cy.roomHeaderName().should("contain", bot1Name);
});
});
it("should find unknown people", () => {
cy.openSpotlightDialog().within(() => {
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot2Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", bot2Name);
cy.spotlightResults().eq(0).click();
}).then(() => {
cy.roomHeaderName().should("contain", bot2Name);
});
cy.openSpotlightDialog()
.within(() => {
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot2Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", bot2Name);
cy.spotlightResults().eq(0).click();
})
.then(() => {
cy.roomHeaderName().should("contain", bot2Name);
});
});
it("should find group DMs by usernames or user ids", () => {
@ -340,10 +364,7 @@ describe("Spotlight", () => {
// Send first message to actually start DM
cy.roomHeaderName().should("contain", bot2Name);
cy.get(".mx_BasicMessageComposer_input")
.click()
.should("have.focus")
.type("Hey!{enter}");
cy.get(".mx_BasicMessageComposer_input").click().should("have.focus").type("Hey!{enter}");
// Assert DM exists by checking for the first message and the room being in the room list
cy.contains(".mx_EventTile_body", "Hey!", { timeout: 30000 });
@ -352,13 +373,13 @@ describe("Spotlight", () => {
// Invite BotBob into existing DM with ByteBot
cy.getDmRooms(bot2.getUserId())
.should("have.length", 1)
.then(dmRooms => cy.getClient().then(client => client.getRoom(dmRooms[0])))
.then(groupDm => {
.then((dmRooms) => cy.getClient().then((client) => client.getRoom(dmRooms[0])))
.then((groupDm) => {
cy.inviteUser(groupDm.roomId, bot1.getUserId());
cy.roomHeaderName().should(($element) =>
expect($element.get(0).innerText).contains(groupDm.name));
cy.roomHeaderName().should(($element) => expect($element.get(0).innerText).contains(groupDm.name));
cy.get(".mx_RoomSublist[aria-label=People]").should(($element) =>
expect($element.get(0).innerText).contains(groupDm.name));
expect($element.get(0).innerText).contains(groupDm.name),
);
// Search for BotBob by id, should return group DM and user
cy.openSpotlightDialog().within(() => {
@ -407,17 +428,19 @@ describe("Spotlight", () => {
});
it("should allow opening group chat dialog", () => {
cy.openSpotlightDialog().within(() => {
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot2Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", bot2Name);
cy.get(".mx_SpotlightDialog_startGroupChat").should("contain", "Start a group chat");
cy.get(".mx_SpotlightDialog_startGroupChat").click();
}).then(() => {
cy.get('[role=dialog]').should("contain", "Direct Messages");
});
cy.openSpotlightDialog()
.within(() => {
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot2Name);
cy.wait(3000); // wait for the dialog code to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", bot2Name);
cy.get(".mx_SpotlightDialog_startGroupChat").should("contain", "Start a group chat");
cy.get(".mx_SpotlightDialog_startGroupChat").click();
})
.then(() => {
cy.get("[role=dialog]").should("contain", "Direct Messages");
});
});
it("should close spotlight after starting a DM", () => {
@ -445,38 +468,40 @@ describe("Spotlight", () => {
// our debouncing logic only starts the search after a short timeout,
// so we wait a few milliseconds.
cy.wait(1000);
cy.get(".mx_Spinner").should("not.exist").then(() => {
cy.spotlightResults().should("have.length", 2).then(() => {
cy.spotlightResults().eq(0)
.should("have.attr", "aria-selected", "true");
cy.spotlightResults().eq(1)
.should("have.attr", "aria-selected", "false");
cy.get(".mx_Spinner")
.should("not.exist")
.then(() => {
cy.spotlightResults()
.should("have.length", 2)
.then(() => {
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "true");
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "false");
});
cy.spotlightSearch()
.type("{downArrow}")
.then(() => {
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "false");
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "true");
});
cy.spotlightSearch()
.type("{downArrow}")
.then(() => {
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "false");
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "false");
});
cy.spotlightSearch()
.type("{upArrow}")
.then(() => {
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "false");
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "true");
});
cy.spotlightSearch()
.type("{upArrow}")
.then(() => {
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "true");
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "false");
});
});
cy.spotlightSearch().type("{downArrow}").then(() => {
cy.spotlightResults().eq(0)
.should("have.attr", "aria-selected", "false");
cy.spotlightResults().eq(1)
.should("have.attr", "aria-selected", "true");
});
cy.spotlightSearch().type("{downArrow}").then(() => {
cy.spotlightResults().eq(0)
.should("have.attr", "aria-selected", "false");
cy.spotlightResults().eq(1)
.should("have.attr", "aria-selected", "false");
});
cy.spotlightSearch().type("{upArrow}").then(() => {
cy.spotlightResults().eq(0)
.should("have.attr", "aria-selected", "false");
cy.spotlightResults().eq(1)
.should("have.attr", "aria-selected", "true");
});
cy.spotlightSearch().type("{upArrow}").then(() => {
cy.spotlightResults().eq(0)
.should("have.attr", "aria-selected", "true");
cy.spotlightResults().eq(1)
.should("have.attr", "aria-selected", "false");
});
});
});
});
});

View file

@ -21,7 +21,7 @@ import { MatrixClient } from "../../global";
function markWindowBeforeReload(): void {
// mark our window object to "know" when it gets reloaded
cy.window().then(w => w.beforeReload = true);
cy.window().then((w) => (w.beforeReload = true));
}
describe("Threads", () => {
@ -30,10 +30,10 @@ describe("Threads", () => {
beforeEach(() => {
// Default threads to ON for this spec
cy.enableLabsFeature("feature_thread");
cy.window().then(win => {
cy.window().then((win) => {
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Tom");
@ -78,12 +78,12 @@ describe("Threads", () => {
cy.getBot(synapse, {
displayName: "BotBob",
autoAcceptInvites: false,
}).then(_bot => {
}).then((_bot) => {
bot = _bot;
});
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.inviteUser(roomId, bot.getUserId());
bot.joinRoom(roomId);
@ -95,10 +95,11 @@ describe("Threads", () => {
// Wait for message to send, get its ID and save as @threadId
cy.contains(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", "Hello Mr. Bot")
.invoke("attr", "data-scroll-tokens").as("threadId");
.invoke("attr", "data-scroll-tokens")
.as("threadId");
// Bot starts thread
cy.get<string>("@threadId").then(threadId => {
cy.get<string>("@threadId").then((threadId) => {
bot.sendMessage(roomId, threadId, {
body: "Hello there",
msgtype: "m.text",
@ -119,7 +120,8 @@ describe("Threads", () => {
// User reacts to message instead
cy.contains(".mx_ThreadView .mx_EventTile .mx_EventTile_line", "Hello there")
.find('[aria-label="React"]').click({ force: true }); // Cypress has no ability to hover
.find('[aria-label="React"]')
.click({ force: true }); // Cypress has no ability to hover
cy.get(".mx_EmojiPicker").within(() => {
cy.get('input[type="text"]').type("wave");
cy.contains('[role="menuitem"]', "👋").click();
@ -127,7 +129,8 @@ describe("Threads", () => {
// User redacts their prior response
cy.contains(".mx_ThreadView .mx_EventTile .mx_EventTile_line", "Test")
.find('[aria-label="Options"]').click({ force: true }); // Cypress has no ability to hover
.find('[aria-label="Options"]')
.click({ force: true }); // Cypress has no ability to hover
cy.get(".mx_IconizedContextMenu").within(() => {
cy.contains('[role="menuitem"]', "Remove").click();
});
@ -144,7 +147,7 @@ describe("Threads", () => {
cy.get(".mx_ThreadPanel .mx_BaseCard_close").click();
// Bot responds to thread
cy.get<string>("@threadId").then(threadId => {
cy.get<string>("@threadId").then((threadId) => {
bot.sendMessage(roomId, threadId, {
body: "How are things?",
msgtype: "m.text",
@ -178,45 +181,55 @@ describe("Threads", () => {
cy.get(".mx_BasicMessageComposer_input").type(" How about yourself?{enter}");
});
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_sender").should("contain", "Tom");
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content")
.should("contain", "Great! How about yourself?");
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content").should(
"contain",
"Great! How about yourself?",
);
// User closes right panel
cy.get(".mx_ThreadView .mx_BaseCard_close").click();
// Bot responds to thread and saves the id of their message to @eventId
cy.get<string>("@threadId").then(threadId => {
cy.wrap(bot.sendMessage(roomId, threadId, {
body: "I'm very good thanks",
msgtype: "m.text",
}).then(res => res.event_id)).as("eventId");
cy.get<string>("@threadId").then((threadId) => {
cy.wrap(
bot
.sendMessage(roomId, threadId, {
body: "I'm very good thanks",
msgtype: "m.text",
})
.then((res) => res.event_id),
).as("eventId");
});
// User asserts
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_sender").should("contain", "BotBob");
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content")
.should("contain", "I'm very good thanks");
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content").should(
"contain",
"I'm very good thanks",
);
// Bot edits their latest event
cy.get<string>("@eventId").then(eventId => {
cy.get<string>("@eventId").then((eventId) => {
bot.sendMessage(roomId, {
"body": "* I'm very good thanks :)",
"msgtype": "m.text",
"m.new_content": {
"body": "I'm very good thanks :)",
"msgtype": "m.text",
body: "I'm very good thanks :)",
msgtype: "m.text",
},
"m.relates_to": {
"rel_type": "m.replace",
"event_id": eventId,
rel_type: "m.replace",
event_id: eventId,
},
});
});
// User asserts
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_sender").should("contain", "BotBob");
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content")
.should("contain", "I'm very good thanks :)");
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content").should(
"contain",
"I'm very good thanks :)",
);
});
it("can send voice messages", () => {
@ -227,7 +240,7 @@ describe("Threads", () => {
});
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.visit("/#/room/" + roomId);
});
@ -237,7 +250,9 @@ describe("Threads", () => {
// Create thread
cy.contains(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", "Hello Mr. Bot")
.realHover().find(".mx_MessageActionBar_threadButton").click();
.realHover()
.find(".mx_MessageActionBar_threadButton")
.click();
cy.get(".mx_ThreadView_timelinePanelWrapper").should("have.length", 1);
cy.openMessageComposerOptions(true).find(`[aria-label="Voice Message"]`).click();
@ -250,7 +265,7 @@ describe("Threads", () => {
it("right panel behaves correctly", () => {
// Create room
let roomId: string;
cy.createRoom({}).then(_roomId => {
cy.createRoom({}).then((_roomId) => {
roomId = _roomId;
cy.visit("/#/room/" + roomId);
});
@ -259,7 +274,9 @@ describe("Threads", () => {
// Create thread
cy.contains(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", "Hello Mr. Bot")
.realHover().find(".mx_MessageActionBar_threadButton").click();
.realHover()
.find(".mx_MessageActionBar_threadButton")
.click();
cy.get(".mx_ThreadView_timelinePanelWrapper").should("have.length", 1);
// Send message to thread
@ -271,7 +288,9 @@ describe("Threads", () => {
// Open existing thread
cy.contains(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", "Hello Mr. Bot")
.realHover().find(".mx_MessageActionBar_threadButton").click();
.realHover()
.find(".mx_MessageActionBar_threadButton")
.click();
cy.get(".mx_ThreadView_timelinePanelWrapper").should("have.length", 1);
cy.get(".mx_BaseCard .mx_EventTile").should("contain", "Hello Mr. Bot");
cy.get(".mx_BaseCard .mx_EventTile").should("contain", "Hello Mr. User");

View file

@ -45,10 +45,7 @@ const expectDisplayName = (e: JQuery<HTMLElement>, displayName: string): void =>
};
const expectAvatar = (e: JQuery<HTMLElement>, avatarUrl: string): void => {
cy.all([
cy.window({ log: false }),
cy.getClient(),
]).then(([win, cli]) => {
cy.all([cy.window({ log: false }), cy.getClient()]).then(([win, cli]) => {
const size = AVATAR_SIZE * win.devicePixelRatio;
expect(e.find(".mx_BaseAvatar_image").attr("src")).to.equal(
// eslint-disable-next-line no-restricted-properties
@ -75,10 +72,10 @@ describe("Timeline", () => {
let newAvatarUrl: string;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, OLD_NAME).then(() =>
cy.createRoom({ name: ROOM_NAME }).then(_room1Id => {
cy.createRoom({ name: ROOM_NAME }).then((_room1Id) => {
roomId = _room1Id;
}),
);
@ -154,8 +151,11 @@ describe("Timeline", () => {
it("should create and configure a room on IRC layout", () => {
cy.visit("/#/room/" + roomId);
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.IRC);
cy.contains(".mx_RoomView_body .mx_GenericEventListSummary[data-layout=irc] " +
".mx_GenericEventListSummary_summary", "created and configured the room.").should("exist");
cy.contains(
".mx_RoomView_body .mx_GenericEventListSummary[data-layout=irc] " +
".mx_GenericEventListSummary_summary",
"created and configured the room.",
).should("exist");
cy.get(".mx_Spinner").should("not.exist");
cy.percySnapshot("Configured room on IRC layout");
});
@ -165,8 +165,10 @@ describe("Timeline", () => {
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.IRC);
// Wait until configuration is finished
cy.contains(".mx_RoomView_body .mx_GenericEventListSummary " +
".mx_GenericEventListSummary_summary", "created and configured the room.").should("exist");
cy.contains(
".mx_RoomView_body .mx_GenericEventListSummary " + ".mx_GenericEventListSummary_summary",
"created and configured the room.",
).should("exist");
// Click "expand" link button
cy.get(".mx_GenericEventListSummary_toggle[aria-expanded=false]").click();
@ -177,13 +179,13 @@ describe("Timeline", () => {
// = calc(var(--name-width) + 10px + var(--icon-width))
// = 80 + 10 + 14 = 104px
cy.get(".mx_EventTile[data-layout=irc].mx_EventTile_info:first-of-type .mx_EventTile_line")
.should('have.css', "margin-inline-start", "104px")
.should('have.css', "inset-inline-start", "0px");
.should("have.css", "margin-inline-start", "104px")
.should("have.css", "inset-inline-start", "0px");
cy.get(".mx_Spinner").should("not.exist");
// Exclude timestamp from snapshot
const percyCSS = ".mx_RoomView_body .mx_EventTile_info .mx_MessageTimestamp "
+ "{ visibility: hidden !important; }";
const percyCSS =
".mx_RoomView_body .mx_EventTile_info .mx_MessageTimestamp " + "{ visibility: hidden !important; }";
cy.percySnapshot("Event line with inline start margin on IRC layout", { percyCSS });
cy.checkA11y();
});
@ -192,8 +194,10 @@ describe("Timeline", () => {
sendEvent(roomId);
cy.visit("/#/room/" + roomId);
cy.setSettingValue("showHiddenEventsInTimeline", null, SettingLevel.DEVICE, true);
cy.contains(".mx_RoomView_body .mx_GenericEventListSummary .mx_GenericEventListSummary_summary",
"created and configured the room.").should("exist");
cy.contains(
".mx_RoomView_body .mx_GenericEventListSummary .mx_GenericEventListSummary_summary",
"created and configured the room.",
).should("exist");
// Edit message
cy.contains(".mx_RoomView_body .mx_EventTile .mx_EventTile_line", "Message").within(() => {
@ -206,20 +210,23 @@ describe("Timeline", () => {
cy.get(".mx_RoomView_body .mx_EventTile_info .mx_MessageTimestamp").click();
// Exclude timestamp from snapshot
const percyCSS = ".mx_RoomView_body .mx_EventTile .mx_MessageTimestamp "
+ "{ visibility: hidden !important; }";
const percyCSS =
".mx_RoomView_body .mx_EventTile .mx_MessageTimestamp " + "{ visibility: hidden !important; }";
// should not add inline start padding to a hidden event line on IRC layout
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.IRC);
cy.get(".mx_EventTile[data-layout=irc].mx_EventTile_info .mx_EventTile_line")
.should('have.css', 'padding-inline-start', '0px');
cy.get(".mx_EventTile[data-layout=irc].mx_EventTile_info .mx_EventTile_line").should(
"have.css",
"padding-inline-start",
"0px",
);
cy.percySnapshot("Hidden event line with zero padding on IRC layout", { percyCSS });
// should add inline start padding to a hidden event line on modern layout
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.Group);
cy.get(".mx_EventTile[data-layout=group].mx_EventTile_info .mx_EventTile_line")
// calc(var(--EventTile_group_line-spacing-inline-start) + 20px) = 64 + 20 = 84px
.should('have.css', 'padding-inline-start', '84px');
.should("have.css", "padding-inline-start", "84px");
cy.percySnapshot("Hidden event line with padding on modern layout", { percyCSS });
});
@ -227,8 +234,10 @@ describe("Timeline", () => {
sendEvent(roomId);
cy.visit("/#/room/" + roomId);
cy.setSettingValue("showHiddenEventsInTimeline", null, SettingLevel.DEVICE, true);
cy.contains(".mx_RoomView_body .mx_GenericEventListSummary " +
".mx_GenericEventListSummary_summary", "created and configured the room.").should("exist");
cy.contains(
".mx_RoomView_body .mx_GenericEventListSummary " + ".mx_GenericEventListSummary_summary",
"created and configured the room.",
).should("exist");
// Edit message
cy.contains(".mx_RoomView_body .mx_EventTile .mx_EventTile_line", "Message").within(() => {
@ -238,9 +247,12 @@ describe("Timeline", () => {
cy.contains(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", "MessageEdit").should("exist");
// Click top left of the event toggle, which should not be covered by MessageActionBar's safe area
cy.get(".mx_EventTile .mx_ViewSourceEvent").should("exist").realHover().within(() => {
cy.get(".mx_ViewSourceEvent_toggle").click('topLeft', { force: false });
});
cy.get(".mx_EventTile .mx_ViewSourceEvent")
.should("exist")
.realHover()
.within(() => {
cy.get(".mx_ViewSourceEvent_toggle").click("topLeft", { force: false });
});
// Make sure the expand toggle worked
cy.get(".mx_EventTile .mx_ViewSourceEvent_expanded .mx_ViewSourceEvent_toggle").should("be.visible");
@ -249,8 +261,11 @@ describe("Timeline", () => {
it("should click 'collapse' link button on the first hovered info event line on bubble layout", () => {
cy.visit("/#/room/" + roomId);
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.Bubble);
cy.contains(".mx_RoomView_body .mx_GenericEventListSummary[data-layout=bubble] " +
".mx_GenericEventListSummary_summary", "created and configured the room.").should("exist");
cy.contains(
".mx_RoomView_body .mx_GenericEventListSummary[data-layout=bubble] " +
".mx_GenericEventListSummary_summary",
"created and configured the room.",
).should("exist");
// Click "expand" link button
cy.get(".mx_GenericEventListSummary_toggle[aria-expanded=false]").click();
@ -340,10 +355,14 @@ describe("Timeline", () => {
cy.getComposer().type(`${reply}{enter}`);
cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line .mx_ReplyTile .mx_MTextBody")
.should("contain", MESSAGE);
cy.contains(".mx_RoomView_body .mx_EventTile > .mx_EventTile_line > .mx_MTextBody", reply)
.should("have.length", 1);
cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line .mx_ReplyTile .mx_MTextBody").should(
"contain",
MESSAGE,
);
cy.contains(".mx_RoomView_body .mx_EventTile > .mx_EventTile_line > .mx_MTextBody", reply).should(
"have.length",
1,
);
});
it("can reply with a voice message", () => {
@ -355,10 +374,14 @@ describe("Timeline", () => {
cy.wait(3000);
cy.get(".mx_RoomView_body .mx_MessageComposer .mx_MessageComposer_sendMessage").click();
cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line .mx_ReplyTile .mx_MTextBody")
.should("contain", MESSAGE);
cy.get(".mx_RoomView_body .mx_EventTile > .mx_EventTile_line > .mx_MVoiceMessageBody")
.should("have.length", 1);
cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line .mx_ReplyTile .mx_MTextBody").should(
"contain",
MESSAGE,
);
cy.get(".mx_RoomView_body .mx_EventTile > .mx_EventTile_line > .mx_MVoiceMessageBody").should(
"have.length",
1,
);
});
});
});

View file

@ -47,15 +47,15 @@ describe("Analytics Toast", () => {
});
it("should not show an analytics toast if config has nothing about posthog", () => {
cy.intercept("/config.json?cachebuster=*", req => {
req.continue(res => {
cy.intercept("/config.json?cachebuster=*", (req) => {
req.continue((res) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { posthog, ...body } = res.body;
res.send(200, body);
});
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Tod");
});
@ -66,8 +66,8 @@ describe("Analytics Toast", () => {
describe("with posthog enabled", () => {
beforeEach(() => {
cy.intercept("/config.json?cachebuster=*", req => {
req.continue(res => {
cy.intercept("/config.json?cachebuster=*", (req) => {
req.continue((res) => {
res.send(200, {
...res.body,
posthog: {
@ -78,7 +78,7 @@ describe("Analytics Toast", () => {
});
});
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Tod");
rejectToast("Notifications");

View file

@ -22,7 +22,7 @@ describe("Update", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
});
});
@ -45,9 +45,11 @@ describe("Update", () => {
cy.initTestUser(synapse, "Ursa");
cy.wait("@version");
cy.url().should("contain", "updated=" + NEW_VERSION).then(href => {
const url = new URL(href);
expect(url.searchParams.get("updated")).to.equal(NEW_VERSION);
});
cy.url()
.should("contain", "updated=" + NEW_VERSION)
.then((href) => {
const url = new URL(href);
expect(url.searchParams.get("updated")).to.equal(NEW_VERSION);
});
});
});

View file

@ -24,10 +24,10 @@ describe("User Menu", () => {
let user: UserCredentials;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Jeff").then(credentials => {
cy.initTestUser(synapse, "Jeff").then((credentials) => {
user = credentials;
});
});

View file

@ -26,23 +26,23 @@ describe("User Onboarding (new user)", () => {
let bot1: MatrixClient;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Jane Doe");
cy.window({ log: false }).then(win => {
cy.window({ log: false }).then((win) => {
win.localStorage.setItem("mx_registration_time", "1656633601");
});
cy.reload().then(() => {
// wait for the app to load
return cy.get(".mx_MatrixChat", { timeout: 15000 });
});
cy.getBot(synapse, { displayName: bot1Name }).then(_bot1 => {
cy.getBot(synapse, { displayName: bot1Name }).then((_bot1) => {
bot1 = _bot1;
});
cy.get('.mx_UserOnboardingPage').should('exist');
cy.get('.mx_UserOnboardingButton').should('exist');
cy.get('.mx_UserOnboardingList')
.should('exist')
cy.get(".mx_UserOnboardingPage").should("exist");
cy.get(".mx_UserOnboardingButton").should("exist");
cy.get(".mx_UserOnboardingList")
.should("exist")
.should(($list) => {
const list = $list.get(0);
expect(getComputedStyle(list).opacity).to.be.eq("1");
@ -55,44 +55,42 @@ describe("User Onboarding (new user)", () => {
});
it("page is shown and preference exists", () => {
cy.get('.mx_UserOnboardingPage')
.percySnapshotElement("User onboarding page");
cy.get(".mx_UserOnboardingPage").percySnapshotElement("User onboarding page");
cy.openUserSettings("Preferences");
cy.contains("Show shortcut to welcome checklist above the room list").should("exist");
});
it("app download dialog", () => {
cy.contains(".mx_UserOnboardingTask_action", "Download apps").click();
cy.get('[role=dialog]')
.contains("#mx_BaseDialog_title", "Download Element")
.should("exist");
cy.get('[role=dialog]')
.percySnapshotElement("App download dialog", {
widths: [640],
});
cy.get("[role=dialog]").contains("#mx_BaseDialog_title", "Download Element").should("exist");
cy.get("[role=dialog]").percySnapshotElement("App download dialog", {
widths: [640],
});
});
it("using find friends action should increase progress", () => {
cy.get(".mx_ProgressBar").invoke("val").then((oldProgress) => {
const findPeopleAction = cy.contains(".mx_UserOnboardingTask_action", "Find friends");
expect(findPeopleAction).to.exist;
findPeopleAction.click();
cy.get(".mx_InviteDialog_editor input").type(bot1.getUserId());
cy.get(".mx_InviteDialog_buttonAndSpinner").click();
cy.get(".mx_InviteDialog_buttonAndSpinner").should("not.exist");
const message = "Hi!";
cy.get(".mx_SendMessageComposer").type(`${message}!{enter}`);
cy.contains(".mx_MTextBody.mx_EventTile_content", message);
cy.visit("/#/home");
cy.get('.mx_UserOnboardingPage').should('exist');
cy.get('.mx_UserOnboardingButton').should('exist');
cy.get('.mx_UserOnboardingList')
.should('exist')
.should(($list) => {
const list = $list.get(0);
expect(getComputedStyle(list).opacity).to.be.eq("1");
});
cy.get(".mx_ProgressBar").invoke("val").should("be.greaterThan", oldProgress);
});
cy.get(".mx_ProgressBar")
.invoke("val")
.then((oldProgress) => {
const findPeopleAction = cy.contains(".mx_UserOnboardingTask_action", "Find friends");
expect(findPeopleAction).to.exist;
findPeopleAction.click();
cy.get(".mx_InviteDialog_editor input").type(bot1.getUserId());
cy.get(".mx_InviteDialog_buttonAndSpinner").click();
cy.get(".mx_InviteDialog_buttonAndSpinner").should("not.exist");
const message = "Hi!";
cy.get(".mx_SendMessageComposer").type(`${message}!{enter}`);
cy.contains(".mx_MTextBody.mx_EventTile_content", message);
cy.visit("/#/home");
cy.get(".mx_UserOnboardingPage").should("exist");
cy.get(".mx_UserOnboardingButton").should("exist");
cy.get(".mx_UserOnboardingList")
.should("exist")
.should(($list) => {
const list = $list.get(0);
expect(getComputedStyle(list).opacity).to.be.eq("1");
});
cy.get(".mx_ProgressBar").invoke("val").should("be.greaterThan", oldProgress);
});
});
});

View file

@ -22,10 +22,10 @@ describe("User Onboarding (old user)", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Jane Doe");
cy.window({ log: false }).then(win => {
cy.window({ log: false }).then((win) => {
win.localStorage.setItem("mx_registration_time", "2");
});
cy.reload().then(() => {
@ -41,8 +41,8 @@ describe("User Onboarding (old user)", () => {
});
it("page and preference are hidden", () => {
cy.get('.mx_UserOnboardingPage').should('not.exist');
cy.get('.mx_UserOnboardingButton').should('not.exist');
cy.get(".mx_UserOnboardingPage").should("not.exist");
cy.get(".mx_UserOnboardingButton").should("not.exist");
cy.openUserSettings("Preferences");
cy.contains("Show shortcut to welcome page above the room list").should("not.exist");
});

View file

@ -23,7 +23,7 @@ describe("UserView", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Violet");
@ -36,7 +36,7 @@ describe("UserView", () => {
});
it("should render the user view as expected", () => {
cy.get<MatrixClient>("@bot").then(bot => {
cy.get<MatrixClient>("@bot").then((bot) => {
cy.visit(`/#/user/${bot.getUserId()}`);
});

View file

@ -19,7 +19,7 @@ import { IWidget } from "matrix-widget-api";
import { SynapseInstance } from "../../plugins/synapsedocker";
const ROOM_NAME = 'Test Room';
const ROOM_NAME = "Test Room";
const WIDGET_ID = "fake-widget";
const WIDGET_HTML = `
<html lang="en">
@ -32,18 +32,18 @@ const WIDGET_HTML = `
</html>
`;
describe('Widget Layout', () => {
describe("Widget Layout", () => {
let widgetUrl: string;
let synapse: SynapseInstance;
let roomId: string;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Sally");
});
cy.serveHtmlFile(WIDGET_HTML).then(url => {
cy.serveHtmlFile(WIDGET_HTML).then((url) => {
widgetUrl = url;
});
@ -53,34 +53,38 @@ describe('Widget Layout', () => {
roomId = id;
// setup widget via state event
cy.getClient().then(async matrixClient => {
const content: IWidget = {
id: WIDGET_ID,
creatorUserId: 'somebody',
type: 'widget',
name: 'widget',
url: widgetUrl,
};
await matrixClient.sendStateEvent(roomId, 'im.vector.modular.widgets', content, WIDGET_ID);
}).as('widgetEventSent');
cy.getClient()
.then(async (matrixClient) => {
const content: IWidget = {
id: WIDGET_ID,
creatorUserId: "somebody",
type: "widget",
name: "widget",
url: widgetUrl,
};
await matrixClient.sendStateEvent(roomId, "im.vector.modular.widgets", content, WIDGET_ID);
})
.as("widgetEventSent");
// set initial layout
cy.getClient().then(async matrixClient => {
const content = {
widgets: {
[WIDGET_ID]: {
container: 'top', index: 1, width: 100, height: 0,
cy.getClient()
.then(async (matrixClient) => {
const content = {
widgets: {
[WIDGET_ID]: {
container: "top",
index: 1,
width: 100,
height: 0,
},
},
},
};
await matrixClient.sendStateEvent(roomId, 'io.element.widgets.layout', content, "");
}).as('layoutEventSent');
};
await matrixClient.sendStateEvent(roomId, "io.element.widgets.layout", content, "");
})
.as("layoutEventSent");
});
cy.all([
cy.get<string>("@widgetEventSent"),
cy.get<string>("@layoutEventSent"),
]).then(() => {
cy.all([cy.get<string>("@widgetEventSent"), cy.get<string>("@layoutEventSent")]).then(() => {
// open the room
cy.viewRoomByName(ROOM_NAME);
});
@ -91,31 +95,34 @@ describe('Widget Layout', () => {
cy.stopWebServers();
});
it('manually resize the height of the top container layout', () => {
cy.get('iframe[title="widget"]').invoke('height').should('be.lessThan', 250);
it("manually resize the height of the top container layout", () => {
cy.get('iframe[title="widget"]').invoke("height").should("be.lessThan", 250);
cy.get('.mx_AppsContainer_resizerHandle')
.trigger('mousedown')
.trigger('mousemove', { clientX: 0, clientY: 550, force: true })
.trigger('mouseup', { clientX: 0, clientY: 550, force: true });
cy.get(".mx_AppsContainer_resizerHandle")
.trigger("mousedown")
.trigger("mousemove", { clientX: 0, clientY: 550, force: true })
.trigger("mouseup", { clientX: 0, clientY: 550, force: true });
cy.get('iframe[title="widget"]').invoke('height').should('be.greaterThan', 400);
cy.get('iframe[title="widget"]').invoke("height").should("be.greaterThan", 400);
});
it('programatically resize the height of the top container layout', () => {
cy.get('iframe[title="widget"]').invoke('height').should('be.lessThan', 250);
it("programatically resize the height of the top container layout", () => {
cy.get('iframe[title="widget"]').invoke("height").should("be.lessThan", 250);
cy.getClient().then(async matrixClient => {
cy.getClient().then(async (matrixClient) => {
const content = {
widgets: {
[WIDGET_ID]: {
container: 'top', index: 1, width: 100, height: 100,
container: "top",
index: 1,
width: 100,
height: 100,
},
},
};
await matrixClient.sendStateEvent(roomId, 'io.element.widgets.layout', content, "");
await matrixClient.sendStateEvent(roomId, "io.element.widgets.layout", content, "");
});
cy.get('iframe[title="widget"]').invoke('height').should('be.greaterThan', 400);
cy.get('iframe[title="widget"]').invoke("height").should("be.greaterThan", 400);
});
});

View file

@ -67,8 +67,8 @@ const WIDGET_HTML = `
`;
function openStickerPicker() {
cy.get('.mx_MessageComposer_buttonMenu').click();
cy.get('#stickersButton').click();
cy.get(".mx_MessageComposer_buttonMenu").click();
cy.get("#stickersButton").click();
}
function sendStickerFromPicker() {
@ -76,18 +76,16 @@ function sendStickerFromPicker() {
// to use `chromeWebSecurity: false` in our cypress config. Not even cy.origin() can
// break into the iframe for us :(
cy.accessIframe(`iframe[title="${STICKER_PICKER_WIDGET_NAME}"]`).within({}, () => {
cy.get("#sendsticker").should('exist').click();
cy.get("#sendsticker").should("exist").click();
});
// Sticker picker should close itself after sending.
cy.get(".mx_AppTileFullWidth#stickers").should('not.exist');
cy.get(".mx_AppTileFullWidth#stickers").should("not.exist");
}
function expectTimelineSticker(roomId: string) {
// Make sure it's in the right room
cy.get('.mx_EventTile_sticker > a')
.should("have.attr", "href")
.and("include", `/${roomId}/`);
cy.get(".mx_EventTile_sticker > a").should("have.attr", "href").and("include", `/${roomId}/`);
// Make sure the image points at the sticker image
cy.get<HTMLImageElement>(`img[alt="${STICKER_NAME}"]`)
@ -107,12 +105,12 @@ describe("Stickers", () => {
let synapse: SynapseInstance;
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Sally");
});
cy.serveHtmlFile(WIDGET_HTML).then(url => {
cy.serveHtmlFile(WIDGET_HTML).then((url) => {
stickerPickerUrl = url;
});
});
@ -122,7 +120,7 @@ describe("Stickers", () => {
cy.stopWebServers();
});
it('should send a sticker to multiple rooms', () => {
it("should send a sticker to multiple rooms", () => {
cy.createRoom({
name: ROOM_NAME_1,
}).as("roomId1");

View file

@ -57,7 +57,7 @@ function waitForRoomWidget(win: Cypress.AUTWindow, widgetId: string, roomId: str
return new Promise((resolve, reject) => {
function eventsInIntendedState(evList) {
const widgetPresent = evList.some((ev) => {
return ev.getContent() && ev.getContent()['id'] === widgetId;
return ev.getContent() && ev.getContent()["id"] === widgetId;
});
if (add) {
return widgetPresent;
@ -68,7 +68,7 @@ function waitForRoomWidget(win: Cypress.AUTWindow, widgetId: string, roomId: str
const room = matrixClient.getRoom(roomId);
const startingWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
const startingWidgetEvents = room.currentState.getStateEvents("im.vector.modular.widgets");
if (eventsInIntendedState(startingWidgetEvents)) {
resolve();
return;
@ -77,7 +77,7 @@ function waitForRoomWidget(win: Cypress.AUTWindow, widgetId: string, roomId: str
function onRoomStateEvents(ev: MatrixEvent) {
if (ev.getRoomId() !== roomId || ev.getType() !== "im.vector.modular.widgets") return;
const currentWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
const currentWidgetEvents = room.currentState.getStateEvents("im.vector.modular.widgets");
if (eventsInIntendedState(currentWidgetEvents)) {
matrixClient.removeListener(win.matrixcs.RoomStateEvent.Events, onRoomStateEvents);
@ -95,35 +95,39 @@ describe("Widget PIP", () => {
let bot: MatrixClient;
let demoWidgetUrl: string;
function roomCreateAddWidgetPip(userRemove: 'leave' | 'kick' | 'ban') {
function roomCreateAddWidgetPip(userRemove: "leave" | "kick" | "ban") {
cy.createRoom({
name: ROOM_NAME,
invite: [bot.getUserId()],
}).then(roomId => {
}).then((roomId) => {
// sets bot to Admin and user to Moderator
cy.getClient().then(matrixClient => {
return matrixClient.sendStateEvent(roomId, 'm.room.power_levels', {
users: {
[user.userId]: 50,
[bot.getUserId()]: 100,
},
});
}).as('powerLevelsChanged');
cy.getClient()
.then((matrixClient) => {
return matrixClient.sendStateEvent(roomId, "m.room.power_levels", {
users: {
[user.userId]: 50,
[bot.getUserId()]: 100,
},
});
})
.as("powerLevelsChanged");
// bot joins the room
cy.botJoinRoom(bot, roomId).as('botJoined');
cy.botJoinRoom(bot, roomId).as("botJoined");
// setup widget via state event
cy.getClient().then(async matrixClient => {
const content: IWidget = {
id: DEMO_WIDGET_ID,
creatorUserId: 'somebody',
type: DEMO_WIDGET_TYPE,
name: DEMO_WIDGET_NAME,
url: demoWidgetUrl,
};
await matrixClient.sendStateEvent(roomId, 'im.vector.modular.widgets', content, DEMO_WIDGET_ID);
}).as('widgetEventSent');
cy.getClient()
.then(async (matrixClient) => {
const content: IWidget = {
id: DEMO_WIDGET_ID,
creatorUserId: "somebody",
type: DEMO_WIDGET_TYPE,
name: DEMO_WIDGET_NAME,
url: demoWidgetUrl,
};
await matrixClient.sendStateEvent(roomId, "im.vector.modular.widgets", content, DEMO_WIDGET_ID);
})
.as("widgetEventSent");
// open the room
cy.viewRoomByName(ROOM_NAME);
@ -133,7 +137,7 @@ describe("Widget PIP", () => {
cy.get<string>("@botJoined"),
cy.get<string>("@widgetEventSent"),
]).then(() => {
cy.window().then(async win => {
cy.window().then(async (win) => {
// wait for widget state event
await waitForRoomWidget(win, DEMO_WIDGET_ID, roomId, true);
@ -145,21 +149,23 @@ describe("Widget PIP", () => {
// checks that widget is opened in pip
cy.accessIframe(`iframe[title="${DEMO_WIDGET_NAME}"]`).within({}, () => {
cy.get("#demo").should('exist').then(async () => {
const userId = user.userId;
if (userRemove == 'leave') {
cy.getClient().then(async matrixClient => {
await matrixClient.leave(roomId);
});
} else if (userRemove == 'kick') {
await bot.kick(roomId, userId);
} else if (userRemove == 'ban') {
await bot.ban(roomId, userId);
}
cy.get("#demo")
.should("exist")
.then(async () => {
const userId = user.userId;
if (userRemove == "leave") {
cy.getClient().then(async (matrixClient) => {
await matrixClient.leave(roomId);
});
} else if (userRemove == "kick") {
await bot.kick(roomId, userId);
} else if (userRemove == "ban") {
await bot.ban(roomId, userId);
}
// checks that pip window is closed
cy.get(".mx_LegacyCallView_pip").should("not.exist");
});
// checks that pip window is closed
cy.get(".mx_LegacyCallView_pip").should("not.exist");
});
});
});
});
@ -167,17 +173,17 @@ describe("Widget PIP", () => {
}
beforeEach(() => {
cy.startSynapse("default").then(data => {
cy.startSynapse("default").then((data) => {
synapse = data;
cy.initTestUser(synapse, "Mike").then(_user => {
cy.initTestUser(synapse, "Mike").then((_user) => {
user = _user;
});
cy.getBot(synapse, { displayName: "Bot", autoAcceptInvites: false }).then(_bot => {
cy.getBot(synapse, { displayName: "Bot", autoAcceptInvites: false }).then((_bot) => {
bot = _bot;
});
});
cy.serveHtmlFile(DEMO_WIDGET_HTML).then(url => {
cy.serveHtmlFile(DEMO_WIDGET_HTML).then((url) => {
demoWidgetUrl = url;
});
});
@ -187,15 +193,15 @@ describe("Widget PIP", () => {
cy.stopWebServers();
});
it('should be closed on leave', () => {
roomCreateAddWidgetPip('leave');
it("should be closed on leave", () => {
roomCreateAddWidgetPip("leave");
});
it('should be closed on kick', () => {
roomCreateAddWidgetPip('kick');
it("should be closed on kick", () => {
roomCreateAddWidgetPip("kick");
});
it('should be closed on ban', () => {
roomCreateAddWidgetPip('ban');
it("should be closed on ban", () => {
roomCreateAddWidgetPip("ban");
});
});