Add dendrite support to cypress tests (#9884)
* Minimum hacks required to run cypress tests with dendrite * Remove wget hack since dendrite containers now have curl * Add basic dendritedocker plugin & hack into login spec for testing * Add generic HomeserverInstance interface * Add env var to configure which homeserver to use * Remove synapse specific homeserver support api * Update the rest of the tests to use HomeserverInstance * Update cypress docs to reference new homeserver abstraction * Fix formatting issues * Change dendrite to use main branch container
This commit is contained in:
parent
b642df98e9
commit
79033eb034
50 changed files with 947 additions and 362 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -24,6 +24,7 @@ package-lock.json
|
||||||
/cypress/downloads
|
/cypress/downloads
|
||||||
/cypress/screenshots
|
/cypress/screenshots
|
||||||
/cypress/synapselogs
|
/cypress/synapselogs
|
||||||
|
/cypress/dendritelogs
|
||||||
# These could have files in them but don't currently
|
# These could have files in them but don't currently
|
||||||
# Cypress will still auto-create them though...
|
# Cypress will still auto-create them though...
|
||||||
/cypress/performance
|
/cypress/performance
|
||||||
|
|
|
@ -33,6 +33,7 @@ export default defineConfig({
|
||||||
env: {
|
env: {
|
||||||
// Docker tag to use for `ghcr.io/matrix-org/sliding-sync-proxy` image.
|
// Docker tag to use for `ghcr.io/matrix-org/sliding-sync-proxy` image.
|
||||||
SLIDING_SYNC_PROXY_TAG: "v0.6.0",
|
SLIDING_SYNC_PROXY_TAG: "v0.6.0",
|
||||||
|
HOMESERVER: "synapse",
|
||||||
},
|
},
|
||||||
retries: {
|
retries: {
|
||||||
runMode: 4,
|
runMode: 4,
|
||||||
|
|
|
@ -16,25 +16,25 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
|
|
||||||
describe("Composer", () => {
|
describe("Composer", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("CIDER", () => {
|
describe("CIDER", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.initTestUser(synapse, "Janet").then(() => {
|
cy.initTestUser(homeserver, "Janet").then(() => {
|
||||||
cy.createRoom({ name: "Composing Room" });
|
cy.createRoom({ name: "Composing Room" });
|
||||||
});
|
});
|
||||||
cy.viewRoomByName("Composing Room");
|
cy.viewRoomByName("Composing Room");
|
||||||
|
@ -101,7 +101,7 @@ describe("Composer", () => {
|
||||||
describe("WYSIWYG", () => {
|
describe("WYSIWYG", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.enableLabsFeature("feature_wysiwyg_composer");
|
cy.enableLabsFeature("feature_wysiwyg_composer");
|
||||||
cy.initTestUser(synapse, "Janet").then(() => {
|
cy.initTestUser(homeserver, "Janet").then(() => {
|
||||||
cy.createRoom({ name: "Composing Room" });
|
cy.createRoom({ name: "Composing Room" });
|
||||||
});
|
});
|
||||||
cy.viewRoomByName("Composing Room");
|
cy.viewRoomByName("Composing Room");
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
function openCreateRoomDialog(): Chainable<JQuery<HTMLElement>> {
|
function openCreateRoomDialog(): Chainable<JQuery<HTMLElement>> {
|
||||||
|
@ -26,18 +26,18 @@ function openCreateRoomDialog(): Chainable<JQuery<HTMLElement>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Create Room", () => {
|
describe("Create Room", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Jim");
|
cy.initTestUser(homeserver, "Jim");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow us to create a public room with name, topic & address set", () => {
|
it("should allow us to create a public room with name, topic & address set", () => {
|
||||||
|
|
|
@ -18,12 +18,12 @@ import type { ISendEventResponse, MatrixClient, Room } from "matrix-js-sdk/src/m
|
||||||
import type { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
import type { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
import type { ISasEvent } from "matrix-js-sdk/src/crypto/verification/SAS";
|
import type { ISasEvent } from "matrix-js-sdk/src/crypto/verification/SAS";
|
||||||
import type { CypressBot } from "../../support/bot";
|
import type { CypressBot } from "../../support/bot";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
type EmojiMapping = [emoji: string, name: string];
|
type EmojiMapping = [emoji: string, name: string];
|
||||||
interface CryptoTestContext extends Mocha.Context {
|
interface CryptoTestContext extends Mocha.Context {
|
||||||
synapse: SynapseInstance;
|
homeserver: HomeserverInstance;
|
||||||
bob: CypressBot;
|
bob: CypressBot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,16 +155,16 @@ const verify = function (this: CryptoTestContext) {
|
||||||
|
|
||||||
describe("Cryptography", function () {
|
describe("Cryptography", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
cy.startSynapse("default")
|
cy.startHomeserver("default")
|
||||||
.as("synapse")
|
.as("homeserver")
|
||||||
.then((synapse: SynapseInstance) => {
|
.then((homeserver: HomeserverInstance) => {
|
||||||
cy.initTestUser(synapse, "Alice", undefined, "alice_");
|
cy.initTestUser(homeserver, "Alice", undefined, "alice_");
|
||||||
cy.getBot(synapse, { displayName: "Bob", autoAcceptInvites: false, userIdPrefix: "bob_" }).as("bob");
|
cy.getBot(homeserver, { displayName: "Bob", autoAcceptInvites: false, userIdPrefix: "bob_" }).as("bob");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function (this: CryptoTestContext) {
|
afterEach(function (this: CryptoTestContext) {
|
||||||
cy.stopSynapse(this.synapse);
|
cy.stopHomeserver(this.homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("setting up secure key backup should work", () => {
|
it("setting up secure key backup should work", () => {
|
||||||
|
@ -215,7 +215,7 @@ describe("Cryptography", function () {
|
||||||
cy.bootstrapCrossSigning();
|
cy.bootstrapCrossSigning();
|
||||||
|
|
||||||
// bob has a second, not cross-signed, device
|
// bob has a second, not cross-signed, device
|
||||||
cy.loginBot(this.synapse, this.bob.getUserId(), this.bob.__cypress_password, {}).as("bobSecondDevice");
|
cy.loginBot(this.homeserver, this.bob.getUserId(), this.bob.__cypress_password, {}).as("bobSecondDevice");
|
||||||
|
|
||||||
autoJoin(this.bob);
|
autoJoin(this.bob);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import type { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
import type { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
import type { ISasEvent } from "matrix-js-sdk/src/crypto/verification/SAS";
|
import type { ISasEvent } from "matrix-js-sdk/src/crypto/verification/SAS";
|
||||||
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { UserCredentials } from "../../support/login";
|
import { UserCredentials } from "../../support/login";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
|
@ -56,20 +56,20 @@ const handleVerificationRequest = (request: VerificationRequest): Chainable<Emoj
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("Decryption Failure Bar", () => {
|
describe("Decryption Failure Bar", () => {
|
||||||
let synapse: SynapseInstance | undefined;
|
let homeserver: HomeserverInstance | undefined;
|
||||||
let testUser: UserCredentials | undefined;
|
let testUser: UserCredentials | undefined;
|
||||||
let bot: MatrixClient | undefined;
|
let bot: MatrixClient | undefined;
|
||||||
let roomId: string;
|
let roomId: string;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
cy.startSynapse("default").then((syn: SynapseInstance) => {
|
cy.startHomeserver("default").then((hs: HomeserverInstance) => {
|
||||||
synapse = syn;
|
homeserver = hs;
|
||||||
cy.initTestUser(synapse, TEST_USER)
|
cy.initTestUser(homeserver, TEST_USER)
|
||||||
.then((creds: UserCredentials) => {
|
.then((creds: UserCredentials) => {
|
||||||
testUser = creds;
|
testUser = creds;
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
cy.getBot(synapse, { displayName: BOT_USER }).then((cli) => {
|
cy.getBot(homeserver, { displayName: BOT_USER }).then((cli) => {
|
||||||
bot = cli;
|
bot = cli;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -97,7 +97,7 @@ describe("Decryption Failure Bar", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(
|
it(
|
||||||
|
@ -105,7 +105,7 @@ describe("Decryption Failure Bar", () => {
|
||||||
"and there are other verified devices or backups",
|
"and there are other verified devices or backups",
|
||||||
() => {
|
() => {
|
||||||
let otherDevice: MatrixClient | undefined;
|
let otherDevice: MatrixClient | undefined;
|
||||||
cy.loginBot(synapse, testUser.username, testUser.password, {})
|
cy.loginBot(homeserver, testUser.username, testUser.password, {})
|
||||||
.then(async (cli) => {
|
.then(async (cli) => {
|
||||||
otherDevice = cli;
|
otherDevice = cli;
|
||||||
await otherDevice.bootstrapCrossSigning({
|
await otherDevice.bootstrapCrossSigning({
|
||||||
|
@ -169,7 +169,7 @@ describe("Decryption Failure Bar", () => {
|
||||||
"should prompt the user to reset keys, if this device isn't verified " +
|
"should prompt the user to reset keys, if this device isn't verified " +
|
||||||
"and there are no other verified devices or backups",
|
"and there are no other verified devices or backups",
|
||||||
() => {
|
() => {
|
||||||
cy.loginBot(synapse, testUser.username, testUser.password, {}).then(async (cli) => {
|
cy.loginBot(homeserver, testUser.username, testUser.password, {}).then(async (cli) => {
|
||||||
await cli.bootstrapCrossSigning({
|
await cli.bootstrapCrossSigning({
|
||||||
authUploadDeviceSigningKeys: async (makeRequest) => {
|
authUploadDeviceSigningKeys: async (makeRequest) => {
|
||||||
await makeRequest({});
|
await makeRequest({});
|
||||||
|
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
||||||
import type { MsgType } from "matrix-js-sdk/src/@types/event";
|
import type { MsgType } from "matrix-js-sdk/src/@types/event";
|
||||||
import type { ISendEventResponse } from "matrix-js-sdk/src/@types/requests";
|
import type { ISendEventResponse } from "matrix-js-sdk/src/@types/requests";
|
||||||
import type { EventType } from "matrix-js-sdk/src/@types/event";
|
import type { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
const sendEvent = (roomId: string): Chainable<ISendEventResponse> => {
|
const sendEvent = (roomId: string): Chainable<ISendEventResponse> => {
|
||||||
|
@ -30,12 +30,12 @@ const sendEvent = (roomId: string): Chainable<ISendEventResponse> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("Editing", () => {
|
describe("Editing", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, "Edith").then(() => {
|
cy.initTestUser(homeserver, "Edith").then(() => {
|
||||||
cy.injectAxe();
|
cy.injectAxe();
|
||||||
return cy.createRoom({ name: "Test room" }).as("roomId");
|
return cy.createRoom({ name: "Test room" }).as("roomId");
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,7 @@ describe("Editing", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should close the composer when clicking save after making a change and undoing it", () => {
|
it("should close the composer when clicking save after making a change and undoing it", () => {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { UserCredentials } from "../../support/login";
|
import { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
const ROOM_NAME = "Integration Manager Test";
|
const ROOM_NAME = "Integration Manager Test";
|
||||||
|
@ -73,17 +73,17 @@ function sendActionFromIntegrationManager(integrationManagerUrl: string) {
|
||||||
|
|
||||||
describe("Integration Manager: Get OpenID Token", () => {
|
describe("Integration Manager: Get OpenID Token", () => {
|
||||||
let testUser: UserCredentials;
|
let testUser: UserCredentials;
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let integrationManagerUrl: string;
|
let integrationManagerUrl: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
||||||
integrationManagerUrl = url;
|
integrationManagerUrl = url;
|
||||||
});
|
});
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
|
cy.initTestUser(homeserver, 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", INTEGRATION_MANAGER_TOKEN);
|
||||||
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
||||||
|
@ -122,7 +122,7 @@ describe("Integration Manager: Get OpenID Token", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
cy.stopWebServers();
|
cy.stopWebServers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
import { UserCredentials } from "../../support/login";
|
import { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
|
@ -94,17 +94,17 @@ function expectKickedMessage(shouldExist: boolean) {
|
||||||
|
|
||||||
describe("Integration Manager: Kick", () => {
|
describe("Integration Manager: Kick", () => {
|
||||||
let testUser: UserCredentials;
|
let testUser: UserCredentials;
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let integrationManagerUrl: string;
|
let integrationManagerUrl: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
||||||
integrationManagerUrl = url;
|
integrationManagerUrl = url;
|
||||||
});
|
});
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
|
cy.initTestUser(homeserver, 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", INTEGRATION_MANAGER_TOKEN);
|
||||||
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
||||||
|
@ -140,12 +140,12 @@ describe("Integration Manager: Kick", () => {
|
||||||
name: ROOM_NAME,
|
name: ROOM_NAME,
|
||||||
}).as("roomId");
|
}).as("roomId");
|
||||||
|
|
||||||
cy.getBot(synapse, { displayName: BOT_DISPLAY_NAME, autoAcceptInvites: true }).as("bob");
|
cy.getBot(homeserver, { displayName: BOT_DISPLAY_NAME, autoAcceptInvites: true }).as("bob");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
cy.stopWebServers();
|
cy.stopWebServers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { UserCredentials } from "../../support/login";
|
import { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
const ROOM_NAME = "Integration Manager Test";
|
const ROOM_NAME = "Integration Manager Test";
|
||||||
|
@ -87,17 +87,17 @@ function sendActionFromIntegrationManager(
|
||||||
|
|
||||||
describe("Integration Manager: Read Events", () => {
|
describe("Integration Manager: Read Events", () => {
|
||||||
let testUser: UserCredentials;
|
let testUser: UserCredentials;
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let integrationManagerUrl: string;
|
let integrationManagerUrl: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
||||||
integrationManagerUrl = url;
|
integrationManagerUrl = url;
|
||||||
});
|
});
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
|
cy.initTestUser(homeserver, 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", INTEGRATION_MANAGER_TOKEN);
|
||||||
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
||||||
|
@ -136,7 +136,7 @@ describe("Integration Manager: Read Events", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
cy.stopWebServers();
|
cy.stopWebServers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { UserCredentials } from "../../support/login";
|
import { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
const ROOM_NAME = "Integration Manager Test";
|
const ROOM_NAME = "Integration Manager Test";
|
||||||
|
@ -93,17 +93,17 @@ function sendActionFromIntegrationManager(
|
||||||
|
|
||||||
describe("Integration Manager: Send Event", () => {
|
describe("Integration Manager: Send Event", () => {
|
||||||
let testUser: UserCredentials;
|
let testUser: UserCredentials;
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let integrationManagerUrl: string;
|
let integrationManagerUrl: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
||||||
integrationManagerUrl = url;
|
integrationManagerUrl = url;
|
||||||
});
|
});
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
|
cy.initTestUser(homeserver, 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", INTEGRATION_MANAGER_TOKEN);
|
||||||
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
||||||
|
@ -142,7 +142,7 @@ describe("Integration Manager: Send Event", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
cy.stopWebServers();
|
cy.stopWebServers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ interface Charly {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Lazy Loading", () => {
|
describe("Lazy Loading", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let bob: MatrixClient;
|
let bob: MatrixClient;
|
||||||
const charlies: Charly[] = [];
|
const charlies: Charly[] = [];
|
||||||
|
|
||||||
|
@ -35,12 +35,12 @@ describe("Lazy Loading", () => {
|
||||||
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Alice");
|
cy.initTestUser(homeserver, "Alice");
|
||||||
|
|
||||||
cy.getBot(synapse, {
|
cy.getBot(homeserver, {
|
||||||
displayName: "Bob",
|
displayName: "Bob",
|
||||||
startClient: false,
|
startClient: false,
|
||||||
autoAcceptInvites: false,
|
autoAcceptInvites: false,
|
||||||
|
@ -50,7 +50,7 @@ describe("Lazy Loading", () => {
|
||||||
|
|
||||||
for (let i = 1; i <= 10; i++) {
|
for (let i = 1; i <= 10; i++) {
|
||||||
const displayName = `Charly #${i}`;
|
const displayName = `Charly #${i}`;
|
||||||
cy.getBot(synapse, {
|
cy.getBot(homeserver, {
|
||||||
displayName,
|
displayName,
|
||||||
startClient: false,
|
startClient: false,
|
||||||
autoAcceptInvites: false,
|
autoAcceptInvites: false,
|
||||||
|
@ -62,7 +62,7 @@ describe("Lazy Loading", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
const name = "Lazy Loading Test";
|
const name = "Lazy Loading Test";
|
||||||
|
|
|
@ -16,11 +16,11 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
describe("Location sharing", () => {
|
describe("Location sharing", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
const selectLocationShareTypeOption = (shareType: string): Chainable<JQuery> => {
|
const selectLocationShareTypeOption = (shareType: string): Chainable<JQuery> => {
|
||||||
return cy.get(`[data-test-id="share-location-option-${shareType}"]`);
|
return cy.get(`[data-test-id="share-location-option-${shareType}"]`);
|
||||||
|
@ -34,15 +34,15 @@ describe("Location sharing", () => {
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
||||||
});
|
});
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Tom");
|
cy.initTestUser(homeserver, "Tom");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sends and displays pin drop location message successfully", () => {
|
it("sends and displays pin drop location message successfully", () => {
|
||||||
|
|
|
@ -18,21 +18,21 @@ limitations under the License.
|
||||||
|
|
||||||
import { SinonStub } from "cypress/types/sinon";
|
import { SinonStub } from "cypress/types/sinon";
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
describe("Consent", () => {
|
describe("Consent", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("consent").then((data) => {
|
cy.startHomeserver("consent").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Bob");
|
cy.initTestUser(homeserver, "Bob");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should prompt the user to consent to terms when server deems it necessary", () => {
|
it("should prompt the user to consent to terms when server deems it necessary", () => {
|
||||||
|
@ -53,8 +53,8 @@ describe("Consent", () => {
|
||||||
cy.get<SinonStub>("@windowOpen").then((stub) => {
|
cy.get<SinonStub>("@windowOpen").then((stub) => {
|
||||||
const url = stub.getCall(0).args[0];
|
const url = stub.getCall(0).args[0];
|
||||||
|
|
||||||
// Go to Synapse's consent page and accept it
|
// Go to Homeserver's consent page and accept it
|
||||||
cy.origin(synapse.baseUrl, { args: { url } }, ({ url }) => {
|
cy.origin(homeserver.baseUrl, { args: { url } }, ({ url }) => {
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
|
|
||||||
cy.get('[type="submit"]').click();
|
cy.get('[type="submit"]').click();
|
||||||
|
|
|
@ -16,17 +16,17 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
describe("Login", () => {
|
describe("Login", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubDefaultServer();
|
cy.stubDefaultServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("m.login.password", () => {
|
describe("m.login.password", () => {
|
||||||
|
@ -34,9 +34,9 @@ describe("Login", () => {
|
||||||
const password = "p4s5W0rD";
|
const password = "p4s5W0rD";
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("consent").then((data) => {
|
cy.startHomeserver("consent").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.registerUser(synapse, username, password);
|
cy.registerUser(homeserver, username, password);
|
||||||
cy.visit("/#/login");
|
cy.visit("/#/login");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,7 @@ describe("Login", () => {
|
||||||
cy.checkA11y();
|
cy.checkA11y();
|
||||||
|
|
||||||
cy.get(".mx_ServerPicker_change").click();
|
cy.get(".mx_ServerPicker_change").click();
|
||||||
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
|
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(homeserver.baseUrl);
|
||||||
cy.get(".mx_ServerPickerDialog_continue").click();
|
cy.get(".mx_ServerPickerDialog_continue").click();
|
||||||
// wait for the dialog to go away
|
// wait for the dialog to go away
|
||||||
cy.get(".mx_ServerPickerDialog").should("not.exist");
|
cy.get(".mx_ServerPickerDialog").should("not.exist");
|
||||||
|
@ -64,9 +64,9 @@ describe("Login", () => {
|
||||||
|
|
||||||
describe("logout", () => {
|
describe("logout", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("consent").then((data) => {
|
cy.startHomeserver("consent").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, "Erin");
|
cy.initTestUser(homeserver, "Erin");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,14 @@ limitations under the License.
|
||||||
|
|
||||||
import { PollResponseEvent } from "matrix-events-sdk";
|
import { PollResponseEvent } from "matrix-events-sdk";
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
const hideTimestampCSS = ".mx_MessageTimestamp { visibility: hidden !important; }";
|
const hideTimestampCSS = ".mx_MessageTimestamp { visibility: hidden !important; }";
|
||||||
|
|
||||||
describe("Polls", () => {
|
describe("Polls", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
type CreatePollOptions = {
|
type CreatePollOptions = {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -81,20 +81,20 @@ describe("Polls", () => {
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
||||||
});
|
});
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Tom");
|
cy.initTestUser(homeserver, "Tom");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be creatable and votable", () => {
|
it("should be creatable and votable", () => {
|
||||||
let bot: MatrixClient;
|
let bot: MatrixClient;
|
||||||
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
|
cy.getBot(homeserver, { displayName: "BotBob" }).then((_bot) => {
|
||||||
bot = _bot;
|
bot = _bot;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ describe("Polls", () => {
|
||||||
|
|
||||||
it("should be editable from context menu if no votes have been cast", () => {
|
it("should be editable from context menu if no votes have been cast", () => {
|
||||||
let bot: MatrixClient;
|
let bot: MatrixClient;
|
||||||
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
|
cy.getBot(homeserver, { displayName: "BotBob" }).then((_bot) => {
|
||||||
bot = _bot;
|
bot = _bot;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ describe("Polls", () => {
|
||||||
|
|
||||||
it("should not be editable from context menu if votes have been cast", () => {
|
it("should not be editable from context menu if votes have been cast", () => {
|
||||||
let bot: MatrixClient;
|
let bot: MatrixClient;
|
||||||
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
|
cy.getBot(homeserver, { displayName: "BotBob" }).then((_bot) => {
|
||||||
bot = _bot;
|
bot = _bot;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -256,10 +256,10 @@ describe("Polls", () => {
|
||||||
it("should be displayed correctly in thread panel", () => {
|
it("should be displayed correctly in thread panel", () => {
|
||||||
let botBob: MatrixClient;
|
let botBob: MatrixClient;
|
||||||
let botCharlie: MatrixClient;
|
let botCharlie: MatrixClient;
|
||||||
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
|
cy.getBot(homeserver, { displayName: "BotBob" }).then((_bot) => {
|
||||||
botBob = _bot;
|
botBob = _bot;
|
||||||
});
|
});
|
||||||
cy.getBot(synapse, { displayName: "BotCharlie" }).then((_bot) => {
|
cy.getBot(homeserver, { displayName: "BotCharlie" }).then((_bot) => {
|
||||||
botCharlie = _bot;
|
botCharlie = _bot;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,21 +16,21 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
describe("Registration", () => {
|
describe("Registration", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubDefaultServer();
|
cy.stubDefaultServer();
|
||||||
cy.visit("/#/register");
|
cy.visit("/#/register");
|
||||||
cy.startSynapse("consent").then((data) => {
|
cy.startHomeserver("consent").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("registers an account and lands on the home screen", () => {
|
it("registers an account and lands on the home screen", () => {
|
||||||
|
@ -42,13 +42,13 @@ describe("Registration", () => {
|
||||||
cy.get(".mx_Dialog").percySnapshotElement("Server Picker", { widths: [516] });
|
cy.get(".mx_Dialog").percySnapshotElement("Server Picker", { widths: [516] });
|
||||||
cy.checkA11y();
|
cy.checkA11y();
|
||||||
|
|
||||||
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
|
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(homeserver.baseUrl);
|
||||||
cy.get(".mx_ServerPickerDialog_continue").click();
|
cy.get(".mx_ServerPickerDialog_continue").click();
|
||||||
// wait for the dialog to go away
|
// 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");
|
cy.get("#mx_RegistrationForm_username").should("be.visible");
|
||||||
// Hide the server text as it contains the randomly allocated Synapse port
|
// Hide the server text as it contains the randomly allocated Homeserver port
|
||||||
const percyCSS = ".mx_ServerPicker_server { visibility: hidden !important; }";
|
const percyCSS = ".mx_ServerPicker_server { visibility: hidden !important; }";
|
||||||
cy.percySnapshot("Registration", { percyCSS });
|
cy.percySnapshot("Registration", { percyCSS });
|
||||||
cy.checkA11y();
|
cy.checkA11y();
|
||||||
|
@ -88,7 +88,7 @@ describe("Registration", () => {
|
||||||
it("should require username to fulfil requirements and be available", () => {
|
it("should require username to fulfil requirements and be available", () => {
|
||||||
cy.get(".mx_ServerPicker_change", { timeout: 15000 }).click();
|
cy.get(".mx_ServerPicker_change", { timeout: 15000 }).click();
|
||||||
cy.get(".mx_ServerPickerDialog_continue").should("be.visible");
|
cy.get(".mx_ServerPickerDialog_continue").should("be.visible");
|
||||||
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
|
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(homeserver.baseUrl);
|
||||||
cy.get(".mx_ServerPickerDialog_continue").click();
|
cy.get(".mx_ServerPickerDialog_continue").click();
|
||||||
// wait for the dialog to go away
|
// wait for the dialog to go away
|
||||||
cy.get(".mx_ServerPickerDialog").should("not.exist");
|
cy.get(".mx_ServerPickerDialog").should("not.exist");
|
||||||
|
|
|
@ -16,21 +16,21 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
describe("Pills", () => {
|
describe("Pills", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Sally");
|
cy.initTestUser(homeserver, "Sally");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should navigate clicks internally to the app", () => {
|
it("should navigate clicks internally to the app", () => {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
const ROOM_NAME = "Test room";
|
const ROOM_NAME = "Test room";
|
||||||
|
@ -43,12 +43,12 @@ const checkRoomSummaryCard = (name: string): Chainable<JQuery<HTMLElement>> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("RightPanel", () => {
|
describe("RightPanel", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, NAME).then(() =>
|
cy.initTestUser(homeserver, NAME).then(() =>
|
||||||
cy.window({ log: false }).then(() => {
|
cy.window({ log: false }).then(() => {
|
||||||
cy.createRoom({ name: ROOM_NAME });
|
cy.createRoom({ name: ROOM_NAME });
|
||||||
cy.createSpace({ name: SPACE_NAME });
|
cy.createSpace({ name: SPACE_NAME });
|
||||||
|
@ -58,7 +58,7 @@ describe("RightPanel", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("in rooms", () => {
|
describe("in rooms", () => {
|
||||||
|
|
|
@ -16,23 +16,23 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
|
|
||||||
describe("Room Directory", () => {
|
describe("Room Directory", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Ray");
|
cy.initTestUser(homeserver, "Ray");
|
||||||
cy.getBot(synapse, { displayName: "Paul" }).as("bot");
|
cy.getBot(homeserver, { displayName: "Paul" }).as("bot");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow admin to add alias & publish room to directory", () => {
|
it("should allow admin to add alias & publish room to directory", () => {
|
||||||
|
|
|
@ -18,34 +18,34 @@ limitations under the License.
|
||||||
|
|
||||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
|
|
||||||
describe("Room Directory", () => {
|
describe("Room Directory", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Alice");
|
cy.initTestUser(homeserver, "Alice");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should switch between existing dm rooms without a loader", () => {
|
it("should switch between existing dm rooms without a loader", () => {
|
||||||
let bobClient: MatrixClient;
|
let bobClient: MatrixClient;
|
||||||
let charlieClient: MatrixClient;
|
let charlieClient: MatrixClient;
|
||||||
cy.getBot(synapse, {
|
cy.getBot(homeserver, {
|
||||||
displayName: "Bob",
|
displayName: "Bob",
|
||||||
}).then((bob) => {
|
}).then((bob) => {
|
||||||
bobClient = bob;
|
bobClient = bob;
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.getBot(synapse, {
|
cy.getBot(homeserver, {
|
||||||
displayName: "Charlie",
|
displayName: "Charlie",
|
||||||
}).then((charlie) => {
|
}).then((charlie) => {
|
||||||
charlieClient = charlie;
|
charlieClient = charlie;
|
||||||
|
|
|
@ -16,34 +16,34 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import type { UserCredentials } from "../../support/login";
|
import type { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
describe("Device manager", () => {
|
describe("Device manager", () => {
|
||||||
let synapse: SynapseInstance | undefined;
|
let homeserver: HomeserverInstance | undefined;
|
||||||
let user: UserCredentials | undefined;
|
let user: UserCredentials | undefined;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.enableLabsFeature("feature_new_device_manager");
|
cy.enableLabsFeature("feature_new_device_manager");
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Alice")
|
cy.initTestUser(homeserver, "Alice")
|
||||||
.then((credentials) => {
|
.then((credentials) => {
|
||||||
user = credentials;
|
user = credentials;
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// create some extra sessions to manage
|
// create some extra sessions to manage
|
||||||
return cy.loginUser(synapse, user.username, user.password);
|
return cy.loginUser(homeserver, user.username, user.password);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return cy.loginUser(synapse, user.username, user.password);
|
return cy.loginUser(homeserver, user.username, user.password);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse!);
|
cy.stopHomeserver(homeserver!);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should display sessions", () => {
|
it("should display sessions", () => {
|
||||||
|
|
|
@ -16,10 +16,10 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
function seedLabs(synapse: SynapseInstance, labsVal: boolean | null): void {
|
function seedLabs(homeserver: HomeserverInstance, labsVal: boolean | null): void {
|
||||||
cy.initTestUser(synapse, "Sally", () => {
|
cy.initTestUser(homeserver, "Sally", () => {
|
||||||
// seed labs flag
|
// seed labs flag
|
||||||
cy.window({ log: false }).then((win) => {
|
cy.window({ log: false }).then((win) => {
|
||||||
if (typeof labsVal === "boolean") {
|
if (typeof labsVal === "boolean") {
|
||||||
|
@ -61,30 +61,30 @@ describe("Hidden Read Receipts Setting Migration", () => {
|
||||||
// For a security-sensitive feature like hidden read receipts, it's absolutely vital
|
// For a security-sensitive feature like hidden read receipts, it's absolutely vital
|
||||||
// that we migrate the setting appropriately.
|
// that we migrate the setting appropriately.
|
||||||
|
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not migrate the lack of a labs flag", () => {
|
it("should not migrate the lack of a labs flag", () => {
|
||||||
seedLabs(synapse, null);
|
seedLabs(homeserver, null);
|
||||||
testForVal(null);
|
testForVal(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should migrate labsHiddenRR=false as sendRR=true", () => {
|
it("should migrate labsHiddenRR=false as sendRR=true", () => {
|
||||||
seedLabs(synapse, false);
|
seedLabs(homeserver, false);
|
||||||
testForVal(true);
|
testForVal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should migrate labsHiddenRR=true as sendRR=false", () => {
|
it("should migrate labsHiddenRR=true as sendRR=false", () => {
|
||||||
seedLabs(synapse, true);
|
seedLabs(homeserver, true);
|
||||||
testForVal(false);
|
testForVal(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,43 +20,45 @@ import _ from "lodash";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
import { Interception } from "cypress/types/net-stubbing";
|
import { Interception } from "cypress/types/net-stubbing";
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
import { Layout } from "../../../src/settings/enums/Layout";
|
import { Layout } from "../../../src/settings/enums/Layout";
|
||||||
import { ProxyInstance } from "../../plugins/sliding-sync";
|
import { ProxyInstance } from "../../plugins/sliding-sync";
|
||||||
|
|
||||||
describe("Sliding Sync", () => {
|
describe("Sliding Sync", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default")
|
cy.startHomeserver("default")
|
||||||
.as("synapse")
|
.as("homeserver")
|
||||||
.then((synapse) => {
|
.then((homeserver) => {
|
||||||
cy.startProxy(synapse).as("proxy");
|
cy.startProxy(homeserver).as("proxy");
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.all([cy.get<SynapseInstance>("@synapse"), cy.get<ProxyInstance>("@proxy")]).then(([synapse, proxy]) => {
|
cy.all([cy.get<HomeserverInstance>("@homeserver"), cy.get<ProxyInstance>("@proxy")]).then(
|
||||||
cy.enableLabsFeature("feature_sliding_sync");
|
([homeserver, proxy]) => {
|
||||||
|
cy.enableLabsFeature("feature_sliding_sync");
|
||||||
|
|
||||||
cy.intercept("/config.json?cachebuster=*", (req) => {
|
cy.intercept("/config.json?cachebuster=*", (req) => {
|
||||||
return req.continue((res) => {
|
return req.continue((res) => {
|
||||||
res.send(200, {
|
res.send(200, {
|
||||||
...res.body,
|
...res.body,
|
||||||
setting_defaults: {
|
setting_defaults: {
|
||||||
feature_sliding_sync_proxy_url: `http://localhost:${proxy.port}`,
|
feature_sliding_sync_proxy_url: `http://localhost:${proxy.port}`,
|
||||||
},
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Sloth").then(() => {
|
cy.initTestUser(homeserver, "Sloth").then(() => {
|
||||||
return cy.window({ log: false }).then(() => {
|
return cy.window({ log: false }).then(() => {
|
||||||
cy.createRoom({ name: "Test Room" }).as("roomId");
|
cy.createRoom({ name: "Test Room" }).as("roomId");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.get<SynapseInstance>("@synapse").then(cy.stopSynapse);
|
cy.get<HomeserverInstance>("@homeserver").then(cy.stopHomeserver);
|
||||||
cy.get<ProxyInstance>("@proxy").then(cy.stopProxy);
|
cy.get<ProxyInstance>("@proxy").then(cy.stopProxy);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -84,9 +86,9 @@ describe("Sliding Sync", () => {
|
||||||
};
|
};
|
||||||
const createAndJoinBob = () => {
|
const createAndJoinBob = () => {
|
||||||
// create a Bob user
|
// create a Bob user
|
||||||
cy.get<SynapseInstance>("@synapse").then((synapse) => {
|
cy.get<HomeserverInstance>("@homeserver").then((homeserver) => {
|
||||||
return cy
|
return cy
|
||||||
.getBot(synapse, {
|
.getBot(homeserver, {
|
||||||
displayName: "Bob",
|
displayName: "Bob",
|
||||||
})
|
})
|
||||||
.as("bob");
|
.as("bob");
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import type { MatrixClient } from "matrix-js-sdk/src/client";
|
import type { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import type { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests";
|
import type { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
import { UserCredentials } from "../../support/login";
|
import { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
|
@ -59,14 +59,14 @@ function spaceChildInitialState(roomId: string): ICreateRoomOpts["initial_state"
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Spaces", () => {
|
describe("Spaces", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let user: UserCredentials;
|
let user: UserCredentials;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Sue").then((_user) => {
|
cy.initTestUser(homeserver, "Sue").then((_user) => {
|
||||||
user = _user;
|
user = _user;
|
||||||
cy.mockClipboard();
|
cy.mockClipboard();
|
||||||
});
|
});
|
||||||
|
@ -74,7 +74,7 @@ describe("Spaces", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only("should allow user to create public space", () => {
|
it.only("should allow user to create public space", () => {
|
||||||
|
@ -173,7 +173,7 @@ describe("Spaces", () => {
|
||||||
|
|
||||||
it("should allow user to invite another to a space", () => {
|
it("should allow user to invite another to a space", () => {
|
||||||
let bot: MatrixClient;
|
let bot: MatrixClient;
|
||||||
cy.getBot(synapse, { displayName: "BotBob" }).then((_bot) => {
|
cy.getBot(homeserver, { displayName: "BotBob" }).then((_bot) => {
|
||||||
bot = _bot;
|
bot = _bot;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ describe("Spaces", () => {
|
||||||
});
|
});
|
||||||
cy.getSpacePanelButton("My Space").should("exist");
|
cy.getSpacePanelButton("My Space").should("exist");
|
||||||
|
|
||||||
cy.getBot(synapse, { displayName: "BotBob" }).then({ timeout: 10000 }, async (bot) => {
|
cy.getBot(homeserver, { displayName: "BotBob" }).then({ timeout: 10000 }, async (bot) => {
|
||||||
const { room_id: roomId } = await bot.createRoom(spaceCreateOptions("Space Space"));
|
const { room_id: roomId } = await bot.createRoom(spaceCreateOptions("Space Space"));
|
||||||
await bot.invite(roomId, user.userId);
|
await bot.invite(roomId, user.userId);
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
import Loggable = Cypress.Loggable;
|
import Loggable = Cypress.Loggable;
|
||||||
import Timeoutable = Cypress.Timeoutable;
|
import Timeoutable = Cypress.Timeoutable;
|
||||||
|
@ -136,7 +136,7 @@ Cypress.Commands.add("startDM", (name: string) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Spotlight", () => {
|
describe("Spotlight", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
const bot1Name = "BotBob";
|
const bot1Name = "BotBob";
|
||||||
let bot1: MatrixClient;
|
let bot1: MatrixClient;
|
||||||
|
@ -154,16 +154,16 @@ describe("Spotlight", () => {
|
||||||
let room3Id: string;
|
let room3Id: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, "Jim")
|
cy.initTestUser(homeserver, "Jim")
|
||||||
.then(() =>
|
.then(() =>
|
||||||
cy.getBot(synapse, { displayName: bot1Name }).then((_bot1) => {
|
cy.getBot(homeserver, { displayName: bot1Name }).then((_bot1) => {
|
||||||
bot1 = _bot1;
|
bot1 = _bot1;
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
cy.getBot(synapse, { displayName: bot2Name }).then((_bot2) => {
|
cy.getBot(homeserver, { displayName: bot2Name }).then((_bot2) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
bot2 = _bot2;
|
bot2 = _bot2;
|
||||||
}),
|
}),
|
||||||
|
@ -205,7 +205,7 @@ describe("Spotlight", () => {
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.visit("/#/home");
|
cy.visit("/#/home");
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to add and remove filters via keyboard", () => {
|
it("should be able to add and remove filters via keyboard", () => {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
|
|
||||||
function markWindowBeforeReload(): void {
|
function markWindowBeforeReload(): void {
|
||||||
|
@ -25,7 +25,7 @@ function markWindowBeforeReload(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Threads", () => {
|
describe("Threads", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Default threads to ON for this spec
|
// Default threads to ON for this spec
|
||||||
|
@ -33,15 +33,15 @@ describe("Threads", () => {
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
win.localStorage.setItem("mx_lhs_size", "0"); // Collapse left panel for these tests
|
||||||
});
|
});
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Tom");
|
cy.initTestUser(homeserver, "Tom");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should reload when enabling threads beta", () => {
|
it("should reload when enabling threads beta", () => {
|
||||||
|
@ -75,7 +75,7 @@ describe("Threads", () => {
|
||||||
|
|
||||||
it("should be usable for a conversation", () => {
|
it("should be usable for a conversation", () => {
|
||||||
let bot: MatrixClient;
|
let bot: MatrixClient;
|
||||||
cy.getBot(synapse, {
|
cy.getBot(homeserver, {
|
||||||
displayName: "BotBob",
|
displayName: "BotBob",
|
||||||
autoAcceptInvites: false,
|
autoAcceptInvites: false,
|
||||||
}).then((_bot) => {
|
}).then((_bot) => {
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import type { ISendEventResponse } from "matrix-js-sdk/src/@types/requests";
|
import type { ISendEventResponse } from "matrix-js-sdk/src/@types/requests";
|
||||||
import type { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
|
import type { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
import { Layout } from "../../../src/settings/enums/Layout";
|
import { Layout } from "../../../src/settings/enums/Layout";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
@ -67,7 +67,7 @@ const sendEvent = (roomId: string, html = false): Chainable<ISendEventResponse>
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("Timeline", () => {
|
describe("Timeline", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
let roomId: string;
|
let roomId: string;
|
||||||
|
|
||||||
|
@ -75,9 +75,9 @@ describe("Timeline", () => {
|
||||||
let newAvatarUrl: string;
|
let newAvatarUrl: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, OLD_NAME).then(() =>
|
cy.initTestUser(homeserver, OLD_NAME).then(() =>
|
||||||
cy.createRoom({ name: ROOM_NAME }).then((_room1Id) => {
|
cy.createRoom({ name: ROOM_NAME }).then((_room1Id) => {
|
||||||
roomId = _room1Id;
|
roomId = _room1Id;
|
||||||
}),
|
}),
|
||||||
|
@ -86,7 +86,7 @@ describe("Timeline", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("useOnlyCurrentProfiles", () => {
|
describe("useOnlyCurrentProfiles", () => {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
function assertNoToasts(): void {
|
function assertNoToasts(): void {
|
||||||
|
@ -40,10 +40,10 @@ function rejectToast(expectedTitle: string): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Analytics Toast", () => {
|
describe("Analytics Toast", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not show an analytics toast if config has nothing about posthog", () => {
|
it("should not show an analytics toast if config has nothing about posthog", () => {
|
||||||
|
@ -55,9 +55,9 @@ describe("Analytics Toast", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, "Tod");
|
cy.initTestUser(homeserver, "Tod");
|
||||||
});
|
});
|
||||||
|
|
||||||
rejectToast("Notifications");
|
rejectToast("Notifications");
|
||||||
|
@ -78,9 +78,9 @@ describe("Analytics Toast", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, "Tod");
|
cy.initTestUser(homeserver, "Tod");
|
||||||
rejectToast("Notifications");
|
rejectToast("Notifications");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,19 +16,19 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
describe("Update", () => {
|
describe("Update", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should navigate to ?updated=$VERSION if realises it is immediately out of date on load", () => {
|
it("should navigate to ?updated=$VERSION if realises it is immediately out of date on load", () => {
|
||||||
|
@ -42,7 +42,7 @@ describe("Update", () => {
|
||||||
},
|
},
|
||||||
}).as("version");
|
}).as("version");
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Ursa");
|
cy.initTestUser(homeserver, "Ursa");
|
||||||
|
|
||||||
cy.wait("@version");
|
cy.wait("@version");
|
||||||
cy.url()
|
cy.url()
|
||||||
|
|
|
@ -16,25 +16,25 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import type { UserCredentials } from "../../support/login";
|
import type { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
describe("User Menu", () => {
|
describe("User Menu", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let user: UserCredentials;
|
let user: UserCredentials;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Jeff").then((credentials) => {
|
cy.initTestUser(homeserver, "Jeff").then((credentials) => {
|
||||||
user = credentials;
|
user = credentials;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should contain our name & userId", () => {
|
it("should contain our name & userId", () => {
|
||||||
|
|
|
@ -17,18 +17,18 @@ limitations under the License.
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
describe("User Onboarding (new user)", () => {
|
describe("User Onboarding (new user)", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
const bot1Name = "BotBob";
|
const bot1Name = "BotBob";
|
||||||
let bot1: MatrixClient;
|
let bot1: MatrixClient;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, "Jane Doe");
|
cy.initTestUser(homeserver, "Jane Doe");
|
||||||
cy.window({ log: false }).then((win) => {
|
cy.window({ log: false }).then((win) => {
|
||||||
win.localStorage.setItem("mx_registration_time", "1656633601");
|
win.localStorage.setItem("mx_registration_time", "1656633601");
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,7 @@ describe("User Onboarding (new user)", () => {
|
||||||
// wait for the app to load
|
// wait for the app to load
|
||||||
return cy.get(".mx_MatrixChat", { timeout: 15000 });
|
return cy.get(".mx_MatrixChat", { timeout: 15000 });
|
||||||
});
|
});
|
||||||
cy.getBot(synapse, { displayName: bot1Name }).then((_bot1) => {
|
cy.getBot(homeserver, { displayName: bot1Name }).then((_bot1) => {
|
||||||
bot1 = _bot1;
|
bot1 = _bot1;
|
||||||
});
|
});
|
||||||
cy.get(".mx_UserOnboardingPage").should("exist");
|
cy.get(".mx_UserOnboardingPage").should("exist");
|
||||||
|
@ -51,7 +51,7 @@ describe("User Onboarding (new user)", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("page is shown and preference exists", () => {
|
it("page is shown and preference exists", () => {
|
||||||
|
|
|
@ -16,15 +16,15 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
describe("User Onboarding (old user)", () => {
|
describe("User Onboarding (old user)", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
cy.initTestUser(synapse, "Jane Doe");
|
cy.initTestUser(homeserver, "Jane Doe");
|
||||||
cy.window({ log: false }).then((win) => {
|
cy.window({ log: false }).then((win) => {
|
||||||
win.localStorage.setItem("mx_registration_time", "2");
|
win.localStorage.setItem("mx_registration_time", "2");
|
||||||
});
|
});
|
||||||
|
@ -37,7 +37,7 @@ describe("User Onboarding (old user)", () => {
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.visit("/#/home");
|
cy.visit("/#/home");
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("page and preference are hidden", () => {
|
it("page and preference are hidden", () => {
|
||||||
|
|
|
@ -16,23 +16,23 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { MatrixClient } from "../../global";
|
import { MatrixClient } from "../../global";
|
||||||
|
|
||||||
describe("UserView", () => {
|
describe("UserView", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Violet");
|
cy.initTestUser(homeserver, "Violet");
|
||||||
cy.getBot(synapse, { displayName: "Usman" }).as("bot");
|
cy.getBot(homeserver, { displayName: "Usman" }).as("bot");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render the user view as expected", () => {
|
it("should render the user view as expected", () => {
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
import { IWidget } from "matrix-widget-api";
|
import { IWidget } from "matrix-widget-api";
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
const ROOM_NAME = "Test Room";
|
const ROOM_NAME = "Test Room";
|
||||||
const WIDGET_ID = "fake-widget";
|
const WIDGET_ID = "fake-widget";
|
||||||
|
@ -34,14 +34,14 @@ const WIDGET_HTML = `
|
||||||
|
|
||||||
describe("Widget Layout", () => {
|
describe("Widget Layout", () => {
|
||||||
let widgetUrl: string;
|
let widgetUrl: string;
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let roomId: string;
|
let roomId: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Sally");
|
cy.initTestUser(homeserver, "Sally");
|
||||||
});
|
});
|
||||||
cy.serveHtmlFile(WIDGET_HTML).then((url) => {
|
cy.serveHtmlFile(WIDGET_HTML).then((url) => {
|
||||||
widgetUrl = url;
|
widgetUrl = url;
|
||||||
|
@ -91,7 +91,7 @@ describe("Widget Layout", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
cy.stopWebServers();
|
cy.stopWebServers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
|
||||||
const STICKER_PICKER_WIDGET_ID = "fake-sticker-picker";
|
const STICKER_PICKER_WIDGET_ID = "fake-sticker-picker";
|
||||||
const STICKER_PICKER_WIDGET_NAME = "Fake Stickers";
|
const STICKER_PICKER_WIDGET_NAME = "Fake Stickers";
|
||||||
|
@ -102,13 +102,13 @@ describe("Stickers", () => {
|
||||||
// See sendStickerFromPicker() for more detail on iframe comms.
|
// See sendStickerFromPicker() for more detail on iframe comms.
|
||||||
|
|
||||||
let stickerPickerUrl: string;
|
let stickerPickerUrl: string;
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Sally");
|
cy.initTestUser(homeserver, "Sally");
|
||||||
});
|
});
|
||||||
cy.serveHtmlFile(WIDGET_HTML).then((url) => {
|
cy.serveHtmlFile(WIDGET_HTML).then((url) => {
|
||||||
stickerPickerUrl = url;
|
stickerPickerUrl = url;
|
||||||
|
@ -116,7 +116,7 @@ describe("Stickers", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
cy.stopWebServers();
|
cy.stopWebServers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ limitations under the License.
|
||||||
import { IWidget } from "matrix-widget-api/src/interfaces/IWidget";
|
import { IWidget } from "matrix-widget-api/src/interfaces/IWidget";
|
||||||
|
|
||||||
import type { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import type { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
import { UserCredentials } from "../../support/login";
|
import { UserCredentials } from "../../support/login";
|
||||||
|
|
||||||
const DEMO_WIDGET_ID = "demo-widget-id";
|
const DEMO_WIDGET_ID = "demo-widget-id";
|
||||||
|
@ -90,7 +90,7 @@ function waitForRoomWidget(win: Cypress.AUTWindow, widgetId: string, roomId: str
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Widget PIP", () => {
|
describe("Widget PIP", () => {
|
||||||
let synapse: SynapseInstance;
|
let homeserver: HomeserverInstance;
|
||||||
let user: UserCredentials;
|
let user: UserCredentials;
|
||||||
let bot: MatrixClient;
|
let bot: MatrixClient;
|
||||||
let demoWidgetUrl: string;
|
let demoWidgetUrl: string;
|
||||||
|
@ -173,13 +173,13 @@ describe("Widget PIP", () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.startSynapse("default").then((data) => {
|
cy.startHomeserver("default").then((data) => {
|
||||||
synapse = data;
|
homeserver = data;
|
||||||
|
|
||||||
cy.initTestUser(synapse, "Mike").then((_user) => {
|
cy.initTestUser(homeserver, "Mike").then((_user) => {
|
||||||
user = _user;
|
user = _user;
|
||||||
});
|
});
|
||||||
cy.getBot(synapse, { displayName: "Bot", autoAcceptInvites: false }).then((_bot) => {
|
cy.getBot(homeserver, { displayName: "Bot", autoAcceptInvites: false }).then((_bot) => {
|
||||||
bot = _bot;
|
bot = _bot;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -189,7 +189,7 @@ describe("Widget PIP", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
cy.stopWebServers();
|
cy.stopWebServers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
181
cypress/plugins/dendritedocker/index.ts
Normal file
181
cypress/plugins/dendritedocker/index.ts
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
import * as path from "path";
|
||||||
|
import * as os from "os";
|
||||||
|
import * as crypto from "crypto";
|
||||||
|
import * as fse from "fs-extra";
|
||||||
|
|
||||||
|
import PluginEvents = Cypress.PluginEvents;
|
||||||
|
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
||||||
|
import { getFreePort } from "../utils/port";
|
||||||
|
import { dockerExec, dockerLogs, dockerRun, dockerStop } from "../docker";
|
||||||
|
import { HomeserverConfig, HomeserverInstance } from "../utils/homeserver";
|
||||||
|
|
||||||
|
// A cypress plugins to add command to start & stop dendrites in
|
||||||
|
// docker with preset templates.
|
||||||
|
|
||||||
|
const dendrites = new Map<string, HomeserverInstance>();
|
||||||
|
|
||||||
|
function randB64Bytes(numBytes: number): string {
|
||||||
|
return crypto.randomBytes(numBytes).toString("base64").replace(/=*$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cfgDirFromTemplate(template: string): Promise<HomeserverConfig> {
|
||||||
|
template = "default";
|
||||||
|
const templateDir = path.join(__dirname, "templates", template);
|
||||||
|
const configFile = "dendrite.yaml";
|
||||||
|
|
||||||
|
const stats = await fse.stat(templateDir);
|
||||||
|
if (!stats?.isDirectory) {
|
||||||
|
throw new Error(`No such template: ${template}`);
|
||||||
|
}
|
||||||
|
const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-dendritedocker-"));
|
||||||
|
|
||||||
|
// copy the contents of the template dir, omitting homeserver.yaml as we'll template that
|
||||||
|
console.log(`Copy ${templateDir} -> ${tempDir}`);
|
||||||
|
await fse.copy(templateDir, tempDir, { filter: (f) => path.basename(f) !== configFile });
|
||||||
|
|
||||||
|
const registrationSecret = randB64Bytes(16);
|
||||||
|
|
||||||
|
const port = await getFreePort();
|
||||||
|
const baseUrl = `http://localhost:${port}`;
|
||||||
|
|
||||||
|
// now copy homeserver.yaml, applying substitutions
|
||||||
|
console.log(`Gen ${path.join(templateDir, configFile)}`);
|
||||||
|
let hsYaml = await fse.readFile(path.join(templateDir, configFile), "utf8");
|
||||||
|
hsYaml = hsYaml.replace(/{{REGISTRATION_SECRET}}/g, registrationSecret);
|
||||||
|
await fse.writeFile(path.join(tempDir, configFile), hsYaml);
|
||||||
|
|
||||||
|
await dockerRun({
|
||||||
|
image: "matrixdotorg/dendrite-monolith:main",
|
||||||
|
params: ["--rm", "--entrypoint=", "-v", `${tempDir}:/mnt`],
|
||||||
|
containerName: `react-sdk-cypress-dendrite-keygen`,
|
||||||
|
cmd: ["/usr/bin/generate-keys", "-private-key", "/mnt/matrix_key.pem"],
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
port,
|
||||||
|
baseUrl,
|
||||||
|
configDir: tempDir,
|
||||||
|
registrationSecret,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a dendrite instance: the template must be the name of
|
||||||
|
// one of the templates in the cypress/plugins/dendritedocker/templates
|
||||||
|
// directory
|
||||||
|
async function dendriteStart(template: string): Promise<HomeserverInstance> {
|
||||||
|
const denCfg = await cfgDirFromTemplate(template);
|
||||||
|
|
||||||
|
console.log(`Starting dendrite with config dir ${denCfg.configDir}...`);
|
||||||
|
|
||||||
|
const dendriteId = await dockerRun({
|
||||||
|
image: "matrixdotorg/dendrite-monolith:main",
|
||||||
|
params: [
|
||||||
|
"--rm",
|
||||||
|
"-v",
|
||||||
|
`${denCfg.configDir}:/etc/dendrite`,
|
||||||
|
"-p",
|
||||||
|
`${denCfg.port}:8008/tcp`,
|
||||||
|
"--entrypoint",
|
||||||
|
"/usr/bin/dendrite-monolith-server",
|
||||||
|
],
|
||||||
|
containerName: `react-sdk-cypress-dendrite`,
|
||||||
|
cmd: ["--really-enable-open-registration", "true", "run"],
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Started dendrite with id ${dendriteId} on port ${denCfg.port}.`);
|
||||||
|
|
||||||
|
// Await Dendrite healthcheck
|
||||||
|
await dockerExec({
|
||||||
|
containerId: dendriteId,
|
||||||
|
params: [
|
||||||
|
"curl",
|
||||||
|
"--connect-timeout",
|
||||||
|
"30",
|
||||||
|
"--retry",
|
||||||
|
"30",
|
||||||
|
"--retry-delay",
|
||||||
|
"1",
|
||||||
|
"--retry-all-errors",
|
||||||
|
"--silent",
|
||||||
|
"http://localhost:8008/_matrix/client/versions",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const dendrite: HomeserverInstance = { serverId: dendriteId, ...denCfg };
|
||||||
|
dendrites.set(dendriteId, dendrite);
|
||||||
|
return dendrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function dendriteStop(id: string): Promise<void> {
|
||||||
|
const denCfg = dendrites.get(id);
|
||||||
|
|
||||||
|
if (!denCfg) throw new Error("Unknown dendrite ID");
|
||||||
|
|
||||||
|
const dendriteLogsPath = path.join("cypress", "dendritelogs", id);
|
||||||
|
await fse.ensureDir(dendriteLogsPath);
|
||||||
|
|
||||||
|
await dockerLogs({
|
||||||
|
containerId: id,
|
||||||
|
stdoutFile: path.join(dendriteLogsPath, "stdout.log"),
|
||||||
|
stderrFile: path.join(dendriteLogsPath, "stderr.log"),
|
||||||
|
});
|
||||||
|
|
||||||
|
await dockerStop({
|
||||||
|
containerId: id,
|
||||||
|
});
|
||||||
|
|
||||||
|
await fse.remove(denCfg.configDir);
|
||||||
|
|
||||||
|
dendrites.delete(id);
|
||||||
|
|
||||||
|
console.log(`Stopped dendrite id ${id}.`);
|
||||||
|
// cypress deliberately fails if you return 'undefined', so
|
||||||
|
// return null to signal all is well, and we've handled the task.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Cypress.PluginConfig}
|
||||||
|
*/
|
||||||
|
export function dendriteDocker(on: PluginEvents, config: PluginConfigOptions) {
|
||||||
|
on("task", {
|
||||||
|
dendriteStart,
|
||||||
|
dendriteStop,
|
||||||
|
});
|
||||||
|
|
||||||
|
on("after:spec", async (spec) => {
|
||||||
|
// Cleans up any remaining dendrite instances after a spec run
|
||||||
|
// This is on the theory that we should avoid re-using dendrite
|
||||||
|
// instances between spec runs: they should be cheap enough to
|
||||||
|
// start that we can have a separate one for each spec run or even
|
||||||
|
// test. If we accidentally re-use dendrites, we could inadvertently
|
||||||
|
// make our tests depend on each other.
|
||||||
|
for (const denId of dendrites.keys()) {
|
||||||
|
console.warn(`Cleaning up dendrite ID ${denId} after ${spec.name}`);
|
||||||
|
await dendriteStop(denId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
on("before:run", async () => {
|
||||||
|
// tidy up old dendrite log files before each run
|
||||||
|
await fse.emptyDir(path.join("cypress", "dendritelogs"));
|
||||||
|
});
|
||||||
|
}
|
374
cypress/plugins/dendritedocker/templates/default/dendrite.yaml
Normal file
374
cypress/plugins/dendritedocker/templates/default/dendrite.yaml
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
# This is the Dendrite configuration file.
|
||||||
|
#
|
||||||
|
# The configuration is split up into sections - each Dendrite component has a
|
||||||
|
# configuration section, in addition to the "global" section which applies to
|
||||||
|
# all components.
|
||||||
|
|
||||||
|
# The version of the configuration file.
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Global Matrix configuration. This configuration applies to all components.
|
||||||
|
global:
|
||||||
|
# The domain name of this homeserver.
|
||||||
|
server_name: localhost
|
||||||
|
|
||||||
|
# The path to the signing private key file, used to sign requests and events.
|
||||||
|
# Note that this is NOT the same private key as used for TLS! To generate a
|
||||||
|
# signing key, use "./bin/generate-keys --private-key matrix_key.pem".
|
||||||
|
private_key: matrix_key.pem
|
||||||
|
|
||||||
|
# The paths and expiry timestamps (as a UNIX timestamp in millisecond precision)
|
||||||
|
# to old signing keys that were formerly in use on this domain name. These
|
||||||
|
# keys will not be used for federation request or event signing, but will be
|
||||||
|
# provided to any other homeserver that asks when trying to verify old events.
|
||||||
|
old_private_keys:
|
||||||
|
# If the old private key file is available:
|
||||||
|
# - private_key: old_matrix_key.pem
|
||||||
|
# expired_at: 1601024554498
|
||||||
|
# If only the public key (in base64 format) and key ID are known:
|
||||||
|
# - public_key: mn59Kxfdq9VziYHSBzI7+EDPDcBS2Xl7jeUdiiQcOnM=
|
||||||
|
# key_id: ed25519:mykeyid
|
||||||
|
# expired_at: 1601024554498
|
||||||
|
|
||||||
|
# How long a remote server can cache our server signing key before requesting it
|
||||||
|
# again. Increasing this number will reduce the number of requests made by other
|
||||||
|
# servers for our key but increases the period that a compromised key will be
|
||||||
|
# considered valid by other homeservers.
|
||||||
|
key_validity_period: 168h0m0s
|
||||||
|
|
||||||
|
# Global database connection pool, for PostgreSQL monolith deployments only. If
|
||||||
|
# this section is populated then you can omit the "database" blocks in all other
|
||||||
|
# sections. For polylith deployments, or monolith deployments using SQLite databases,
|
||||||
|
# you must configure the "database" block for each component instead.
|
||||||
|
# database:
|
||||||
|
# connection_string: postgresql://username:password@hostname/dendrite?sslmode=disable
|
||||||
|
# max_open_conns: 90
|
||||||
|
# max_idle_conns: 5
|
||||||
|
# conn_max_lifetime: -1
|
||||||
|
|
||||||
|
# Configuration for in-memory caches. Caches can often improve performance by
|
||||||
|
# keeping frequently accessed items (like events, identifiers etc.) in memory
|
||||||
|
# rather than having to read them from the database.
|
||||||
|
cache:
|
||||||
|
# The estimated maximum size for the global cache in bytes, or in terabytes,
|
||||||
|
# gigabytes, megabytes or kilobytes when the appropriate 'tb', 'gb', 'mb' or
|
||||||
|
# 'kb' suffix is specified. Note that this is not a hard limit, nor is it a
|
||||||
|
# memory limit for the entire process. A cache that is too small may ultimately
|
||||||
|
# provide little or no benefit.
|
||||||
|
max_size_estimated: 1gb
|
||||||
|
|
||||||
|
# The maximum amount of time that a cache entry can live for in memory before
|
||||||
|
# it will be evicted and/or refreshed from the database. Lower values result in
|
||||||
|
# easier admission of new cache entries but may also increase database load in
|
||||||
|
# comparison to higher values, so adjust conservatively. Higher values may make
|
||||||
|
# it harder for new items to make it into the cache, e.g. if new rooms suddenly
|
||||||
|
# become popular.
|
||||||
|
max_age: 1h
|
||||||
|
|
||||||
|
# The server name to delegate server-server communications to, with optional port
|
||||||
|
# e.g. localhost:443
|
||||||
|
well_known_server_name: ""
|
||||||
|
|
||||||
|
# The server name to delegate client-server communications to, with optional port
|
||||||
|
# e.g. localhost:443
|
||||||
|
well_known_client_name: ""
|
||||||
|
|
||||||
|
# Lists of domains that the server will trust as identity servers to verify third
|
||||||
|
# party identifiers such as phone numbers and email addresses.
|
||||||
|
trusted_third_party_id_servers:
|
||||||
|
- matrix.org
|
||||||
|
- vector.im
|
||||||
|
|
||||||
|
# Disables federation. Dendrite will not be able to communicate with other servers
|
||||||
|
# in the Matrix federation and the federation API will not be exposed.
|
||||||
|
disable_federation: false
|
||||||
|
|
||||||
|
# Configures the handling of presence events. Inbound controls whether we receive
|
||||||
|
# presence events from other servers, outbound controls whether we send presence
|
||||||
|
# events for our local users to other servers.
|
||||||
|
presence:
|
||||||
|
enable_inbound: false
|
||||||
|
enable_outbound: false
|
||||||
|
|
||||||
|
# Configures phone-home statistics reporting. These statistics contain the server
|
||||||
|
# name, number of active users and some information on your deployment config.
|
||||||
|
# We use this information to understand how Dendrite is being used in the wild.
|
||||||
|
report_stats:
|
||||||
|
enabled: false
|
||||||
|
endpoint: https://matrix.org/report-usage-stats/push
|
||||||
|
|
||||||
|
# Server notices allows server admins to send messages to all users on the server.
|
||||||
|
server_notices:
|
||||||
|
enabled: false
|
||||||
|
# The local part, display name and avatar URL (as a mxc:// URL) for the user that
|
||||||
|
# will send the server notices. These are visible to all users on the deployment.
|
||||||
|
local_part: "_server"
|
||||||
|
display_name: "Server Alerts"
|
||||||
|
avatar_url: ""
|
||||||
|
# The room name to be used when sending server notices. This room name will
|
||||||
|
# appear in user clients.
|
||||||
|
room_name: "Server Alerts"
|
||||||
|
|
||||||
|
# Configuration for NATS JetStream
|
||||||
|
jetstream:
|
||||||
|
# A list of NATS Server addresses to connect to. If none are specified, an
|
||||||
|
# internal NATS server will be started automatically when running Dendrite in
|
||||||
|
# monolith mode. For polylith deployments, it is required to specify the address
|
||||||
|
# of at least one NATS Server node.
|
||||||
|
addresses:
|
||||||
|
# - localhost:4222
|
||||||
|
|
||||||
|
# Disable the validation of TLS certificates of NATS. This is
|
||||||
|
# not recommended in production since it may allow NATS traffic
|
||||||
|
# to be sent to an insecure endpoint.
|
||||||
|
disable_tls_validation: false
|
||||||
|
|
||||||
|
# Persistent directory to store JetStream streams in. This directory should be
|
||||||
|
# preserved across Dendrite restarts.
|
||||||
|
storage_path: ./
|
||||||
|
|
||||||
|
# The prefix to use for stream names for this homeserver - really only useful
|
||||||
|
# if you are running more than one Dendrite server on the same NATS deployment.
|
||||||
|
topic_prefix: Dendrite
|
||||||
|
|
||||||
|
# Configuration for Prometheus metric collection.
|
||||||
|
metrics:
|
||||||
|
enabled: false
|
||||||
|
basic_auth:
|
||||||
|
username: metrics
|
||||||
|
password: metrics
|
||||||
|
|
||||||
|
# Optional DNS cache. The DNS cache may reduce the load on DNS servers if there
|
||||||
|
# is no local caching resolver available for use.
|
||||||
|
dns_cache:
|
||||||
|
enabled: false
|
||||||
|
cache_size: 256
|
||||||
|
cache_lifetime: "5m" # 5 minutes; https://pkg.go.dev/time@master#ParseDuration
|
||||||
|
|
||||||
|
# Configuration for the Appservice API.
|
||||||
|
app_service_api:
|
||||||
|
# Disable the validation of TLS certificates of appservices. This is
|
||||||
|
# not recommended in production since it may allow appservice traffic
|
||||||
|
# to be sent to an insecure endpoint.
|
||||||
|
disable_tls_validation: false
|
||||||
|
|
||||||
|
# Appservice configuration files to load into this homeserver.
|
||||||
|
config_files:
|
||||||
|
# - /path/to/appservice_registration.yaml
|
||||||
|
|
||||||
|
# Configuration for the Client API.
|
||||||
|
client_api:
|
||||||
|
# Prevents new users from being able to register on this homeserver, except when
|
||||||
|
# using the registration shared secret below.
|
||||||
|
registration_disabled: false
|
||||||
|
|
||||||
|
# Prevents new guest accounts from being created. Guest registration is also
|
||||||
|
# disabled implicitly by setting 'registration_disabled' above.
|
||||||
|
guests_disabled: true
|
||||||
|
|
||||||
|
# If set, allows registration by anyone who knows the shared secret, regardless
|
||||||
|
# of whether registration is otherwise disabled.
|
||||||
|
registration_shared_secret: "{{REGISTRATION_SECRET}}"
|
||||||
|
|
||||||
|
# Whether to require reCAPTCHA for registration. If you have enabled registration
|
||||||
|
# then this is HIGHLY RECOMMENDED to reduce the risk of your homeserver being used
|
||||||
|
# for coordinated spam attacks.
|
||||||
|
enable_registration_captcha: false
|
||||||
|
|
||||||
|
# Settings for ReCAPTCHA.
|
||||||
|
recaptcha_public_key: ""
|
||||||
|
recaptcha_private_key: ""
|
||||||
|
recaptcha_bypass_secret: ""
|
||||||
|
|
||||||
|
# To use hcaptcha.com instead of ReCAPTCHA, set the following parameters, otherwise just keep them empty.
|
||||||
|
# recaptcha_siteverify_api: "https://hcaptcha.com/siteverify"
|
||||||
|
# recaptcha_api_js_url: "https://js.hcaptcha.com/1/api.js"
|
||||||
|
# recaptcha_form_field: "h-captcha-response"
|
||||||
|
# recaptcha_sitekey_class: "h-captcha"
|
||||||
|
|
||||||
|
# TURN server information that this homeserver should send to clients.
|
||||||
|
turn:
|
||||||
|
turn_user_lifetime: "5m"
|
||||||
|
turn_uris:
|
||||||
|
# - turn:turn.server.org?transport=udp
|
||||||
|
# - turn:turn.server.org?transport=tcp
|
||||||
|
turn_shared_secret: ""
|
||||||
|
# If your TURN server requires static credentials, then you will need to enter
|
||||||
|
# them here instead of supplying a shared secret. Note that these credentials
|
||||||
|
# will be visible to clients!
|
||||||
|
# turn_username: ""
|
||||||
|
# turn_password: ""
|
||||||
|
|
||||||
|
# Settings for rate-limited endpoints. Rate limiting kicks in after the threshold
|
||||||
|
# number of "slots" have been taken by requests from a specific host. Each "slot"
|
||||||
|
# will be released after the cooloff time in milliseconds. Server administrators
|
||||||
|
# and appservice users are exempt from rate limiting by default.
|
||||||
|
rate_limiting:
|
||||||
|
enabled: true
|
||||||
|
threshold: 20
|
||||||
|
cooloff_ms: 500
|
||||||
|
exempt_user_ids:
|
||||||
|
# - "@user:domain.com"
|
||||||
|
|
||||||
|
# Configuration for the Federation API.
|
||||||
|
federation_api:
|
||||||
|
# How many times we will try to resend a failed transaction to a specific server. The
|
||||||
|
# backoff is 2**x seconds, so 1 = 2 seconds, 2 = 4 seconds, 3 = 8 seconds etc. Once
|
||||||
|
# the max retries are exceeded, Dendrite will no longer try to send transactions to
|
||||||
|
# that server until it comes back to life and connects to us again.
|
||||||
|
send_max_retries: 16
|
||||||
|
|
||||||
|
# Disable the validation of TLS certificates of remote federated homeservers. Do not
|
||||||
|
# enable this option in production as it presents a security risk!
|
||||||
|
disable_tls_validation: false
|
||||||
|
|
||||||
|
# Disable HTTP keepalives, which also prevents connection reuse. Dendrite will typically
|
||||||
|
# keep HTTP connections open to remote hosts for 5 minutes as they can be reused much
|
||||||
|
# more quickly than opening new connections each time. Disabling keepalives will close
|
||||||
|
# HTTP connections immediately after a successful request but may result in more CPU and
|
||||||
|
# memory being used on TLS handshakes for each new connection instead.
|
||||||
|
disable_http_keepalives: false
|
||||||
|
|
||||||
|
# Perspective keyservers to use as a backup when direct key fetches fail. This may
|
||||||
|
# be required to satisfy key requests for servers that are no longer online when
|
||||||
|
# joining some rooms.
|
||||||
|
key_perspectives:
|
||||||
|
- server_name: matrix.org
|
||||||
|
keys:
|
||||||
|
- key_id: ed25519:auto
|
||||||
|
public_key: Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw
|
||||||
|
- key_id: ed25519:a_RXGa
|
||||||
|
public_key: l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ
|
||||||
|
|
||||||
|
# This option will control whether Dendrite will prefer to look up keys directly
|
||||||
|
# or whether it should try perspective servers first, using direct fetches as a
|
||||||
|
# last resort.
|
||||||
|
prefer_direct_fetch: false
|
||||||
|
|
||||||
|
database:
|
||||||
|
connection_string: file:dendrite-federationapi.db
|
||||||
|
|
||||||
|
# Configuration for the Media API.
|
||||||
|
media_api:
|
||||||
|
# Storage path for uploaded media. May be relative or absolute.
|
||||||
|
base_path: ./media_store
|
||||||
|
|
||||||
|
# The maximum allowed file size (in bytes) for media uploads to this homeserver
|
||||||
|
# (0 = unlimited). If using a reverse proxy, ensure it allows requests at least
|
||||||
|
#this large (e.g. the client_max_body_size setting in nginx).
|
||||||
|
max_file_size_bytes: 10485760
|
||||||
|
|
||||||
|
# Whether to dynamically generate thumbnails if needed.
|
||||||
|
dynamic_thumbnails: false
|
||||||
|
|
||||||
|
# The maximum number of simultaneous thumbnail generators to run.
|
||||||
|
max_thumbnail_generators: 10
|
||||||
|
|
||||||
|
# A list of thumbnail sizes to be generated for media content.
|
||||||
|
thumbnail_sizes:
|
||||||
|
- width: 32
|
||||||
|
height: 32
|
||||||
|
method: crop
|
||||||
|
- width: 96
|
||||||
|
height: 96
|
||||||
|
method: crop
|
||||||
|
- width: 640
|
||||||
|
height: 480
|
||||||
|
method: scale
|
||||||
|
|
||||||
|
database:
|
||||||
|
connection_string: file:dendrite-mediaapi.db
|
||||||
|
|
||||||
|
# Configuration for enabling experimental MSCs on this homeserver.
|
||||||
|
mscs:
|
||||||
|
mscs:
|
||||||
|
# - msc2836 # (Threading, see https://github.com/matrix-org/matrix-doc/pull/2836)
|
||||||
|
# - msc2946 # (Spaces Summary, see https://github.com/matrix-org/matrix-doc/pull/2946)
|
||||||
|
|
||||||
|
database:
|
||||||
|
connection_string: file:dendrite-msc.db
|
||||||
|
|
||||||
|
# Configuration for the Sync API.
|
||||||
|
sync_api:
|
||||||
|
# This option controls which HTTP header to inspect to find the real remote IP
|
||||||
|
# address of the client. This is likely required if Dendrite is running behind
|
||||||
|
# a reverse proxy server.
|
||||||
|
# real_ip_header: X-Real-IP
|
||||||
|
|
||||||
|
# Configuration for the full-text search engine.
|
||||||
|
search:
|
||||||
|
# Whether or not search is enabled.
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# The path where the search index will be created in.
|
||||||
|
index_path: "./searchindex"
|
||||||
|
|
||||||
|
# The language most likely to be used on the server - used when indexing, to
|
||||||
|
# ensure the returned results match expectations. A full list of possible languages
|
||||||
|
# can be found at https://github.com/blevesearch/bleve/tree/master/analysis/lang
|
||||||
|
language: "en"
|
||||||
|
|
||||||
|
database:
|
||||||
|
connection_string: file:dendrite-syncapi.db
|
||||||
|
|
||||||
|
# Configuration for the User API.
|
||||||
|
user_api:
|
||||||
|
# The cost when hashing passwords on registration/login. Default: 10. Min: 4, Max: 31
|
||||||
|
# See https://pkg.go.dev/golang.org/x/crypto/bcrypt for more information.
|
||||||
|
# Setting this lower makes registration/login consume less CPU resources at the cost
|
||||||
|
# of security should the database be compromised. Setting this higher makes registration/login
|
||||||
|
# consume more CPU resources but makes it harder to brute force password hashes. This value
|
||||||
|
# can be lowered if performing tests or on embedded Dendrite instances (e.g WASM builds).
|
||||||
|
bcrypt_cost: 10
|
||||||
|
|
||||||
|
# The length of time that a token issued for a relying party from
|
||||||
|
# /_matrix/client/r0/user/{userId}/openid/request_token endpoint
|
||||||
|
# is considered to be valid in milliseconds.
|
||||||
|
# The default lifetime is 3600000ms (60 minutes).
|
||||||
|
# openid_token_lifetime_ms: 3600000
|
||||||
|
|
||||||
|
# Users who register on this homeserver will automatically be joined to the rooms listed under "auto_join_rooms" option.
|
||||||
|
# By default, any room aliases included in this list will be created as a publicly joinable room
|
||||||
|
# when the first user registers for the homeserver. If the room already exists,
|
||||||
|
# make certain it is a publicly joinable room, i.e. the join rule of the room must be set to 'public'.
|
||||||
|
# As Spaces are just rooms under the hood, Space aliases may also be used.
|
||||||
|
auto_join_rooms:
|
||||||
|
# - "#main:matrix.org"
|
||||||
|
|
||||||
|
account_database:
|
||||||
|
connection_string: file:dendrite-userapi.db
|
||||||
|
|
||||||
|
room_server:
|
||||||
|
database:
|
||||||
|
connection_string: file:dendrite-roomserverapi.db
|
||||||
|
|
||||||
|
key_server:
|
||||||
|
database:
|
||||||
|
connection_string: file:dendrite-keyserverapi.db
|
||||||
|
|
||||||
|
# Configuration for Opentracing.
|
||||||
|
# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on
|
||||||
|
# how this works and how to set it up.
|
||||||
|
tracing:
|
||||||
|
enabled: false
|
||||||
|
jaeger:
|
||||||
|
serviceName: ""
|
||||||
|
disabled: false
|
||||||
|
rpc_metrics: false
|
||||||
|
tags: []
|
||||||
|
sampler: null
|
||||||
|
reporter: null
|
||||||
|
headers: null
|
||||||
|
baggage_restrictions: null
|
||||||
|
throttler: null
|
||||||
|
|
||||||
|
# Logging configuration. The "std" logging type controls the logs being sent to
|
||||||
|
# stdout. The "file" logging type controls logs being written to a log folder on
|
||||||
|
# the disk. Supported log levels are "debug", "info", "warn", "error".
|
||||||
|
logging:
|
||||||
|
- type: std
|
||||||
|
level: debug
|
||||||
|
- type: file
|
||||||
|
level: debug
|
||||||
|
params:
|
||||||
|
path: ./logs
|
|
@ -30,7 +30,7 @@ export function dockerRun(opts: {
|
||||||
image: string;
|
image: string;
|
||||||
containerName: string;
|
containerName: string;
|
||||||
params?: string[];
|
params?: string[];
|
||||||
cmd?: string;
|
cmd?: string[];
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
const userInfo = os.userInfo();
|
const userInfo = os.userInfo();
|
||||||
const params = opts.params ?? [];
|
const params = opts.params ?? [];
|
||||||
|
@ -49,7 +49,7 @@ export function dockerRun(opts: {
|
||||||
opts.image,
|
opts.image,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (opts.cmd) args.push(opts.cmd);
|
if (opts.cmd) args.push(...opts.cmd);
|
||||||
|
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
childProcess.execFile("docker", args, (err, stdout) => {
|
childProcess.execFile("docker", args, (err, stdout) => {
|
||||||
|
|
|
@ -19,6 +19,7 @@ limitations under the License.
|
||||||
import PluginEvents = Cypress.PluginEvents;
|
import PluginEvents = Cypress.PluginEvents;
|
||||||
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
||||||
import { synapseDocker } from "./synapsedocker";
|
import { synapseDocker } from "./synapsedocker";
|
||||||
|
import { dendriteDocker } from "./dendritedocker";
|
||||||
import { slidingSyncProxyDocker } from "./sliding-sync";
|
import { slidingSyncProxyDocker } from "./sliding-sync";
|
||||||
import { webserver } from "./webserver";
|
import { webserver } from "./webserver";
|
||||||
import { docker } from "./docker";
|
import { docker } from "./docker";
|
||||||
|
@ -30,6 +31,7 @@ import { log } from "./log";
|
||||||
export default function (on: PluginEvents, config: PluginConfigOptions) {
|
export default function (on: PluginEvents, config: PluginConfigOptions) {
|
||||||
docker(on, config);
|
docker(on, config);
|
||||||
synapseDocker(on, config);
|
synapseDocker(on, config);
|
||||||
|
dendriteDocker(on, config);
|
||||||
slidingSyncProxyDocker(on, config);
|
slidingSyncProxyDocker(on, config);
|
||||||
webserver(on, config);
|
webserver(on, config);
|
||||||
log(on, config);
|
log(on, config);
|
||||||
|
|
|
@ -20,7 +20,7 @@ import PluginEvents = Cypress.PluginEvents;
|
||||||
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
||||||
import { dockerExec, dockerIp, dockerRun, dockerStop } from "../docker";
|
import { dockerExec, dockerIp, dockerRun, dockerStop } from "../docker";
|
||||||
import { getFreePort } from "../utils/port";
|
import { getFreePort } from "../utils/port";
|
||||||
import { SynapseInstance } from "../synapsedocker";
|
import { HomeserverInstance } from "../utils/homeserver";
|
||||||
|
|
||||||
// A cypress plugin to add command to start & stop https://github.com/matrix-org/sliding-sync
|
// A cypress plugin to add command to start & stop https://github.com/matrix-org/sliding-sync
|
||||||
// SLIDING_SYNC_PROXY_TAG env used as the docker tag to use for `ghcr.io/matrix-org/sliding-sync-proxy` image.
|
// SLIDING_SYNC_PROXY_TAG env used as the docker tag to use for `ghcr.io/matrix-org/sliding-sync-proxy` image.
|
||||||
|
@ -35,7 +35,7 @@ const instances = new Map<string, ProxyInstance>();
|
||||||
|
|
||||||
const PG_PASSWORD = "p4S5w0rD";
|
const PG_PASSWORD = "p4S5w0rD";
|
||||||
|
|
||||||
async function proxyStart(dockerTag: string, synapse: SynapseInstance): Promise<ProxyInstance> {
|
async function proxyStart(dockerTag: string, homeserver: HomeserverInstance): Promise<ProxyInstance> {
|
||||||
console.log(new Date(), "Starting sliding sync proxy...");
|
console.log(new Date(), "Starting sliding sync proxy...");
|
||||||
|
|
||||||
const postgresId = await dockerRun({
|
const postgresId = await dockerRun({
|
||||||
|
@ -45,7 +45,7 @@ async function proxyStart(dockerTag: string, synapse: SynapseInstance): Promise<
|
||||||
});
|
});
|
||||||
|
|
||||||
const postgresIp = await dockerIp({ containerId: postgresId });
|
const postgresIp = await dockerIp({ containerId: postgresId });
|
||||||
const synapseIp = await dockerIp({ containerId: synapse.synapseId });
|
const homeserverIp = await dockerIp({ containerId: homeserver.serverId });
|
||||||
console.log(new Date(), "postgres container up");
|
console.log(new Date(), "postgres container up");
|
||||||
|
|
||||||
const waitTimeMillis = 30000;
|
const waitTimeMillis = 30000;
|
||||||
|
@ -81,7 +81,7 @@ async function proxyStart(dockerTag: string, synapse: SynapseInstance): Promise<
|
||||||
"-e",
|
"-e",
|
||||||
"SYNCV3_SECRET=bwahahaha",
|
"SYNCV3_SECRET=bwahahaha",
|
||||||
"-e",
|
"-e",
|
||||||
`SYNCV3_SERVER=http://${synapseIp}:8008`,
|
`SYNCV3_SERVER=http://${homeserverIp}:8008`,
|
||||||
"-e",
|
"-e",
|
||||||
`SYNCV3_DB=user=postgres dbname=postgres password=${PG_PASSWORD} host=${postgresIp} sslmode=disable`,
|
`SYNCV3_DB=user=postgres dbname=postgres password=${PG_PASSWORD} host=${postgresIp} sslmode=disable`,
|
||||||
],
|
],
|
||||||
|
|
|
@ -25,29 +25,18 @@ import PluginEvents = Cypress.PluginEvents;
|
||||||
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
||||||
import { getFreePort } from "../utils/port";
|
import { getFreePort } from "../utils/port";
|
||||||
import { dockerExec, dockerLogs, dockerRun, dockerStop } from "../docker";
|
import { dockerExec, dockerLogs, dockerRun, dockerStop } from "../docker";
|
||||||
|
import { HomeserverConfig, HomeserverInstance } from "../utils/homeserver";
|
||||||
|
|
||||||
// A cypress plugins to add command to start & stop synapses in
|
// A cypress plugins to add command to start & stop synapses in
|
||||||
// docker with preset templates.
|
// docker with preset templates.
|
||||||
|
|
||||||
interface SynapseConfig {
|
const synapses = new Map<string, HomeserverInstance>();
|
||||||
configDir: string;
|
|
||||||
registrationSecret: string;
|
|
||||||
// Synapse must be configured with its public_baseurl so we have to allocate a port & url at this stage
|
|
||||||
baseUrl: string;
|
|
||||||
port: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SynapseInstance extends SynapseConfig {
|
|
||||||
synapseId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const synapses = new Map<string, SynapseInstance>();
|
|
||||||
|
|
||||||
function randB64Bytes(numBytes: number): string {
|
function randB64Bytes(numBytes: number): string {
|
||||||
return crypto.randomBytes(numBytes).toString("base64").replace(/=*$/, "");
|
return crypto.randomBytes(numBytes).toString("base64").replace(/=*$/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cfgDirFromTemplate(template: string): Promise<SynapseConfig> {
|
async function cfgDirFromTemplate(template: string): Promise<HomeserverConfig> {
|
||||||
const templateDir = path.join(__dirname, "templates", template);
|
const templateDir = path.join(__dirname, "templates", template);
|
||||||
|
|
||||||
const stats = await fse.stat(templateDir);
|
const stats = await fse.stat(templateDir);
|
||||||
|
@ -94,7 +83,7 @@ async function cfgDirFromTemplate(template: string): Promise<SynapseConfig> {
|
||||||
// Start a synapse instance: the template must be the name of
|
// Start a synapse instance: the template must be the name of
|
||||||
// one of the templates in the cypress/plugins/synapsedocker/templates
|
// one of the templates in the cypress/plugins/synapsedocker/templates
|
||||||
// directory
|
// directory
|
||||||
async function synapseStart(template: string): Promise<SynapseInstance> {
|
async function synapseStart(template: string): Promise<HomeserverInstance> {
|
||||||
const synCfg = await cfgDirFromTemplate(template);
|
const synCfg = await cfgDirFromTemplate(template);
|
||||||
|
|
||||||
console.log(`Starting synapse with config dir ${synCfg.configDir}...`);
|
console.log(`Starting synapse with config dir ${synCfg.configDir}...`);
|
||||||
|
@ -103,7 +92,7 @@ async function synapseStart(template: string): Promise<SynapseInstance> {
|
||||||
image: "matrixdotorg/synapse:develop",
|
image: "matrixdotorg/synapse:develop",
|
||||||
containerName: `react-sdk-cypress-synapse`,
|
containerName: `react-sdk-cypress-synapse`,
|
||||||
params: ["--rm", "-v", `${synCfg.configDir}:/data`, "-p", `${synCfg.port}:8008/tcp`],
|
params: ["--rm", "-v", `${synCfg.configDir}:/data`, "-p", `${synCfg.port}:8008/tcp`],
|
||||||
cmd: "run",
|
cmd: ["run"],
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`);
|
console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`);
|
||||||
|
@ -125,7 +114,7 @@ async function synapseStart(template: string): Promise<SynapseInstance> {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const synapse: SynapseInstance = { synapseId, ...synCfg };
|
const synapse: HomeserverInstance = { serverId: synapseId, ...synCfg };
|
||||||
synapses.set(synapseId, synapse);
|
synapses.set(synapseId, synapse);
|
||||||
return synapse;
|
return synapse;
|
||||||
}
|
}
|
||||||
|
|
28
cypress/plugins/utils/homeserver.ts
Normal file
28
cypress/plugins/utils/homeserver.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
export interface HomeserverConfig {
|
||||||
|
configDir: string;
|
||||||
|
registrationSecret: string;
|
||||||
|
baseUrl: string;
|
||||||
|
port: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HomeserverInstance extends HomeserverConfig {
|
||||||
|
serverId: string;
|
||||||
|
}
|
|
@ -17,8 +17,8 @@ limitations under the License.
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import type { ISendEventResponse, MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
import type { ISendEventResponse, MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
||||||
import { SynapseInstance } from "../plugins/synapsedocker";
|
import { HomeserverInstance } from "../plugins/utils/homeserver";
|
||||||
import { Credentials } from "./synapse";
|
import { Credentials } from "./homeserver";
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
interface CreateBotOpts {
|
interface CreateBotOpts {
|
||||||
|
@ -61,19 +61,19 @@ declare global {
|
||||||
interface Chainable {
|
interface Chainable {
|
||||||
/**
|
/**
|
||||||
* Returns a new Bot instance
|
* Returns a new Bot instance
|
||||||
* @param synapse the instance on which to register the bot user
|
* @param homeserver the instance on which to register the bot user
|
||||||
* @param opts create bot options
|
* @param opts create bot options
|
||||||
*/
|
*/
|
||||||
getBot(synapse: SynapseInstance, opts: CreateBotOpts): Chainable<CypressBot>;
|
getBot(homeserver: HomeserverInstance, opts: CreateBotOpts): Chainable<CypressBot>;
|
||||||
/**
|
/**
|
||||||
* Returns a new Bot instance logged in as an existing user
|
* Returns a new Bot instance logged in as an existing user
|
||||||
* @param synapse the instance on which to register the bot user
|
* @param homeserver the instance on which to register the bot user
|
||||||
* @param username the username for the bot to log in with
|
* @param username the username for the bot to log in with
|
||||||
* @param password the password for the bot to log in with
|
* @param password the password for the bot to log in with
|
||||||
* @param opts create bot options
|
* @param opts create bot options
|
||||||
*/
|
*/
|
||||||
loginBot(
|
loginBot(
|
||||||
synapse: SynapseInstance,
|
homeserver: HomeserverInstance,
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
opts: CreateBotOpts,
|
opts: CreateBotOpts,
|
||||||
|
@ -102,7 +102,7 @@ declare global {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupBotClient(
|
function setupBotClient(
|
||||||
synapse: SynapseInstance,
|
homeserver: HomeserverInstance,
|
||||||
credentials: Credentials,
|
credentials: Credentials,
|
||||||
opts: CreateBotOpts,
|
opts: CreateBotOpts,
|
||||||
): Chainable<MatrixClient> {
|
): Chainable<MatrixClient> {
|
||||||
|
@ -119,7 +119,7 @@ function setupBotClient(
|
||||||
};
|
};
|
||||||
|
|
||||||
const cli = new win.matrixcs.MatrixClient({
|
const cli = new win.matrixcs.MatrixClient({
|
||||||
baseUrl: synapse.baseUrl,
|
baseUrl: homeserver.baseUrl,
|
||||||
userId: credentials.userId,
|
userId: credentials.userId,
|
||||||
deviceId: credentials.deviceId,
|
deviceId: credentials.deviceId,
|
||||||
accessToken: credentials.accessToken,
|
accessToken: credentials.accessToken,
|
||||||
|
@ -160,15 +160,15 @@ function setupBotClient(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Cypress.Commands.add("getBot", (synapse: SynapseInstance, opts: CreateBotOpts): Chainable<CypressBot> => {
|
Cypress.Commands.add("getBot", (homeserver: HomeserverInstance, opts: CreateBotOpts): Chainable<CypressBot> => {
|
||||||
opts = Object.assign({}, defaultCreateBotOptions, opts);
|
opts = Object.assign({}, defaultCreateBotOptions, opts);
|
||||||
const username = Cypress._.uniqueId(opts.userIdPrefix);
|
const username = Cypress._.uniqueId(opts.userIdPrefix);
|
||||||
const password = Cypress._.uniqueId("password_");
|
const password = Cypress._.uniqueId("password_");
|
||||||
return cy
|
return cy
|
||||||
.registerUser(synapse, username, password, opts.displayName)
|
.registerUser(homeserver, username, password, opts.displayName)
|
||||||
.then((credentials) => {
|
.then((credentials) => {
|
||||||
cy.log(`Registered bot user ${username} with displayname ${opts.displayName}`);
|
cy.log(`Registered bot user ${username} with displayname ${opts.displayName}`);
|
||||||
return setupBotClient(synapse, credentials, opts);
|
return setupBotClient(homeserver, credentials, opts);
|
||||||
})
|
})
|
||||||
.then((client): Chainable<CypressBot> => {
|
.then((client): Chainable<CypressBot> => {
|
||||||
Object.assign(client, { __cypress_password: password });
|
Object.assign(client, { __cypress_password: password });
|
||||||
|
@ -178,10 +178,15 @@ Cypress.Commands.add("getBot", (synapse: SynapseInstance, opts: CreateBotOpts):
|
||||||
|
|
||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
"loginBot",
|
"loginBot",
|
||||||
(synapse: SynapseInstance, username: string, password: string, opts: CreateBotOpts): Chainable<MatrixClient> => {
|
(
|
||||||
|
homeserver: HomeserverInstance,
|
||||||
|
username: string,
|
||||||
|
password: string,
|
||||||
|
opts: CreateBotOpts,
|
||||||
|
): Chainable<MatrixClient> => {
|
||||||
opts = Object.assign({}, defaultCreateBotOptions, { bootstrapCrossSigning: false }, opts);
|
opts = Object.assign({}, defaultCreateBotOptions, { bootstrapCrossSigning: false }, opts);
|
||||||
return cy.loginUser(synapse, username, password).then((credentials) => {
|
return cy.loginUser(homeserver, username, password).then((credentials) => {
|
||||||
return setupBotClient(synapse, credentials, opts);
|
return setupBotClient(homeserver, credentials, opts);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
||||||
import "@percy/cypress";
|
import "@percy/cypress";
|
||||||
import "cypress-real-events";
|
import "cypress-real-events";
|
||||||
|
|
||||||
import "./synapse";
|
import "./homeserver";
|
||||||
import "./login";
|
import "./login";
|
||||||
import "./labs";
|
import "./labs";
|
||||||
import "./client";
|
import "./client";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -20,34 +20,34 @@ import * as crypto from "crypto";
|
||||||
|
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
import AUTWindow = Cypress.AUTWindow;
|
import AUTWindow = Cypress.AUTWindow;
|
||||||
import { SynapseInstance } from "../plugins/synapsedocker";
|
import { HomeserverInstance } from "../plugins/utils/homeserver";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
namespace Cypress {
|
namespace Cypress {
|
||||||
interface Chainable {
|
interface Chainable {
|
||||||
/**
|
/**
|
||||||
* Start a synapse instance with a given config template.
|
* Start a homeserver instance with a given config template.
|
||||||
* @param template path to template within cypress/plugins/synapsedocker/template/ directory.
|
* @param template path to template within cypress/plugins/{homeserver}docker/template/ directory.
|
||||||
*/
|
*/
|
||||||
startSynapse(template: string): Chainable<SynapseInstance>;
|
startHomeserver(template: string): Chainable<HomeserverInstance>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom command wrapping task:synapseStop whilst preventing uncaught exceptions
|
* Custom command wrapping task:{homeserver}Stop whilst preventing uncaught exceptions
|
||||||
* for if Synapse stopping races with the app's background sync loop.
|
* for if Homeserver stopping races with the app's background sync loop.
|
||||||
* @param synapse the synapse instance returned by startSynapse
|
* @param homeserver the homeserver instance returned by start{Homeserver}
|
||||||
*/
|
*/
|
||||||
stopSynapse(synapse: SynapseInstance): Chainable<AUTWindow>;
|
stopHomeserver(homeserver: HomeserverInstance): Chainable<AUTWindow>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a user on the given Synapse using the shared registration secret.
|
* Register a user on the given Homeserver using the shared registration secret.
|
||||||
* @param synapse the synapse instance returned by startSynapse
|
* @param homeserver the homeserver instance returned by start{Homeserver}
|
||||||
* @param username the username of the user to register
|
* @param username the username of the user to register
|
||||||
* @param password the password of the user to register
|
* @param password the password of the user to register
|
||||||
* @param displayName optional display name to set on the newly registered user
|
* @param displayName optional display name to set on the newly registered user
|
||||||
*/
|
*/
|
||||||
registerUser(
|
registerUser(
|
||||||
synapse: SynapseInstance,
|
homeserver: HomeserverInstance,
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
displayName?: string,
|
displayName?: string,
|
||||||
|
@ -56,16 +56,18 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startSynapse(template: string): Chainable<SynapseInstance> {
|
function startHomeserver(template: string): Chainable<HomeserverInstance> {
|
||||||
return cy.task<SynapseInstance>("synapseStart", template);
|
const homeserverName = Cypress.env("HOMESERVER");
|
||||||
|
return cy.task<HomeserverInstance>(homeserverName + "Start", template);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopSynapse(synapse?: SynapseInstance): Chainable<AUTWindow> {
|
function stopHomeserver(homeserver?: HomeserverInstance): Chainable<AUTWindow> {
|
||||||
if (!synapse) return;
|
if (!homeserver) return;
|
||||||
// Navigate away from app to stop the background network requests which will race with Synapse shutting down
|
// Navigate away from app to stop the background network requests which will race with Homeserver shutting down
|
||||||
return cy.window({ log: false }).then((win) => {
|
return cy.window({ log: false }).then((win) => {
|
||||||
win.location.href = "about:blank";
|
win.location.href = "about:blank";
|
||||||
cy.task("synapseStop", synapse.synapseId);
|
const homeserverName = Cypress.env("HOMESERVER");
|
||||||
|
cy.task(homeserverName + "Stop", homeserver.serverId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +79,12 @@ export interface Credentials {
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerUser(
|
function registerUser(
|
||||||
synapse: SynapseInstance,
|
homeserver: HomeserverInstance,
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
displayName?: string,
|
displayName?: string,
|
||||||
): Chainable<Credentials> {
|
): Chainable<Credentials> {
|
||||||
const url = `${synapse.baseUrl}/_synapse/admin/v1/register`;
|
const url = `${homeserver.baseUrl}/_synapse/admin/v1/register`;
|
||||||
return cy
|
return cy
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// get a nonce
|
// get a nonce
|
||||||
|
@ -91,7 +93,7 @@ function registerUser(
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const { nonce } = response.body;
|
const { nonce } = response.body;
|
||||||
const mac = crypto
|
const mac = crypto
|
||||||
.createHmac("sha1", synapse.registrationSecret)
|
.createHmac("sha1", homeserver.registrationSecret)
|
||||||
.update(`${nonce}\0${username}\0${password}\0notadmin`)
|
.update(`${nonce}\0${username}\0${password}\0notadmin`)
|
||||||
.digest("hex");
|
.digest("hex");
|
||||||
|
|
||||||
|
@ -121,6 +123,6 @@ function registerUser(
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Cypress.Commands.add("startSynapse", startSynapse);
|
Cypress.Commands.add("startHomeserver", startHomeserver);
|
||||||
Cypress.Commands.add("stopSynapse", stopSynapse);
|
Cypress.Commands.add("stopHomeserver", stopHomeserver);
|
||||||
Cypress.Commands.add("registerUser", registerUser);
|
Cypress.Commands.add("registerUser", registerUser);
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
import { SynapseInstance } from "../plugins/synapsedocker";
|
import { HomeserverInstance } from "../plugins/utils/homeserver";
|
||||||
|
|
||||||
export interface UserCredentials {
|
export interface UserCredentials {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
|
@ -41,7 +41,7 @@ declare global {
|
||||||
* useed.
|
* useed.
|
||||||
*/
|
*/
|
||||||
initTestUser(
|
initTestUser(
|
||||||
synapse: SynapseInstance,
|
homeserver: HomeserverInstance,
|
||||||
displayName: string,
|
displayName: string,
|
||||||
prelaunchFn?: () => void,
|
prelaunchFn?: () => void,
|
||||||
userIdPrefix?: string,
|
userIdPrefix?: string,
|
||||||
|
@ -52,7 +52,7 @@ declare global {
|
||||||
* @param username login username
|
* @param username login username
|
||||||
* @param password login password
|
* @param password login password
|
||||||
*/
|
*/
|
||||||
loginUser(synapse: SynapseInstance, username: string, password: string): Chainable<UserCredentials>;
|
loginUser(synapse: HomeserverInstance, username: string, password: string): Chainable<UserCredentials>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,8 +60,8 @@ declare global {
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
"loginUser",
|
"loginUser",
|
||||||
(synapse: SynapseInstance, username: string, password: string): Chainable<UserCredentials> => {
|
(homeserver: HomeserverInstance, username: string, password: string): Chainable<UserCredentials> => {
|
||||||
const url = `${synapse.baseUrl}/_matrix/client/r0/login`;
|
const url = `${homeserver.baseUrl}/_matrix/client/r0/login`;
|
||||||
return cy
|
return cy
|
||||||
.request<{
|
.request<{
|
||||||
access_token: string;
|
access_token: string;
|
||||||
|
@ -95,7 +95,7 @@ Cypress.Commands.add(
|
||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
"initTestUser",
|
"initTestUser",
|
||||||
(
|
(
|
||||||
synapse: SynapseInstance,
|
homeserver: HomeserverInstance,
|
||||||
displayName: string,
|
displayName: string,
|
||||||
prelaunchFn?: () => void,
|
prelaunchFn?: () => void,
|
||||||
userIdPrefix = "user_",
|
userIdPrefix = "user_",
|
||||||
|
@ -112,15 +112,15 @@ Cypress.Commands.add(
|
||||||
const username = Cypress._.uniqueId(userIdPrefix);
|
const username = Cypress._.uniqueId(userIdPrefix);
|
||||||
const password = Cypress._.uniqueId("password_");
|
const password = Cypress._.uniqueId("password_");
|
||||||
return cy
|
return cy
|
||||||
.registerUser(synapse, username, password, displayName)
|
.registerUser(homeserver, username, password, displayName)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return cy.loginUser(synapse, username, password);
|
return cy.loginUser(homeserver, username, password);
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
cy.log(`Registered test user ${username} with displayname ${displayName}`);
|
cy.log(`Registered test user ${username} with displayname ${displayName}`);
|
||||||
cy.window({ log: false }).then((win) => {
|
cy.window({ log: false }).then((win) => {
|
||||||
// Seed the localStorage with the required credentials
|
// Seed the localStorage with the required credentials
|
||||||
win.localStorage.setItem("mx_hs_url", synapse.baseUrl);
|
win.localStorage.setItem("mx_hs_url", homeserver.baseUrl);
|
||||||
win.localStorage.setItem("mx_user_id", response.userId);
|
win.localStorage.setItem("mx_user_id", response.userId);
|
||||||
win.localStorage.setItem("mx_access_token", response.accessToken);
|
win.localStorage.setItem("mx_access_token", response.accessToken);
|
||||||
win.localStorage.setItem("mx_device_id", response.deviceId);
|
win.localStorage.setItem("mx_device_id", response.deviceId);
|
||||||
|
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
||||||
import Chainable = Cypress.Chainable;
|
import Chainable = Cypress.Chainable;
|
||||||
import AUTWindow = Cypress.AUTWindow;
|
import AUTWindow = Cypress.AUTWindow;
|
||||||
import { ProxyInstance } from "../plugins/sliding-sync";
|
import { ProxyInstance } from "../plugins/sliding-sync";
|
||||||
import { SynapseInstance } from "../plugins/synapsedocker";
|
import { HomeserverInstance } from "../plugins/utils/homeserver";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
@ -27,9 +27,9 @@ declare global {
|
||||||
interface Chainable {
|
interface Chainable {
|
||||||
/**
|
/**
|
||||||
* Start a sliding sync proxy instance.
|
* Start a sliding sync proxy instance.
|
||||||
* @param synapse the synapse instance returned by startSynapse
|
* @param homeserver the homeserver instance returned by startHomeserver
|
||||||
*/
|
*/
|
||||||
startProxy(synapse: SynapseInstance): Chainable<ProxyInstance>;
|
startProxy(homeserver: HomeserverInstance): Chainable<ProxyInstance>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom command wrapping task:proxyStop whilst preventing uncaught exceptions
|
* Custom command wrapping task:proxyStop whilst preventing uncaught exceptions
|
||||||
|
@ -41,13 +41,13 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startProxy(synapse: SynapseInstance): Chainable<ProxyInstance> {
|
function startProxy(homeserver: HomeserverInstance): Chainable<ProxyInstance> {
|
||||||
return cy.task<ProxyInstance>("proxyStart", synapse);
|
return cy.task<ProxyInstance>("proxyStart", homeserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopProxy(proxy?: ProxyInstance): Chainable<AUTWindow> {
|
function stopProxy(proxy?: ProxyInstance): Chainable<AUTWindow> {
|
||||||
if (!proxy) return;
|
if (!proxy) return;
|
||||||
// Navigate away from app to stop the background network requests which will race with Synapse shutting down
|
// Navigate away from app to stop the background network requests which will race with Homeserver shutting down
|
||||||
return cy.window({ log: false }).then((win) => {
|
return cy.window({ log: false }).then((win) => {
|
||||||
win.location.href = "about:blank";
|
win.location.href = "about:blank";
|
||||||
cy.task("proxyStop", proxy);
|
cy.task("proxyStop", proxy);
|
||||||
|
|
|
@ -21,7 +21,7 @@ be tested. When running Cypress tests yourself, the standard `yarn start` from t
|
||||||
element-web project is fine: leave it running it a different terminal as you would
|
element-web project is fine: leave it running it a different terminal as you would
|
||||||
when developing.
|
when developing.
|
||||||
|
|
||||||
The tests use Docker to launch Synapse instances to test against, so you'll also
|
The tests use Docker to launch Homeserver (Synapse or Dendrite) instances to test against, so you'll also
|
||||||
need to have Docker installed and working in order to run the Cypress tests.
|
need to have Docker installed and working in order to run the Cypress tests.
|
||||||
|
|
||||||
There are a few different ways to run the tests yourself. The simplest is to run:
|
There are a few different ways to run the tests yourself. The simplest is to run:
|
||||||
|
@ -58,10 +58,10 @@ Synapse can be launched with different configurations in order to test element
|
||||||
in different configurations. `cypress/plugins/synapsedocker/templates` contains
|
in different configurations. `cypress/plugins/synapsedocker/templates` contains
|
||||||
template configuration files for each different configuration.
|
template configuration files for each different configuration.
|
||||||
|
|
||||||
Each test suite can then launch whatever Synapse instances it needs it whatever
|
Each test suite can then launch whatever Synapse instances it needs in whatever
|
||||||
configurations.
|
configurations.
|
||||||
|
|
||||||
Note that although tests should stop the Synapse instances after running and the
|
Note that although tests should stop the Homeserver instances after running and the
|
||||||
plugin also stop any remaining instances after all tests have run, it is possible
|
plugin also stop any remaining instances after all tests have run, it is possible
|
||||||
to be left with some stray containers if, for example, you terminate a test such
|
to be left with some stray containers if, for example, you terminate a test such
|
||||||
that the `after()` does not run and also exit Cypress uncleanly. All the containers
|
that the `after()` does not run and also exit Cypress uncleanly. All the containers
|
||||||
|
@ -82,29 +82,29 @@ a read.
|
||||||
### Getting a Synapse
|
### Getting a Synapse
|
||||||
|
|
||||||
The key difference is in starting Synapse instances. Tests use this plugin via
|
The key difference is in starting Synapse instances. Tests use this plugin via
|
||||||
`cy.startSynapse()` to provide a Synapse instance to log into:
|
`cy.startHomeserver()` to provide a Homeserver instance to log into:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
cy.startSynapse("consent").then((result) => {
|
cy.startHomeserver("consent").then((result) => {
|
||||||
synapse = result;
|
homeserver = result;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
This returns an object with information about the Synapse instance, including what port
|
This returns an object with information about the Homeserver instance, including what port
|
||||||
it was started on and the ID that needs to be passed to shut it down again. It also
|
it was started on and the ID that needs to be passed to shut it down again. It also
|
||||||
returns the registration shared secret (`registrationSecret`) that can be used to
|
returns the registration shared secret (`registrationSecret`) that can be used to
|
||||||
register users via the REST API. The Synapse has been ensured ready to go by awaiting
|
register users via the REST API. The Homeserver has been ensured ready to go by awaiting
|
||||||
its internal health-check.
|
its internal health-check.
|
||||||
|
|
||||||
Synapse instances should be reasonably cheap to start (you may see the first one take a
|
Homeserver instances should be reasonably cheap to start (you may see the first one take a
|
||||||
while as it pulls the Docker image), so it's generally expected that tests will start a
|
while as it pulls the Docker image), so it's generally expected that tests will start a
|
||||||
Synapse instance for each test suite, i.e. in `before()`, and then tear it down in `after()`.
|
Homeserver instance for each test suite, i.e. in `before()`, and then tear it down in `after()`.
|
||||||
|
|
||||||
To later destroy your Synapse you should call `stopSynapse`, passing the SynapseInstance
|
To later destroy your Homeserver you should call `stopHomeserver`, passing the HomeserverInstance
|
||||||
object you received when starting it.
|
object you received when starting it.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
cy.stopSynapse(synapse);
|
cy.stopHomeserver(homeserver);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Synapse Config Templates
|
### Synapse Config Templates
|
||||||
|
@ -131,10 +131,10 @@ in a template can be referenced in the config as `/data/foo.html`.
|
||||||
There exists a basic utility to start the app with a random user already logged in:
|
There exists a basic utility to start the app with a random user already logged in:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
cy.initTestUser(synapse, "Jeff");
|
cy.initTestUser(homeserver, "Jeff");
|
||||||
```
|
```
|
||||||
|
|
||||||
It takes the SynapseInstance you received from `startSynapse` and a display name for your test user.
|
It takes the HomeserverInstance you received from `startHomeserver` and a display name for your test user.
|
||||||
This custom command will register a random userId using the registrationSecret with a random password
|
This custom command will register a random userId using the registrationSecret with a random password
|
||||||
and the given display name. The returned Chainable will contain details about the credentials for if
|
and the given display name. The returned Chainable will contain details about the credentials for if
|
||||||
they are needed for User-Interactive Auth or similar but localStorage will already be seeded with them
|
they are needed for User-Interactive Auth or similar but localStorage will already be seeded with them
|
||||||
|
@ -147,11 +147,11 @@ but the signature can be maintained for simpler maintenance.
|
||||||
|
|
||||||
Many tests will also want to start with the client in a room, ready to send & receive messages. Best
|
Many tests will also want to start with the client in a room, ready to send & receive messages. Best
|
||||||
way to do this may be to get an access token for the user and use this to create a room with the REST
|
way to do this may be to get an access token for the user and use this to create a room with the REST
|
||||||
API before logging the user in. You can make use of `cy.getBot(synapse)` and `cy.getClient()` to do this.
|
API before logging the user in. You can make use of `cy.getBot(homeserver)` and `cy.getClient()` to do this.
|
||||||
|
|
||||||
### Convenience APIs
|
### Convenience APIs
|
||||||
|
|
||||||
We should probably end up with convenience APIs that wrap the synapse creation, logging in and room
|
We should probably end up with convenience APIs that wrap the homeserver creation, logging in and room
|
||||||
creation that can be called to set up tests.
|
creation that can be called to set up tests.
|
||||||
|
|
||||||
### Using matrix-js-sdk
|
### Using matrix-js-sdk
|
||||||
|
|
Loading…
Reference in a new issue