Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge branch 'develop' into EventBubbleTile
Browse files Browse the repository at this point in the history
  • Loading branch information
luixxiul authored May 5, 2022
2 parents aaae517 + 1a0af54 commit 7c6c37d
Show file tree
Hide file tree
Showing 145 changed files with 2,928 additions and 2,177 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/upgrade_dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: Upgrade Dependencies
on:
workflow_dispatch: { }
jobs:
upgrade:
uses: matrix-org/matrix-js-sdk/.github/workflows/upgrade_dependencies.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[![npm](https://img.shields.io/npm/v/matrix-react-sdk)](https://www.npmjs.com/package/matrix-react-sdk)
![Tests](https://github.com/matrix-org/matrix-react-sdk/actions/workflows/tests.yml/badge.svg)
![Static Analysis](https://github.com/matrix-org/matrix-react-sdk/actions/workflows/static_analysis.yaml/badge.svg)
[![Weblate](https://translate.element.io/widgets/element-web/-/matrix-react-sdk/svg-badge.svg)](https://translate.element.io/engage/element-web/)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=matrix-react-sdk&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=matrix-react-sdk)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=matrix-react-sdk&metric=coverage)](https://sonarcloud.io/summary/new_code?id=matrix-react-sdk)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=matrix-react-sdk&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=matrix-react-sdk)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=matrix-react-sdk&metric=bugs)](https://sonarcloud.io/summary/new_code?id=matrix-react-sdk)

matrix-react-sdk
================

Expand Down
18 changes: 9 additions & 9 deletions cypress/integration/1-register/register.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,34 @@ limitations under the License.

/// <reference types="cypress" />

import { SynapseInstance } from "../../plugins/synapsedocker/index";
import { SynapseInstance } from "../../plugins/synapsedocker";

describe("Registration", () => {
let synapseId;
let synapsePort;
let synapse: SynapseInstance;

beforeEach(() => {
cy.task<SynapseInstance>("synapseStart", "consent").then(result => {
synapseId = result.synapseId;
synapsePort = result.port;
});
cy.visit("/#/register");
cy.startSynapse("consent").then(data => {
synapse = data;
});
});

afterEach(() => {
cy.task("synapseStop", synapseId);
cy.stopSynapse(synapse);
});

it("registers an account and lands on the home screen", () => {
cy.get(".mx_ServerPicker_change", { timeout: 15000 }).click();
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(`http://localhost:${synapsePort}`);
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
cy.get(".mx_ServerPickerDialog_continue").click();
// wait for the dialog to go away
cy.get('.mx_ServerPickerDialog').should('not.exist');

cy.get("#mx_RegistrationForm_username").type("alice");
cy.get("#mx_RegistrationForm_password").type("totally a great password");
cy.get("#mx_RegistrationForm_passwordConfirm").type("totally a great password");
cy.get(".mx_Login_submit").click();

cy.get(".mx_RegistrationEmailPromptDialog button.mx_Dialog_primary").click();
cy.get(".mx_InteractiveAuthEntryComponents_termsPolicy input").click();
cy.get(".mx_InteractiveAuthEntryComponents_termsSubmit").click();
Expand Down
57 changes: 57 additions & 0 deletions cypress/integration/2-login/login.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/// <reference types="cypress" />

import { SynapseInstance } from "../../plugins/synapsedocker";

describe("Login", () => {
let synapse: SynapseInstance;

beforeEach(() => {
cy.visit("/#/login");
cy.startSynapse("consent").then(data => {
synapse = data;
});
});

afterEach(() => {
cy.stopSynapse(synapse);
});

describe("m.login.password", () => {
const username = "user1234";
const password = "p4s5W0rD";

beforeEach(() => {
cy.registerUser(synapse, username, password);
});

it("logs in with an existing account and lands on the home screen", () => {
cy.get(".mx_ServerPicker_change", { timeout: 15000 }).click();
cy.get(".mx_ServerPickerDialog_otherHomeserver").type(synapse.baseUrl);
cy.get(".mx_ServerPickerDialog_continue").click();
// wait for the dialog to go away
cy.get('.mx_ServerPickerDialog').should('not.exist');

cy.get("#mx_LoginForm_username").type(username);
cy.get("#mx_LoginForm_password").type(password);
cy.get(".mx_Login_submit").click();

cy.url().should('contain', '/#/home');
});
});
});
45 changes: 45 additions & 0 deletions cypress/integration/3-user-menu/user-menu.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/// <reference types="cypress" />

import { SynapseInstance } from "../../plugins/synapsedocker";
import type { UserCredentials } from "../../support/login";

describe("UserMenu", () => {
let synapse: SynapseInstance;
let user: UserCredentials;

beforeEach(() => {
cy.startSynapse("consent").then(data => {
synapse = data;

cy.initTestUser(synapse, "Jeff").then(credentials => {
user = credentials;
});
});
});

afterEach(() => {
cy.stopSynapse(synapse);
});

it("should contain our name & userId", () => {
cy.get('[aria-label="User menu"]', { timeout: 15000 }).click();
cy.get(".mx_UserMenu_contextMenu_displayName").should("contain", "Jeff");
cy.get(".mx_UserMenu_contextMenu_userId").should("contain", user.userId);
});
});
9 changes: 7 additions & 2 deletions cypress/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ limitations under the License.

/// <reference types="cypress" />

import { synapseDocker } from "./synapsedocker/index";
import { synapseDocker } from "./synapsedocker";
import PluginEvents = Cypress.PluginEvents;
import PluginConfigOptions = Cypress.PluginConfigOptions;

export default function(on, config) {
/**
* @type {Cypress.PluginConfig}
*/
export default function(on: PluginEvents, config: PluginConfigOptions) {
synapseDocker(on, config);
}
69 changes: 46 additions & 23 deletions cypress/plugins/synapsedocker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,24 @@ import * as os from "os";
import * as crypto from "crypto";
import * as childProcess from "child_process";
import * as fse from "fs-extra";
import * as net from "net";

import PluginEvents = Cypress.PluginEvents;
import PluginConfigOptions = Cypress.PluginConfigOptions;

// A cypress plugins to add command to start & stop synapses in
// docker with preset templates.

interface SynapseConfig {
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;
port: number;
}

const synapses = new Map<string, SynapseInstance>();
Expand All @@ -41,6 +47,16 @@ function randB64Bytes(numBytes: number): string {
return crypto.randomBytes(numBytes).toString("base64").replace(/=*$/, "");
}

async function getFreePort(): Promise<number> {
return new Promise<number>(resolve => {
const srv = net.createServer();
srv.listen(0, () => {
const port = (<net.AddressInfo>srv.address()).port;
srv.close(() => resolve(port));
});
});
}

async function cfgDirFromTemplate(template: string): Promise<SynapseConfig> {
const templateDir = path.join(__dirname, "templates", template);

Expand All @@ -61,12 +77,16 @@ async function cfgDirFromTemplate(template: string): Promise<SynapseConfig> {
const macaroonSecret = randB64Bytes(16);
const formSecret = randB64Bytes(16);

// now copy homeserver.yaml, applying sustitutions
const port = await getFreePort();
const baseUrl = `http://localhost:${port}`;

// now copy homeserver.yaml, applying substitutions
console.log(`Gen ${path.join(templateDir, "homeserver.yaml")}`);
let hsYaml = await fse.readFile(path.join(templateDir, "homeserver.yaml"), "utf8");
hsYaml = hsYaml.replace(/{{REGISTRATION_SECRET}}/g, registrationSecret);
hsYaml = hsYaml.replace(/{{MACAROON_SECRET_KEY}}/g, macaroonSecret);
hsYaml = hsYaml.replace(/{{FORM_SECRET}}/g, formSecret);
hsYaml = hsYaml.replace(/{{PUBLIC_BASEURL}}/g, baseUrl);
await fse.writeFile(path.join(tempDir, "homeserver.yaml"), hsYaml);

// now generate a signing key (we could use synapse's config generation for
Expand All @@ -77,6 +97,8 @@ async function cfgDirFromTemplate(template: string): Promise<SynapseConfig> {
await fse.writeFile(path.join(tempDir, "localhost.signing.key"), `ed25519 x ${signingKey}`);

return {
port,
baseUrl,
configDir: tempDir,
registrationSecret,
};
Expand All @@ -98,7 +120,7 @@ async function synapseStart(template: string): Promise<SynapseInstance> {
"--name", containerName,
"-d",
"-v", `${synCfg.configDir}:/data`,
"-p", "8008/tcp",
"-p", `${synCfg.port}:8008/tcp`,
"matrixdotorg/synapse:develop",
"run",
], (err, stdout) => {
Expand All @@ -107,30 +129,31 @@ async function synapseStart(template: string): Promise<SynapseInstance> {
});
});

// Get the port that docker allocated: specifying only one
// port above leaves docker to just grab a free one, although
// in hindsight we need to put the port in public_baseurl in the
// config really, so this will probably need changing to use a fixed
// / configured port.
const port = await new Promise<number>((resolve, reject) => {
childProcess.execFile('docker', [
"port", synapseId, "8008",
synapses.set(synapseId, { synapseId, ...synCfg });

console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`);

// Await Synapse healthcheck
await new Promise<void>((resolve, reject) => {
childProcess.execFile("docker", [
"exec", synapseId,
"curl",
"--connect-timeout", "30",
"--retry", "30",
"--retry-delay", "1",
"--retry-all-errors",
"--silent",
"http://localhost:8008/health",
], { encoding: 'utf8' }, (err, stdout) => {
if (err) reject(err);
resolve(Number(stdout.trim().split(":")[1]));
else resolve();
});
});

synapses.set(synapseId, Object.assign({
port,
synapseId,
}, synCfg));

console.log(`Started synapse with id ${synapseId} on port ${port}.`);
return synapses.get(synapseId);
}

async function synapseStop(id) {
async function synapseStop(id: string): Promise<void> {
const synCfg = synapses.get(id);

if (!synCfg) throw new Error("Unknown synapse ID");
Expand Down Expand Up @@ -186,18 +209,18 @@ async function synapseStop(id) {
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
export function synapseDocker(on, config) {
export function synapseDocker(on: PluginEvents, config: PluginConfigOptions) {
on("task", {
synapseStart, synapseStop,
synapseStart,
synapseStop,
});

on("after:spec", async (spec) => {
// Cleans up any remaining synapse instances after a spec run
// This is on the theory that we should avoid re-using synapse
// 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 synapses, we could inadvertantly
// test. If we accidentally re-use synapses, we could inadvertently
// make our tests depend on each other.
for (const synId of synapses.keys()) {
console.warn(`Cleaning up synapse ID ${synId} after ${spec.name}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
server_name: "localhost"
pid_file: /data/homeserver.pid
public_baseurl: http://localhost:5005/
public_baseurl: "{{PUBLIC_BASEURL}}"
listeners:
- port: 8008
tls: false
Expand Down
23 changes: 20 additions & 3 deletions cypress/support/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
// Empty file to prevent cypress from recreating a helpful example
// file on every run (their example file doesn't use semicolons and
// so fails our lint rules).
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/// <reference types="cypress" />

import "./synapse";
import "./login";
Loading

0 comments on commit 7c6c37d

Please sign in to comment.