mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-22 19:14:52 +01:00
Merge pull request #1134 from vector-im/invite/implement-invite-command
Invite - PR [1/2] - Add command /invite to message composer
This commit is contained in:
commit
0cad1e5048
2
.github/workflows/codechecks.js.yml
vendored
2
.github/workflows/codechecks.js.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [18.1.0]
|
||||
|
||||
steps:
|
||||
- name: Checkout source
|
||||
|
@ -45,6 +45,7 @@
|
||||
"escodegen": "^2.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"fake-indexeddb": "^3.1.2",
|
||||
"fs-extra": "^11.1.1",
|
||||
"impunity": "^1.0.9",
|
||||
"mdn-polyfills": "^5.20.0",
|
||||
"merge-options": "^3.0.4",
|
||||
|
@ -14,15 +14,13 @@ 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 fse from "fs-extra";
|
||||
|
||||
import {dockerRun, dockerStop } from "../docker";
|
||||
|
||||
// A cypress plugins to add command to start & stop dex instances
|
||||
// A plugin that adds command to start & stop dex instances
|
||||
|
||||
interface DexConfig {
|
||||
configDir: string;
|
||||
|
@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import * as os from "os";
|
||||
import * as childProcess from "child_process";
|
||||
import * as fse from "fs-extra";
|
||||
@ -36,7 +34,8 @@ export function dockerRun(args: {
|
||||
}
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
childProcess.execFile('docker', [
|
||||
childProcess.execFile('sudo', [
|
||||
"docker",
|
||||
"run",
|
||||
"--name", args.containerName,
|
||||
"-d",
|
||||
@ -57,7 +56,8 @@ export function dockerExec(args: {
|
||||
params: string[];
|
||||
}): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile("docker", [
|
||||
childProcess.execFile("sudo", [
|
||||
"docker",
|
||||
"exec", args.containerId,
|
||||
...args.params,
|
||||
], { encoding: 'utf8' }, (err, stdout, stderr) => {
|
||||
@ -79,10 +79,12 @@ export function dockerCreateNetwork(args: {
|
||||
networkName: string;
|
||||
}): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile("docker", [
|
||||
childProcess.execFile("sudo", [
|
||||
"docker",
|
||||
"network",
|
||||
"create",
|
||||
args.networkName
|
||||
args.networkName,
|
||||
"--subnet", "172.18.0.0/16"
|
||||
], { encoding: 'utf8' }, (err, stdout, stderr) => {
|
||||
if(err) {
|
||||
if (stderr.includes(`network with name ${args.networkName} already exists`)) {
|
||||
@ -106,7 +108,8 @@ export async function dockerLogs(args: {
|
||||
const stderrFile = args.stderrFile ? await fse.open(args.stderrFile, "w") : "ignore";
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
childProcess.spawn("docker", [
|
||||
childProcess.spawn("sudo", [
|
||||
"docker",
|
||||
"logs",
|
||||
args.containerId,
|
||||
], {
|
||||
@ -122,7 +125,8 @@ export function dockerStop(args: {
|
||||
containerId: string;
|
||||
}): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile('docker', [
|
||||
childProcess.execFile('sudo', [
|
||||
"docker",
|
||||
"stop",
|
||||
args.containerId,
|
||||
], err => {
|
||||
@ -138,7 +142,8 @@ export function dockerRm(args: {
|
||||
containerId: string;
|
||||
}): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile('docker', [
|
||||
childProcess.execFile('sudo', [
|
||||
"docker",
|
||||
"rm",
|
||||
args.containerId,
|
||||
], err => {
|
||||
|
@ -14,8 +14,6 @@ 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";
|
||||
@ -25,7 +23,7 @@ import {dockerCreateNetwork, dockerExec, dockerLogs, dockerRun, dockerStop} from
|
||||
import {request} from "@playwright/test";
|
||||
|
||||
|
||||
// A cypress plugins to add command to start & stop synapses in
|
||||
// A plugin to add command to start & stop synapses in
|
||||
// docker with preset templates.
|
||||
|
||||
interface SynapseConfig {
|
||||
|
86
playwright/tests/invite.spec.ts
Normal file
86
playwright/tests/invite.spec.ts
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
import {test} from '@playwright/test';
|
||||
import {synapseStart, synapseStop, registerUser} from "../plugins/synapsedocker";
|
||||
import type {SynapseInstance} from "../plugins/synapsedocker";
|
||||
|
||||
test.describe("Login", () => {
|
||||
let synapse: SynapseInstance;
|
||||
|
||||
test.beforeEach(async () => {
|
||||
synapse = await synapseStart("default");
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await synapseStop(synapse.synapseId);
|
||||
});
|
||||
|
||||
test("Invite user using /invite command from composer", async ({ page }) => {
|
||||
const user1 = ["foobaraccount", "password123"] as const;
|
||||
const user2 = ["foobaraccount2", "password123"] as const;
|
||||
await registerUser(synapse, ...user1);
|
||||
const { userId } = await registerUser(synapse, ...user2);
|
||||
await page.goto("/");
|
||||
await page.locator("#homeserver").fill("");
|
||||
await page.locator("#homeserver").type(synapse.baseUrl);
|
||||
const [username, password] = user1;
|
||||
await page.locator("#username").type(username);
|
||||
await page.locator("#password").type(password);
|
||||
await page.getByText("Log In", { exact: true }).click();
|
||||
await page.locator(".SessionView").waitFor();
|
||||
// Create the room
|
||||
await page.getByLabel("Create room").click();
|
||||
await page.getByText("Create Room").click();
|
||||
await page.locator("#name").type("My Room");
|
||||
await page.locator(".CreateRoomView_detailsForm")
|
||||
.getByRole("button", { name: "Create room" })
|
||||
.click();
|
||||
await page.locator(".RoomList")
|
||||
.locator("li")
|
||||
.first()
|
||||
.click();
|
||||
await page.locator(".MessageComposer_input textarea").type(`/invite ${userId}`);
|
||||
await page.keyboard.press("Enter");
|
||||
await page.locator(".AnnouncementView").last().getByText("was invited to the room").waitFor();
|
||||
});
|
||||
|
||||
test("Error is shown when using /invite command from composer", async ({ page }) => {
|
||||
const user1 = ["foobaraccount", "password123"] as const;
|
||||
await registerUser(synapse, ...user1);
|
||||
await page.goto("/");
|
||||
await page.locator("#homeserver").fill("");
|
||||
await page.locator("#homeserver").type(synapse.baseUrl);
|
||||
const [username, password] = user1;
|
||||
await page.locator("#username").type(username);
|
||||
await page.locator("#password").type(password);
|
||||
await page.getByText("Log In", { exact: true }).click();
|
||||
await page.locator(".SessionView").waitFor();
|
||||
// Create the room
|
||||
await page.getByLabel("Create room").click();
|
||||
await page.getByText("Create Room").click();
|
||||
await page.locator("#name").type("My Room");
|
||||
await page.locator(".CreateRoomView_detailsForm")
|
||||
.getByRole("button", { name: "Create room" })
|
||||
.click();
|
||||
await page.locator(".RoomList")
|
||||
.locator("li")
|
||||
.first()
|
||||
.click();
|
||||
await page.locator(".MessageComposer_input textarea").type("/invite foobar");
|
||||
await page.keyboard.press("Enter");
|
||||
await page.locator(".RoomView").locator(".ErrorView").waitFor();
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Make sure docker is available
|
||||
if ! docker info > /dev/null 2>&1; then
|
||||
if ! docker --version > /dev/null 2>&1; then
|
||||
echo "You need to intall docker before you can run the tests!"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -273,6 +273,14 @@ export class RoomViewModel extends ErrorReportViewModel {
|
||||
this.reportError(new Error("join syntax: /join <room-id>"));
|
||||
}
|
||||
break;
|
||||
case "invite":
|
||||
if (args.length === 1) {
|
||||
const userId = args[0];
|
||||
await this._room.inviteUser(userId);
|
||||
} else {
|
||||
this.reportError(new Error("invite syntax: /invite <user-id>"));
|
||||
}
|
||||
break;
|
||||
case "shrug":
|
||||
message = "¯\\_(ツ)_/¯ " + args.join(" ");
|
||||
msgtype = "m.text";
|
||||
|
@ -267,6 +267,15 @@ export class HomeServerApi {
|
||||
return this._get("/pushers", undefined, undefined, options);
|
||||
}
|
||||
|
||||
invite(roomId: string, userId: string, reason?: string, options?: BaseRequestOptions): IHomeServerRequest {
|
||||
return this._post(
|
||||
`/rooms/${encodeURIComponent(roomId)}/invite`,
|
||||
{},
|
||||
{ user_id: userId, reason },
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
join(roomId: string, options?: BaseRequestOptions): IHomeServerRequest {
|
||||
return this._post(`/rooms/${encodeURIComponent(roomId)}/join`, {}, {}, options);
|
||||
}
|
||||
|
@ -470,6 +470,13 @@ export class Room extends BaseRoom {
|
||||
});
|
||||
}
|
||||
|
||||
async inviteUser(userId, reason) {
|
||||
if (!userId) {
|
||||
throw new Error("userId is null/undefined");
|
||||
}
|
||||
await this._hsApi.invite(this.id, userId, reason).response();
|
||||
}
|
||||
|
||||
/* called by BaseRoom to pass pendingEvents when opening the timeline */
|
||||
_getPendingEvents() {
|
||||
return this._sendQueue.pendingEvents;
|
||||
|
44
yarn.lock
44
yarn.lock
@ -83,12 +83,12 @@
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@playwright/test@^1.27.1":
|
||||
version "1.32.1"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.32.1.tgz#749c9791adb048c266277a39ba0f7e33fe593ffe"
|
||||
integrity sha512-FTwjCuhlm1qHUGf4hWjfr64UMJD/z0hXYbk+O387Ioe6WdyZQ+0TBDAc6P+pHjx2xCv1VYNgrKbYrNixFWy4Dg==
|
||||
version "1.37.1"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.37.1.tgz#e7f44ae0faf1be52d6360c6bbf689fd0057d9b6f"
|
||||
integrity sha512-bq9zTli3vWJo8S3LwB91U0qDNQDpEXnw7knhxLM0nwDvexQAwx9tO8iKDZSqqneVq+URd/WIoz+BALMqUTgdSg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
playwright-core "1.32.1"
|
||||
playwright-core "1.37.1"
|
||||
optionalDependencies:
|
||||
fsevents "2.3.2"
|
||||
|
||||
@ -1000,6 +1000,15 @@ flatted@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
|
||||
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
|
||||
|
||||
fs-extra@^11.1.1:
|
||||
version "11.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
|
||||
integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
@ -1065,6 +1074,11 @@ globby@^11.0.3:
|
||||
merge2 "^1.3.0"
|
||||
slash "^3.0.0"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
@ -1199,6 +1213,15 @@ json-stable-stringify-without-jsonify@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
|
||||
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
|
||||
|
||||
jsonfile@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
||||
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
|
||||
dependencies:
|
||||
universalify "^2.0.0"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
levn@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
|
||||
@ -1384,10 +1407,10 @@ picomatch@^2.2.3:
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
||||
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
|
||||
|
||||
playwright-core@1.32.1:
|
||||
version "1.32.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.32.1.tgz#5a10c32403323b07d75ea428ebeed866a80b76a1"
|
||||
integrity sha512-KZYUQC10mXD2Am1rGlidaalNGYk3LU1vZqqNk0gT4XPty1jOqgup8KDP8l2CUlqoNKhXM5IfGjWgW37xvGllBA==
|
||||
playwright-core@1.37.1:
|
||||
version "1.37.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.37.1.tgz#cb517d52e2e8cb4fa71957639f1cd105d1683126"
|
||||
integrity sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA==
|
||||
|
||||
postcss-css-variables@^0.18.0:
|
||||
version "0.18.0"
|
||||
@ -1714,6 +1737,11 @@ typeson@^6.0.0:
|
||||
resolved "https://registry.yarnpkg.com/typeson/-/typeson-6.1.0.tgz#5b2a53705a5f58ff4d6f82f965917cabd0d7448b"
|
||||
integrity sha512-6FTtyGr8ldU0pfbvW/eOZrEtEkczHRUtduBnA90Jh9kMPCiFNnXIon3vF41N0S4tV1HHQt4Hk1j4srpESziCaA==
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||
|
Loading…
Reference in New Issue
Block a user