Compare commits
31 Commits
t3chguy/fi
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
570e263ca1 | ||
|
|
a2e18a61a8 | ||
|
|
2146ff6f23 | ||
|
|
115e3cd3d8 | ||
|
|
155c0b6a0c | ||
|
|
841f12bd46 | ||
|
|
6f41ac58bc | ||
|
|
902cdb0810 | ||
|
|
4fd752fe29 | ||
|
|
d83a2d2b93 | ||
|
|
fb9d5db6ec | ||
|
|
0ca23af4a9 | ||
|
|
5db72f7fab | ||
|
|
d193434b30 | ||
|
|
1bbe4802e4 | ||
|
|
169ae025bf | ||
|
|
e666fa33f3 | ||
|
|
c9f375a02b | ||
|
|
81fc054b8b | ||
|
|
efbced733a | ||
|
|
87d40ab0e0 | ||
|
|
8e9a43d70c | ||
|
|
9a11a80483 | ||
|
|
ccf0762737 | ||
|
|
8d07e797c5 | ||
|
|
4dc087c342 | ||
|
|
0783f27f33 | ||
|
|
3c13f55b74 | ||
|
|
2e8e6e92cc | ||
|
|
3432613195 | ||
|
|
eaa20a2c9a |
2
.github/workflows/build.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
# Disable cache on Windows as it is slower than not caching
|
||||
# https://github.com/actions/setup-node/issues/975
|
||||
|
||||
2
.github/workflows/build_develop.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
|
||||
2
.github/workflows/docs.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
repository: matrix-org/matrix-js-sdk
|
||||
path: matrix-js-sdk
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
cache-dependency-path: element-web/yarn.lock
|
||||
|
||||
8
.github/workflows/end-to-end-tests.yaml
vendored
@@ -54,7 +54,7 @@ jobs:
|
||||
with:
|
||||
repository: element-hq/element-web
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
|
||||
- name: Calculate runner variables
|
||||
id: runner-vars
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
with:
|
||||
script: |
|
||||
const numRunners = parseInt(process.env.NUM_RUNNERS, 10);
|
||||
@@ -140,7 +140,7 @@ jobs:
|
||||
name: webapp
|
||||
path: webapp
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
cache-dependency-path: yarn.lock
|
||||
@@ -207,7 +207,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
repository: element-hq/element-web
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
if: inputs.skip != true
|
||||
with:
|
||||
cache: "yarn"
|
||||
|
||||
4
.github/workflows/issue_closed.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
name: Tidy closed issues
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
id: main
|
||||
with:
|
||||
# PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org)
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
});
|
||||
}
|
||||
}
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
name: Close duplicate as Not Planned
|
||||
if: steps.main.outputs.closeAsNotPlanned
|
||||
with:
|
||||
|
||||
2
.github/workflows/pending-reviews.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
URL: "https://github.com/pulls?q=is%3Apr+is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Aelement-hq%2Felement-web+repo%3Aelement-hq%2Felement-desktop+review-requested%3A%40me+sort%3Aupdated-desc+"
|
||||
RELEASE_BLOCKERS_URL: "https://github.com/pulls?q=is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Aelement-hq%2Felement-web+repo%3Aelement-hq%2Felement-desktop+sort%3Aupdated-desc+label%3AX-Release-Blocker+"
|
||||
steps:
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
env:
|
||||
HS_URL: ${{ secrets.BETABOT_HS_URL }}
|
||||
ROOM_ID: ${{ secrets.ROOM_ID }}
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
name: Check PR base branch
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
with:
|
||||
script: |
|
||||
const baseBranch = context.payload.pull_request.base.ref;
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
repository: element-hq/element-web
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
|
||||
10
.github/workflows/static_analysis.yaml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/element-web' || github.repository }}
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
cache: "yarn"
|
||||
|
||||
4
.github/workflows/triage-labelled.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor') ||
|
||||
contains(github.event.issue.labels.*.name, 'A-Element-Call')
|
||||
steps:
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
contains(github.event.issue.labels.*.name, 'good first issue') ||
|
||||
contains(github.event.issue.labels.*.name, 'Hacktoberfest')
|
||||
steps:
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
|
||||
2
.github/workflows/triage-stale.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9
|
||||
- uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10
|
||||
with:
|
||||
operations-per-run: 100
|
||||
|
||||
|
||||
2
.github/workflows/triage-unlabelled.yml
vendored
@@ -62,7 +62,7 @@ jobs:
|
||||
contains(github.event.issue.labels.*.name, 'A-Element-Call')) &&
|
||||
contains(github.event.issue.labels.*.name, 'Z-Labs')
|
||||
steps:
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.removeLabel({
|
||||
|
||||
2
.github/workflows/update-jitsi.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
cache: "yarn"
|
||||
node-version: "lts/*"
|
||||
|
||||
2
.github/workflows/update-topics.yaml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
environment: Matrix
|
||||
steps:
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
env:
|
||||
HS_URL: ${{ secrets.BETABOT_HS_URL }}
|
||||
LOBBY_ROOM_ID: ${{ secrets.ROOM_ID }}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
Changes in [1.11.112](https://github.com/element-hq/element-web/releases/tag/v1.11.112) (2025-09-16)
|
||||
====================================================================================================
|
||||
Fix [CVE-2025-59161](https://www.cve.org/CVERecord?id=CVE-2025-59161) / [GHSA-m6c8-98f4-75rr](https://github.com/element-hq/element-web/security/advisories/GHSA-m6c8-98f4-75rr)
|
||||
|
||||
|
||||
Changes in [1.11.111](https://github.com/element-hq/element-web/releases/tag/v1.11.111) (2025-09-10)
|
||||
====================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# syntax=docker.io/docker/dockerfile:1.17-labs@sha256:9187104f31e3a002a8a6a3209ea1f937fb7486c093cbbde1e14b0fa0d7e4f1b5
|
||||
# syntax=docker.io/docker/dockerfile:1.18-labs@sha256:79cdc14e1c220efb546ad14a8ebc816e3277cd72d27195ced5bebdd226dd1025
|
||||
|
||||
# Builder
|
||||
FROM --platform=$BUILDPLATFORM node:22-bullseye@sha256:f7f28d1962d93cc096ea6327378d990284757fec281ce48e42436e7b4b167fa2 AS builder
|
||||
FROM --platform=$BUILDPLATFORM node:22-bullseye@sha256:f8c398a3ad2612293e8827915c056ed0f5cc708b0f676274bb6c732e3c10f93d AS builder
|
||||
|
||||
# Support custom branch of the js-sdk. This also helps us build images of element-web develop.
|
||||
ARG USE_CUSTOM_SDKS=false
|
||||
@@ -19,7 +19,7 @@ RUN /src/scripts/docker-package.sh
|
||||
RUN cp /src/config.sample.json /src/webapp/config.json
|
||||
|
||||
# App
|
||||
FROM nginxinc/nginx-unprivileged:alpine-slim@sha256:0d019e980f83728002de7a6d8819d0d4af7179046d3946b8b37749953fbb28e6
|
||||
FROM nginxinc/nginx-unprivileged:alpine-slim@sha256:14b127ed799301a21a1798516443c675237120c76b9a738d43c5e4747de4b1c9
|
||||
|
||||
# Need root user to install packages & manipulate the usr directory
|
||||
USER root
|
||||
|
||||
@@ -41,7 +41,7 @@ const config: Config = {
|
||||
"recorderWorkletFactory": "<rootDir>/__mocks__/empty.js",
|
||||
"^fetch-mock$": "<rootDir>/node_modules/fetch-mock",
|
||||
},
|
||||
transformIgnorePatterns: ["/node_modules/(?!(mime|matrix-js-sdk)).+$"],
|
||||
transformIgnorePatterns: ["/node_modules/(?!(mime|matrix-js-sdk|uuid|p-retry|is-network-error)).+$"],
|
||||
collectCoverageFrom: [
|
||||
"<rootDir>/src/**/*.{js,ts,tsx}",
|
||||
// getSessionLock is piped into a different JS context via stringification, and the coverage functionality is
|
||||
|
||||
11
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "element-web",
|
||||
"version": "1.11.111",
|
||||
"version": "1.11.112",
|
||||
"description": "Element: the future of secure communication",
|
||||
"author": "New Vector Ltd.",
|
||||
"repository": {
|
||||
@@ -75,7 +75,7 @@
|
||||
"resolutions": {
|
||||
"**/pretty-format/react-is": "19.1.1",
|
||||
"@playwright/test": "1.54.2",
|
||||
"@types/react": "19.1.12",
|
||||
"@types/react": "19.1.13",
|
||||
"@types/react-dom": "19.1.9",
|
||||
"oidc-client-ts": "3.3.0",
|
||||
"jwt-decode": "4.0.0",
|
||||
@@ -142,7 +142,7 @@
|
||||
"opus-recorder": "^8.0.3",
|
||||
"pako": "^2.0.3",
|
||||
"png-chunks-extract": "^1.0.0",
|
||||
"posthog-js": "1.261.0",
|
||||
"posthog-js": "1.265.1",
|
||||
"qrcode": "1.5.4",
|
||||
"re-resizable": "6.11.2",
|
||||
"react": "^19.0.0",
|
||||
@@ -159,7 +159,7 @@
|
||||
"tar-js": "^0.3.0",
|
||||
"temporal-polyfill": "^0.3.0",
|
||||
"ua-parser-js": "1.0.40",
|
||||
"uuid": "^11.0.0",
|
||||
"uuid": "^13.0.0",
|
||||
"what-input": "^5.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -223,7 +223,7 @@
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/pako": "^2.0.0",
|
||||
"@types/qrcode": "^1.3.5",
|
||||
"@types/react": "19.1.12",
|
||||
"@types/react": "19.1.13",
|
||||
"@types/react-beautiful-dnd": "^13.0.0",
|
||||
"@types/react-dom": "19.1.9",
|
||||
"@types/react-transition-group": "^4.4.0",
|
||||
@@ -232,7 +232,6 @@
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/tar-js": "^0.3.5",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.19.0",
|
||||
"@typescript-eslint/parser": "^8.19.0",
|
||||
"babel-jest": "^29.0.0",
|
||||
|
||||
@@ -29,7 +29,7 @@ test.describe("Landmark navigation tests", () => {
|
||||
|
||||
// Pressing Control+F6 again will focus room search
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
await expect(page.locator(".mx_RoomSearch")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||
|
||||
// Pressing Control+F6 again will focus the message composer
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
@@ -44,7 +44,7 @@ test.describe("Landmark navigation tests", () => {
|
||||
await expect(page.locator(".mx_HomePage")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_RoomSearch")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
||||
@@ -75,11 +75,11 @@ test.describe("Landmark navigation tests", () => {
|
||||
|
||||
// Pressing Control+F6 again will focus room search
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
await expect(page.locator(".mx_RoomSearch")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||
|
||||
// Pressing Control+F6 again will focus the room tile in the room list
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
await expect(page.locator(".mx_RoomTile_selected")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListItemView_selected")).toBeFocused();
|
||||
|
||||
// Pressing Control+F6 again will focus the message composer
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
@@ -94,10 +94,10 @@ test.describe("Landmark navigation tests", () => {
|
||||
await expect(page.locator(".mx_BasicMessageComposer_input")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_RoomTile_selected")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListItemView_selected")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_RoomSearch")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
||||
@@ -131,11 +131,11 @@ test.describe("Landmark navigation tests", () => {
|
||||
|
||||
// Pressing Control+F6 again will focus room search
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
await expect(page.locator(".mx_RoomSearch")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||
|
||||
// Pressing Control+F6 again will focus the room tile in the room list
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
await expect(page.locator(".mx_RoomTile")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListItemView")).toBeFocused();
|
||||
|
||||
// Pressing Control+F6 again will focus the home section
|
||||
await page.keyboard.press("ControlOrMeta+F6");
|
||||
@@ -150,10 +150,10 @@ test.describe("Landmark navigation tests", () => {
|
||||
await expect(page.locator(".mx_HomePage")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_RoomTile")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListItemView")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_RoomSearch")).toBeFocused();
|
||||
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
||||
|
||||
@@ -108,7 +108,10 @@ test.describe("Composer", () => {
|
||||
|
||||
const composer = page.getByRole("textbox", { name: "Send an unencrypted message…" });
|
||||
await composer.pressSequentially("@bob");
|
||||
await page.getByRole("option", { name: "Bob" }).click();
|
||||
|
||||
// Note that we include the user ID here as the room tile is also an 'option' role
|
||||
// with text 'Bob'
|
||||
await page.getByRole("option", { name: `Bob ${bot.credentials.userId}` }).click();
|
||||
await expect(composer.getByText("Bob")).toBeVisible();
|
||||
await expect(composer).toMatchScreenshot("mention.png");
|
||||
await composer.press("Enter");
|
||||
|
||||
@@ -49,7 +49,7 @@ test.describe("Encryption state after registration", () => {
|
||||
"Pa$sW0rD!",
|
||||
);
|
||||
|
||||
await page.getByRole("button", { name: "Add room" }).click();
|
||||
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "New room" }).click();
|
||||
await page.getByRole("textbox", { name: "Name" }).fill("test room");
|
||||
await page.getByRole("button", { name: "Create room" }).click();
|
||||
@@ -78,7 +78,7 @@ test.describe("Key backup reset from elsewhere", () => {
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
await registerAccountMas(page, mailpitClient, testUsername, `${testUsername}@email.com`, testPassword);
|
||||
|
||||
await page.getByRole("button", { name: "Add room" }).click();
|
||||
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "New room" }).click();
|
||||
await page.getByRole("textbox", { name: "Name" }).fill("test room");
|
||||
await page.getByRole("button", { name: "Create room" }).click();
|
||||
|
||||
@@ -21,7 +21,8 @@ const checkDMRoom = async (page: Page) => {
|
||||
};
|
||||
|
||||
const startDMWithBob = async (page: Page, bob: Bot) => {
|
||||
await page.locator(".mx_LegacyRoomList").getByRole("button", { name: "Start chat" }).click();
|
||||
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "Start chat" }).click();
|
||||
await page.getByTestId("invite-dialog-input").fill(bob.credentials.userId);
|
||||
await page.locator(".mx_InviteDialog_tile_nameStack_name").getByText("Bob").click();
|
||||
await expect(
|
||||
|
||||
@@ -143,10 +143,7 @@ test.describe("Cryptography", function () {
|
||||
);
|
||||
|
||||
// Alice accepts the invite
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Invites" }).locator(".mx_RoomSublist_tiles").getByRole("treeitem"),
|
||||
).toHaveCount(1);
|
||||
await page.getByRole("treeitem", { name: "Test room" }).click();
|
||||
await page.getByRole("option", { name: "Test room" }).click();
|
||||
await page.locator(".mx_RoomView").getByRole("button", { name: "Accept" }).click();
|
||||
|
||||
// Bob sends an encrypted event and an undecryptable event
|
||||
@@ -280,10 +277,7 @@ test.describe("Cryptography", function () {
|
||||
);
|
||||
|
||||
// Alice accepts the invite
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Invites" }).locator(".mx_RoomSublist_tiles").getByRole("treeitem"),
|
||||
).toHaveCount(1);
|
||||
await page.getByRole("treeitem", { name: "Test room" }).click();
|
||||
await page.getByRole("option", { name: "Test room" }).click();
|
||||
await page.locator(".mx_RoomView").getByRole("button", { name: "Accept" }).click();
|
||||
|
||||
// wait until we're joined and see the timeline
|
||||
|
||||
@@ -23,7 +23,7 @@ test.describe("Key storage out of sync toast", () => {
|
||||
await deleteCachedSecrets(page);
|
||||
|
||||
// We won't be prompted for crypto setup unless we have an e2e room, so make one
|
||||
await page.getByRole("button", { name: "Add room" }).click();
|
||||
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "New room" }).click();
|
||||
await page.getByRole("textbox", { name: "Name" }).fill("Test room");
|
||||
await page.getByRole("button", { name: "Create room" }).click();
|
||||
@@ -68,7 +68,7 @@ test.describe("'Turn on key storage' toast", () => {
|
||||
await logIntoElementAndVerify(page, credentials, recoveryKey.encodedPrivateKey);
|
||||
|
||||
// We won't be prompted for crypto setup unless we have an e2e room, so make one
|
||||
await page.getByRole("button", { name: "Add room" }).click();
|
||||
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "New room" }).click();
|
||||
await page.getByRole("textbox", { name: "Name" }).fill("Test room");
|
||||
await page.getByRole("button", { name: "Create room" }).click();
|
||||
|
||||
@@ -438,8 +438,8 @@ export async function sendMessageInCurrentRoom(page: Page, message: string): Pro
|
||||
* @param isEncrypted - Whether the room should be encrypted
|
||||
*/
|
||||
export async function createRoom(page: Page, roomName: string, isEncrypted: boolean): Promise<void> {
|
||||
await page.getByRole("button", { name: "Add room" }).click();
|
||||
await page.locator(".mx_IconizedContextMenu").getByRole("menuitem", { name: "New room" }).click();
|
||||
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "New room" }).click();
|
||||
|
||||
const dialog = page.locator(".mx_Dialog");
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ test.describe("Invite dialog", function () {
|
||||
"should support inviting a user to Direct Messages",
|
||||
{ tag: "@screenshot" },
|
||||
async ({ page, app, user, bot }) => {
|
||||
await page.locator(".mx_LegacyRoomList").getByRole("button", { name: "Start chat" }).click();
|
||||
await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "Start chat" }).click();
|
||||
|
||||
const other = page.locator(".mx_InviteDialog_other");
|
||||
// Assert that the header is rendered
|
||||
|
||||
@@ -59,7 +59,7 @@ test.describe("Knock Into Room", () => {
|
||||
|
||||
// Knocked room should appear in Rooms
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).toBeVisible();
|
||||
|
||||
// bot waits for knock request from Alice
|
||||
@@ -77,7 +77,7 @@ test.describe("Knock Into Room", () => {
|
||||
await bot.inviteUser(room.roomId, user.userId);
|
||||
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Invites" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).toBeVisible();
|
||||
|
||||
// Alice have to accept invitation in order to join the room.
|
||||
@@ -85,7 +85,7 @@ test.describe("Knock Into Room", () => {
|
||||
await page.locator(".mx_RoomView").getByRole("button", { name: "Accept" }).click();
|
||||
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(page.getByText("Alice joined the room")).toBeVisible();
|
||||
@@ -136,7 +136,7 @@ test.describe("Knock Into Room", () => {
|
||||
|
||||
// Knocked room should appear in Rooms
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).toBeVisible();
|
||||
|
||||
// bot waits for knock request from Alice
|
||||
@@ -154,7 +154,7 @@ test.describe("Knock Into Room", () => {
|
||||
await bot.inviteUser(room.roomId, user.userId);
|
||||
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Invites" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).toBeVisible();
|
||||
|
||||
// Alice have to accept invitation in order to join the room.
|
||||
@@ -162,7 +162,7 @@ test.describe("Knock Into Room", () => {
|
||||
await page.locator(".mx_RoomView").getByRole("button", { name: "Accept" }).click();
|
||||
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(page.getByText("Alice joined the room")).toBeVisible();
|
||||
@@ -215,14 +215,14 @@ test.describe("Knock Into Room", () => {
|
||||
await expect(roomPreviewBar.getByRole("heading", { name: "Request to join sent" })).toBeVisible();
|
||||
|
||||
// Knocked room should appear in Rooms
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity" });
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" });
|
||||
|
||||
await roomPreviewBar.getByRole("button", { name: "Cancel request" }).click();
|
||||
await expect(roomPreviewBar.getByRole("heading", { name: "Ask to join Cybersecurity?" })).toBeVisible();
|
||||
await expect(roomPreviewBar.getByRole("button", { name: "Request access" })).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).not.toBeVisible();
|
||||
});
|
||||
|
||||
@@ -244,7 +244,7 @@ test.describe("Knock Into Room", () => {
|
||||
|
||||
// Knocked room should appear in Rooms
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity" }),
|
||||
page.getByTestId("room-list").getByRole("option", { name: "Open room Cybersecurity" }),
|
||||
).toBeVisible();
|
||||
|
||||
// bot waits for knock request from Alice
|
||||
@@ -262,13 +262,10 @@ test.describe("Knock Into Room", () => {
|
||||
await bot.kick(room.roomId, user.userId);
|
||||
|
||||
// Room should stay in Rooms and have red badge when knock is denied
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).getByRole("treeitem", { name: "Cybersecurity", exact: true }),
|
||||
).not.toBeVisible();
|
||||
await expect(
|
||||
page
|
||||
.getByRole("group", { name: "Rooms" })
|
||||
.getByRole("treeitem", { name: "Cybersecurity 1 unread mention." }),
|
||||
.getByTestId("room-list")
|
||||
.getByRole("option", { name: "Open room Cybersecurity with 1 unread mention." }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(roomPreviewBar.getByRole("heading", { name: "You have been denied access" })).toBeVisible();
|
||||
|
||||
@@ -17,7 +17,7 @@ test.describe("LeftPanel", () => {
|
||||
// create rooms and check room names are correct
|
||||
for (const name of ["Apple", "Pineapple", "Orange"]) {
|
||||
await app.client.createRoom({ name });
|
||||
await expect(page.getByRole("treeitem", { name })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: `Open room ${name}` })).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import type { JSHandle, Page } from "@playwright/test";
|
||||
import type { JSHandle, Locator, Page } from "@playwright/test";
|
||||
import type { MatrixEvent, Room, IndexedDBStore, ReceiptType } from "matrix-js-sdk/src/matrix";
|
||||
import { test as base, expect } from "../../element-web-test";
|
||||
import { type Bot } from "../../pages/bot";
|
||||
@@ -428,7 +428,7 @@ class Helpers {
|
||||
}
|
||||
|
||||
getRoomListTile(label: string) {
|
||||
return this.page.getByRole("treeitem", { name: new RegExp("^" + label) });
|
||||
return this.page.getByRole("option", { name: new RegExp("^Open room " + label) });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -446,8 +446,8 @@ class Helpers {
|
||||
*/
|
||||
async assertRead(room: RoomRef) {
|
||||
const tile = this.getRoomListTile(room.name);
|
||||
await expect(tile.locator(".mx_NotificationBadge_dot")).not.toBeVisible();
|
||||
await expect(tile.locator(".mx_NotificationBadge_count")).not.toBeVisible();
|
||||
await expect(tile.getByTestId("notification-decoration")).not.toBeVisible();
|
||||
await expect(tile).not.toHaveAccessibleName(/with \d* unread message/);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,15 +463,18 @@ class Helpers {
|
||||
/**
|
||||
* Assert a given room is marked as unread (via the room list tile)
|
||||
* @param room - the name of the room to check
|
||||
* @param count - the numeric count to assert, or if "." specified then a bold/dot (no count) state is asserted
|
||||
* @param count - the numeric count to assert
|
||||
*/
|
||||
async assertUnread(room: RoomRef, count: number | ".") {
|
||||
async assertUnread(room: RoomRef, count: number) {
|
||||
const tile = this.getRoomListTile(room.name);
|
||||
if (count === ".") {
|
||||
await expect(tile.locator(".mx_NotificationBadge_dot")).toBeVisible();
|
||||
} else {
|
||||
await expect(tile.locator(".mx_NotificationBadge_count")).toHaveText(count.toString());
|
||||
}
|
||||
await expect(tile).toBeVisible();
|
||||
await expect(tile).toHaveAccessibleName(/with \d* unread message/);
|
||||
}
|
||||
|
||||
async unreadCountForRoomTile(tile: Locator): Promise<number> {
|
||||
const accessibleName = await tile.getAttribute("aria-label");
|
||||
const match = accessibleName?.match(/(\d+)\s+unread message/);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,7 +490,7 @@ class Helpers {
|
||||
// .toBeLessThan doesn't have a retry mechanism, so we use .poll
|
||||
await expect
|
||||
.poll(async () => {
|
||||
return parseInt(await tile.locator(".mx_NotificationBadge_count").textContent(), 10);
|
||||
return this.unreadCountForRoomTile(tile);
|
||||
})
|
||||
.toBeLessThan(lessThan);
|
||||
}
|
||||
@@ -505,7 +508,7 @@ class Helpers {
|
||||
// .toBeGreaterThan doesn't have a retry mechanism, so we use .poll
|
||||
await expect
|
||||
.poll(async () => {
|
||||
return parseInt(await tile.locator(".mx_NotificationBadge_count").textContent(), 10);
|
||||
return this.unreadCountForRoomTile(tile);
|
||||
})
|
||||
.toBeGreaterThan(greaterThan);
|
||||
}
|
||||
@@ -596,24 +599,15 @@ class Helpers {
|
||||
await button.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the `Show rooms with unread messages first` option for the room list
|
||||
*/
|
||||
async toggleRoomUnreadOrder() {
|
||||
await this.toggleRoomListMenu();
|
||||
await this.page.getByText("Show rooms with unread messages first").click();
|
||||
// Close contextual menu
|
||||
await this.page.locator(".mx_ContextualMenu_background").click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the room list is ordered as expected
|
||||
* @param rooms
|
||||
*/
|
||||
async assertRoomListOrder(rooms: Array<{ name: string }>) {
|
||||
const roomList = this.page.locator(".mx_RoomTile_title");
|
||||
const roomListContainer = this.page.getByTestId("room-list");
|
||||
const roomTiles = roomListContainer.getByRole("option");
|
||||
for (const [i, room] of rooms.entries()) {
|
||||
await expect(roomList.nth(i)).toHaveText(room.name);
|
||||
await expect(roomTiles.nth(i)).toHaveAccessibleName(new RegExp(`${room.name}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
const main3 = await sendMessage(bot);
|
||||
|
||||
// (So the room starts off unread)
|
||||
await expect(page.getByLabel(`${otherRoomName} 3 unread messages.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 3 unread messages.`)).toBeVisible();
|
||||
|
||||
// When we send a threaded receipt for the last event in main
|
||||
// And an unthreaded receipt for an earlier event
|
||||
@@ -147,13 +147,13 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await sendMessage(bot);
|
||||
|
||||
// (The room starts off unread)
|
||||
await expect(page.getByLabel(`${otherRoomName} 3 unread messages.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 3 unread messages.`)).toBeVisible();
|
||||
|
||||
// When we send a threaded receipt for the second-last event in main
|
||||
await sendThreadedReadReceipt(app, main2);
|
||||
|
||||
// Then the room has only one unread
|
||||
await expect(page.getByLabel(`${otherRoomName} 1 unread message.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 1 unread message.`)).toBeVisible();
|
||||
});
|
||||
|
||||
test("Considers room read if there is only a main thread and we have a main receipt", async ({
|
||||
@@ -166,7 +166,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await sendMessage(bot);
|
||||
const main3 = await sendMessage(bot);
|
||||
// (The room starts off unread)
|
||||
await expect(page.getByLabel(`${otherRoomName} 3 unread messages.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 3 unread messages.`)).toBeVisible();
|
||||
|
||||
// When we send a threaded receipt for the last event in main
|
||||
await sendThreadedReadReceipt(app, main3);
|
||||
@@ -186,7 +186,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
const thread1a = await botSendThreadMessage(bot, main1.event_id);
|
||||
await botSendThreadMessage(bot, main1.event_id);
|
||||
// 1 unread on the main thread, 2 in the new thread that aren't shown
|
||||
await expect(page.getByLabel(`${otherRoomName} 1 unread message.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 1 unread message.`)).toBeVisible();
|
||||
|
||||
// When we send receipts for main, and the second-last in the thread
|
||||
await sendThreadedReadReceipt(app, main1);
|
||||
@@ -203,7 +203,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await botSendThreadMessage(bot, main1.event_id);
|
||||
const thread1b = await botSendThreadMessage(bot, main1.event_id);
|
||||
// 1 unread on the main thread, 2 in the new thread which don't show
|
||||
await expect(page.getByLabel(`${otherRoomName} 1 unread message.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 1 unread message.`)).toBeVisible();
|
||||
|
||||
// When we send receipts for main, and the last in the thread
|
||||
await sendThreadedReadReceipt(app, main1);
|
||||
@@ -226,7 +226,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
const thread1a = await botSendThreadMessage(bot, main1.event_id);
|
||||
await botSendThreadMessage(bot, main1.event_id);
|
||||
// 1 unread on the main thread, 2 in the new thread which don't count
|
||||
await expect(page.getByLabel(`${otherRoomName} 1 unread message.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 1 unread message.`)).toBeVisible();
|
||||
|
||||
// When we send an unthreaded receipt for the second-last in the thread
|
||||
await sendUnthreadedReadReceipt(app, thread1a);
|
||||
@@ -251,7 +251,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
const thread1b = await botSendThreadMessage(bot, main1.event_id);
|
||||
await sendMessage(bot);
|
||||
// 2 unreads on the main thread, 2 in the new thread which don't count
|
||||
await expect(page.getByLabel(`${otherRoomName} 2 unread messages.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 2 unread messages.`)).toBeVisible();
|
||||
|
||||
// When we send an unthreaded receipt for the last in the thread
|
||||
await sendUnthreadedReadReceipt(app, thread1b);
|
||||
@@ -259,7 +259,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
// Then the room has only one unread - the one in the
|
||||
// main thread, because it is later than the unthreaded
|
||||
// receipt.
|
||||
await expect(page.getByLabel(`${otherRoomName} 1 unread message.`)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} with 1 unread message.`)).toBeVisible();
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -291,7 +291,9 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
const uriEncodedLastMessageId = encodeURIComponent(lastMessageId);
|
||||
|
||||
// wait until all messages have been received
|
||||
await expect(page.getByLabel(`${otherRoomName} ${sendMessageResponses.length} unread messages.`)).toBeVisible();
|
||||
await expect(
|
||||
page.getByLabel(`${otherRoomName} with ${sendMessageResponses.length} unread messages.`),
|
||||
).toBeVisible();
|
||||
|
||||
// switch to the room with the messages
|
||||
await page.goto(`/#/room/${otherRoomId}`);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Room list order", () => {
|
||||
test("Rooms with unread messages appear at the top of room list if 'unread first' is selected", async ({
|
||||
test("Rooms with unread messages appear at the top of room list with default 'activity' ordering", async ({
|
||||
roomAlpha: room1,
|
||||
roomBeta: room2,
|
||||
util,
|
||||
@@ -22,15 +22,18 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await util.goTo(room2);
|
||||
|
||||
// Display the unread first room
|
||||
await util.toggleRoomUnreadOrder();
|
||||
await util.receiveMessages(room1, ["Msg1"]);
|
||||
await page.reload();
|
||||
|
||||
// switch rooms so they can re-order in the list
|
||||
await util.goTo(room1);
|
||||
|
||||
// Room 1 has an unread message and should be displayed first
|
||||
// (as the default is to sort by activity)
|
||||
await util.assertRoomListOrder([room1, room2]);
|
||||
});
|
||||
|
||||
test("Rooms with unread threads appear at the top of room list if 'unread first' is selected", async ({
|
||||
test("Rooms with unread threads appear at the top of room list with default 'activity' order", async ({
|
||||
roomAlpha: room1,
|
||||
roomBeta: room2,
|
||||
util,
|
||||
@@ -42,7 +45,6 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await util.assertRead(room1);
|
||||
|
||||
// Display the unread first room
|
||||
await util.toggleRoomUnreadOrder();
|
||||
await util.receiveMessages(room1, [msg.threadedOff("Msg1", "Resp1")]);
|
||||
await util.saveAndReload();
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ test.describe("Release announcement", () => {
|
||||
"should display the new room list release announcement",
|
||||
{ tag: "@screenshot" },
|
||||
async ({ page, app, room, util }) => {
|
||||
// dismiss the toast so the announcement appears
|
||||
await page.getByRole("button", { name: "Dismiss" }).click();
|
||||
|
||||
const name = "Chats has a new look!";
|
||||
|
||||
// The release announcement should be displayed
|
||||
|
||||
@@ -46,7 +46,7 @@ test.describe("Create Room", () => {
|
||||
|
||||
test("should allow us to start a chat and show encryption state", async ({ page, user, app }) => {
|
||||
await page.getByRole("button", { name: "Add", exact: true }).click();
|
||||
await page.getByText("Start new chat").click();
|
||||
await page.getByRole("menuitem", { name: "Start chat" }).click();
|
||||
|
||||
await page.getByTestId("invite-dialog-input").fill(user.userId);
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@ import { type ElementAppPage } from "../../pages/ElementAppPage";
|
||||
test.describe("Room Header", () => {
|
||||
test.use({
|
||||
displayName: "Sakura",
|
||||
config: {
|
||||
features: {
|
||||
feature_new_room_list: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
test.describe("with feature_notifications enabled", () => {
|
||||
@@ -23,7 +28,7 @@ test.describe("Room Header", () => {
|
||||
});
|
||||
test("should render default buttons properly", { tag: "@screenshot" }, async ({ page, app, user }) => {
|
||||
await app.client.createRoom({ name: "Test Room" });
|
||||
await app.viewRoomByName("Test Room");
|
||||
await app.viewRoomByNameOnOldRoomList("Test Room");
|
||||
|
||||
const header = page.locator(".mx_RoomHeader");
|
||||
|
||||
@@ -61,7 +66,7 @@ test.describe("Room Header", () => {
|
||||
"officia deserunt mollit anim id est laborum.";
|
||||
|
||||
await app.client.createRoom({ name: LONG_ROOM_NAME });
|
||||
await app.viewRoomByName(LONG_ROOM_NAME);
|
||||
await app.viewRoomByNameOnOldRoomList(LONG_ROOM_NAME);
|
||||
|
||||
const header = page.locator(".mx_RoomHeader");
|
||||
// Wait until the room name is set
|
||||
@@ -86,7 +91,7 @@ test.describe("Room Header", () => {
|
||||
|
||||
test("should render room header icon correctly", { tag: "@screenshot" }, async ({ page, app, user }) => {
|
||||
await app.client.createRoom({ name: "Test Room", visibility: "public" as Visibility });
|
||||
await app.viewRoomByName("Test Room");
|
||||
await app.viewRoomByNameOnOldRoomList("Test Room");
|
||||
|
||||
const header = page.locator(".mx_RoomHeader");
|
||||
|
||||
@@ -106,7 +111,7 @@ test.describe("Room Header", () => {
|
||||
|
||||
await page.getByRole("button", { name: "Create video room" }).click();
|
||||
|
||||
await app.viewRoomByName("Test video room");
|
||||
await app.viewRoomByNameOnOldRoomList("Test video room");
|
||||
};
|
||||
|
||||
test.describe("and with feature_notifications enabled", () => {
|
||||
|
||||
@@ -34,7 +34,7 @@ test.describe("Mark as Unread", () => {
|
||||
await bot.sendMessage(roomId, "I am a robot. Beep.");
|
||||
|
||||
// Regular notification on new message
|
||||
await expect(page.getByLabel(TEST_ROOM_NAME + " 1 unread message.")).toBeVisible();
|
||||
await expect(page.getByLabel(`Open room ${TEST_ROOM_NAME} with 1 unread message.`)).toBeVisible();
|
||||
await expect(page).toHaveTitle("Element [1]");
|
||||
|
||||
await page.goto("/#/room/" + roomId);
|
||||
@@ -48,9 +48,12 @@ test.describe("Mark as Unread", () => {
|
||||
|
||||
const roomTile = page.getByLabel(TEST_ROOM_NAME);
|
||||
await roomTile.focus();
|
||||
await roomTile.getByRole("button", { name: "Room options" }).click();
|
||||
await roomTile.getByRole("button", { name: "More Options" }).click();
|
||||
await page.getByRole("menuitem", { name: "Mark as unread" }).click();
|
||||
|
||||
await expect(page.getByLabel(TEST_ROOM_NAME + " Unread messages.")).toBeVisible();
|
||||
// focus the user menu to avoid to have hover decoration
|
||||
await page.getByRole("button", { name: "User menu" }).focus();
|
||||
|
||||
await expect(roomTile.getByTestId("notification-decoration")).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type Page, type Request } from "@playwright/test";
|
||||
import { type Locator, type Page, type Request } from "@playwright/test";
|
||||
|
||||
import { test as base, expect } from "../../element-web-test";
|
||||
import type { ElementAppPage } from "../../pages/ElementAppPage";
|
||||
@@ -38,7 +38,7 @@ const test = base.extend<{
|
||||
|
||||
test.describe("Sliding Sync", () => {
|
||||
const checkOrder = async (wantOrder: string[], page: Page) => {
|
||||
await expect(page.getByRole("group", { name: "Rooms" }).locator(".mx_RoomTile_title")).toHaveText(wantOrder);
|
||||
await expect(page.getByTestId("room-list").locator(".mx_RoomListItemView_text")).toHaveText(wantOrder);
|
||||
};
|
||||
|
||||
const bumpRoom = async (roomId: string, app: ElementAppPage) => {
|
||||
@@ -50,6 +50,18 @@ test.describe("Sliding Sync", () => {
|
||||
});
|
||||
};
|
||||
|
||||
function getPrimaryFilters(page: Page): Locator {
|
||||
return page.getByTestId("primary-filters");
|
||||
}
|
||||
|
||||
function getRoomOptionsMenu(page: Page): Locator {
|
||||
return page.getByRole("button", { name: "Room Options" });
|
||||
}
|
||||
|
||||
function getFilterExpandButton(page: Page): Locator {
|
||||
return getPrimaryFilters(page).getByRole("button", { name: "Expand filter list" });
|
||||
}
|
||||
|
||||
test.use({
|
||||
config: {
|
||||
features: {
|
||||
@@ -69,20 +81,15 @@ test.describe("Sliding Sync", () => {
|
||||
// create rooms and check room names are correct
|
||||
for (const fruit of ["Apple", "Pineapple", "Orange"]) {
|
||||
await app.client.createRoom({ name: fruit });
|
||||
await expect(page.getByRole("treeitem", { name: fruit })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: `Open room ${fruit}` })).toBeVisible();
|
||||
}
|
||||
|
||||
const roomList = page.getByTestId("room-list");
|
||||
// Check count, 3 fruits + 1 testRoom = 4
|
||||
await expect(page.locator(".mx_RoomSublist_tiles").getByRole("treeitem")).toHaveCount(4);
|
||||
await expect(roomList.getByRole("option")).toHaveCount(4);
|
||||
await checkOrder(["Orange", "Pineapple", "Apple", "Test Room"], page);
|
||||
|
||||
const locator = page.getByRole("group", { name: "Rooms" }).locator(".mx_RoomSublist_headerContainer");
|
||||
await locator.hover();
|
||||
await locator.getByRole("button", { name: "List options" }).click();
|
||||
|
||||
// force click as the radio button's size is zero
|
||||
await page.getByRole("menuitemradio", { name: "A-Z" }).dispatchEvent("click");
|
||||
await expect(page.locator(".mx_StyledRadioButton_checked").getByText("A-Z")).toBeVisible();
|
||||
await getRoomOptionsMenu(page).click();
|
||||
await page.getByRole("menuitemradio", { name: "A-Z" }).click();
|
||||
|
||||
await checkOrder(["Apple", "Orange", "Pineapple", "Test Room"], page);
|
||||
});
|
||||
@@ -93,11 +100,11 @@ test.describe("Sliding Sync", () => {
|
||||
for (const fruit of ["Apple", "Pineapple", "Orange"]) {
|
||||
const id = await app.client.createRoom({ name: fruit });
|
||||
roomIds.push(id);
|
||||
await expect(page.getByRole("treeitem", { name: fruit })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: `Open room ${fruit}` })).toBeVisible();
|
||||
}
|
||||
|
||||
// Select the Test Room
|
||||
await page.getByRole("treeitem", { name: "Test Room" }).click();
|
||||
await page.getByRole("option", { name: "Open room Test Room" }).click();
|
||||
const [apple, pineapple, orange] = roomIds;
|
||||
await checkOrder(["Orange", "Pineapple", "Apple", "Test Room"], page);
|
||||
await bumpRoom(apple, app);
|
||||
@@ -116,7 +123,7 @@ test.describe("Sliding Sync", () => {
|
||||
for (const fruit of ["Apple", "Pineapple", "Orange"]) {
|
||||
const id = await app.client.createRoom({ name: fruit });
|
||||
roomIds.push(id);
|
||||
await expect(page.getByRole("treeitem", { name: fruit })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: `Open room ${fruit}` })).toBeVisible();
|
||||
}
|
||||
|
||||
// Given a list of Orange, Pineapple, Apple - if Pineapple is active and a message is sent in Apple, the list should
|
||||
@@ -124,7 +131,7 @@ test.describe("Sliding Sync", () => {
|
||||
// be Apple, Orange Pineapple - only when you click on a different room do things reshuffle.
|
||||
|
||||
// Select the Pineapple room
|
||||
await page.getByRole("treeitem", { name: "Pineapple" }).click();
|
||||
await page.getByRole("option", { name: "Open room Pineapple" }).click();
|
||||
await checkOrder(["Orange", "Pineapple", "Apple", "Test Room"], page);
|
||||
|
||||
// Move Apple
|
||||
@@ -132,7 +139,7 @@ test.describe("Sliding Sync", () => {
|
||||
await checkOrder(["Apple", "Pineapple", "Orange", "Test Room"], page);
|
||||
|
||||
// Select the Test Room
|
||||
await page.getByRole("treeitem", { name: "Test Room" }).click();
|
||||
await page.getByRole("option", { name: "Open room Test Room" }).click();
|
||||
|
||||
// the rooms reshuffle to match reality
|
||||
await checkOrder(["Apple", "Orange", "Pineapple", "Test Room"], page);
|
||||
@@ -142,25 +149,20 @@ test.describe("Sliding Sync", () => {
|
||||
// send a message in the test room: unread notification count should increment
|
||||
await bob.sendMessage(testRoom.roomId, "Hello World");
|
||||
|
||||
const treeItemLocator1 = page.getByRole("treeitem", { name: "Test Room 1 unread message." });
|
||||
await expect(treeItemLocator1.locator(".mx_NotificationBadge_count")).toHaveText("1");
|
||||
// await expect(page.locator(".mx_NotificationBadge")).not.toHaveClass("mx_NotificationBadge_highlighted");
|
||||
await expect(treeItemLocator1.locator(".mx_NotificationBadge")).not.toHaveClass(
|
||||
/mx_NotificationBadge_highlighted/,
|
||||
);
|
||||
const itemLocator1 = page.getByRole("option", { name: "Open room David Langley with 1 unread message." });
|
||||
await expect(itemLocator1.getByTestId("notification-decoration")).toHaveText("1");
|
||||
|
||||
// send an @mention: highlight count (red) should be 2.
|
||||
await bob.sendMessage(testRoom.roomId, `Hello ${user.displayName}`);
|
||||
const treeItemLocator2 = page.getByRole("treeitem", {
|
||||
name: "Test Room 2 unread messages including mentions.",
|
||||
const itemLocator2 = page.getByRole("treeitem", {
|
||||
name: "Open room Test Room 2 unread messages including mentions.",
|
||||
});
|
||||
await expect(treeItemLocator2.locator(".mx_NotificationBadge_count")).toHaveText("2");
|
||||
await expect(treeItemLocator2.locator(".mx_NotificationBadge")).toHaveClass(/mx_NotificationBadge_highlighted/);
|
||||
await expect(itemLocator2.getByTestId("notification-decoration")).toHaveText("2");
|
||||
|
||||
// click on the room, the notif counts should disappear
|
||||
await page.getByRole("treeitem", { name: "Test Room 2 unread messages including mentions." }).click();
|
||||
await page.getByRole("option", { name: "Open room Test Room 2 unread messages including mentions." }).click();
|
||||
await expect(
|
||||
page.getByRole("treeitem", { name: "Test Room" }).locator("mx_NotificationBadge_count"),
|
||||
page.getByRole("option", { name: "Open room Test Room" }).getByTestId("notification-decoration"),
|
||||
).not.toBeAttached();
|
||||
});
|
||||
|
||||
@@ -175,7 +177,9 @@ test.describe("Sliding Sync", () => {
|
||||
// wait for this message to arrive, tell by the room list resorting
|
||||
await checkOrder(["Test Room", "Dummy"], page);
|
||||
|
||||
await expect(page.getByRole("treeitem", { name: "Test Room" }).locator(".mx_NotificationBadge")).toBeAttached();
|
||||
await expect(
|
||||
page.getByRole("option", { name: "Open room Test Room" }).getByTestId("notification-decoration"),
|
||||
).toBeAttached();
|
||||
});
|
||||
|
||||
test("should update user settings promptly", async ({ page, app }) => {
|
||||
@@ -193,7 +197,7 @@ test.describe("Sliding Sync", () => {
|
||||
for (const fruit of ["Apple", "Pineapple", "Orange"]) {
|
||||
const id = await app.client.createRoom({ name: fruit });
|
||||
roomIds.push(id);
|
||||
await expect(page.getByRole("treeitem", { name: fruit })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: `Open room ${fruit}` })).toBeVisible();
|
||||
}
|
||||
const [roomAId, roomPId] = roomIds;
|
||||
|
||||
@@ -206,7 +210,7 @@ test.describe("Sliding Sync", () => {
|
||||
// Select the Test Room and wait for playwright to get the request
|
||||
const [request] = await Promise.all([
|
||||
page.waitForRequest(matchRoomSubRequest(roomAId)),
|
||||
page.getByRole("treeitem", { name: "Apple", exact: true }).click(),
|
||||
page.getByRole("option", { name: "Open room Apple", exact: true }).click(),
|
||||
]);
|
||||
const roomSubscriptions = request.postDataJSON().room_subscriptions;
|
||||
expect(roomSubscriptions, "room_subscriptions is object").toBeDefined();
|
||||
@@ -214,7 +218,7 @@ test.describe("Sliding Sync", () => {
|
||||
// Switch to another room and wait for playwright to get the request
|
||||
await Promise.all([
|
||||
page.waitForRequest(matchRoomSubRequest(roomPId)),
|
||||
page.getByRole("treeitem", { name: "Pineapple", exact: true }).click(),
|
||||
page.getByRole("option", { name: "Open room Pineapple", exact: true }).click(),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -240,34 +244,29 @@ test.describe("Sliding Sync", () => {
|
||||
{ roomNames, clientUserId },
|
||||
);
|
||||
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Invites" }).locator(".mx_RoomSublist_tiles").getByRole("treeitem"),
|
||||
).toHaveCount(3);
|
||||
await getFilterExpandButton(page).click();
|
||||
const primaryFilters = getPrimaryFilters(page);
|
||||
await primaryFilters.getByRole("option", { name: "Invites" }).click();
|
||||
|
||||
await expect(page.getByTestId("room-list").getByRole("option")).toHaveCount(3);
|
||||
|
||||
// Select the room to join
|
||||
await page.getByRole("treeitem", { name: "Room to Join" }).click();
|
||||
await page.getByRole("option", { name: "Open room Room to Join" }).click();
|
||||
|
||||
// Accept the invite
|
||||
await page.locator(".mx_RoomView").getByRole("button", { name: "Accept" }).click();
|
||||
|
||||
await checkOrder(["Room to Join", "Test Room"], page);
|
||||
await checkOrder(["Room to Rescind", "Room to Reject"], page);
|
||||
|
||||
// Select the room to reject
|
||||
await page.getByRole("treeitem", { name: "Room to Reject" }).click();
|
||||
await page.getByRole("option", { name: "Open room Room to Reject" }).click();
|
||||
|
||||
// Decline the invite
|
||||
await page.locator(".mx_RoomView").getByRole("button", { name: "Decline", exact: true }).click();
|
||||
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Invites" }).locator(".mx_RoomSublist_tiles").getByRole("treeitem"),
|
||||
).toHaveCount(2);
|
||||
await expect(page.getByTestId("room-list").getByRole("option")).toHaveCount(1);
|
||||
|
||||
// check the lists are correct
|
||||
await checkOrder(["Room to Join", "Test Room"], page);
|
||||
|
||||
const titleLocator = page.getByRole("group", { name: "Invites" }).locator(".mx_RoomTile_title");
|
||||
await expect(titleLocator).toHaveCount(1);
|
||||
await expect(titleLocator).toHaveText("Room to Rescind");
|
||||
await expect(page.getByRole("option", { name: "Open room Room to Rescind" })).toBeVisible();
|
||||
|
||||
// now rescind the invite
|
||||
await bot.evaluate(
|
||||
@@ -277,10 +276,14 @@ test.describe("Sliding Sync", () => {
|
||||
{ roomRescind, clientUserId },
|
||||
);
|
||||
|
||||
await page.getByRole("option", { name: "Open room Room to Rescind" }).click();
|
||||
|
||||
await page.locator(".mx_RoomView").getByRole("button", { name: "Forget this room", exact: true }).click();
|
||||
|
||||
await primaryFilters.getByRole("option", { name: "Invites" }).click();
|
||||
|
||||
// Wait for the rescind to take effect and check the joined list once more
|
||||
await expect(
|
||||
page.getByRole("group", { name: "Rooms" }).locator(".mx_RoomSublist_tiles").getByRole("treeitem"),
|
||||
).toHaveCount(2);
|
||||
await expect(page.getByTestId("room-list").getByRole("option")).toHaveCount(2);
|
||||
|
||||
await checkOrder(["Room to Join", "Test Room"], page);
|
||||
});
|
||||
@@ -293,19 +296,27 @@ test.describe("Sliding Sync", () => {
|
||||
await app.client.evaluate(async (client, roomId) => {
|
||||
await client.setRoomTag(roomId, "m.favourite", { order: 0.5 });
|
||||
}, roomId);
|
||||
await expect(page.getByRole("group", { name: "Favourites" }).getByText("Favourite DM")).toBeVisible();
|
||||
await expect(page.getByRole("group", { name: "People" }).getByText("Favourite DM")).not.toBeAttached();
|
||||
|
||||
await getFilterExpandButton(page).click();
|
||||
const primaryFilters = getPrimaryFilters(page);
|
||||
await primaryFilters.getByRole("option", { name: "Favourites" }).click();
|
||||
|
||||
await expect(page.getByRole("option", { name: "Favourite DM" })).toBeVisible();
|
||||
|
||||
await primaryFilters.getByRole("option", { name: "People" }).click();
|
||||
|
||||
await expect(page.getByRole("option", { name: "Favourite DM" })).not.toBeAttached();
|
||||
});
|
||||
|
||||
// Regression test for a bug in SS mode, but would be useful to have in non-SS mode too.
|
||||
// This ensures we are setting RoomViewStore state correctly.
|
||||
test("should clear the reply to field when swapping rooms", async ({ page, app, testRoom }) => {
|
||||
await app.client.createRoom({ name: "Other Room" });
|
||||
await expect(page.getByRole("treeitem", { name: "Other Room" })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: "Open room Other Room" })).toBeVisible();
|
||||
await app.client.sendMessage(testRoom.roomId, "Hello world");
|
||||
|
||||
// select the room
|
||||
await page.getByRole("treeitem", { name: "Test Room" }).click();
|
||||
await page.getByRole("option", { name: "Open room Test Room" }).click();
|
||||
|
||||
await expect(page.locator(".mx_ReplyPreview")).not.toBeAttached();
|
||||
|
||||
@@ -318,13 +329,13 @@ test.describe("Sliding Sync", () => {
|
||||
await expect(page.locator(".mx_ReplyPreview")).toBeVisible();
|
||||
|
||||
// now click Other Room
|
||||
await page.getByRole("treeitem", { name: "Other Room" }).click();
|
||||
await page.getByRole("option", { name: "Open room Other Room" }).click();
|
||||
|
||||
// ensure the reply-to disappears
|
||||
await expect(page.locator(".mx_ReplyPreview")).not.toBeAttached();
|
||||
|
||||
// click back
|
||||
await page.getByRole("treeitem", { name: "Test Room" }).click();
|
||||
await page.getByRole("option", { name: "Open room Test Room" }).click();
|
||||
|
||||
// ensure the reply-to reappears
|
||||
await expect(page.locator(".mx_ReplyPreview")).toBeVisible();
|
||||
@@ -338,7 +349,7 @@ test.describe("Sliding Sync", () => {
|
||||
await app.client.sendMessage(testRoom.roomId, "Reply to me");
|
||||
|
||||
// select the room
|
||||
await page.getByRole("treeitem", { name: "Test Room" }).click();
|
||||
await page.getByRole("option", { name: "Open room Test Room" }).click();
|
||||
await expect(page.locator(".mx_ReplyPreview")).not.toBeAttached();
|
||||
|
||||
// click reply-to on the Reply to me message
|
||||
|
||||
@@ -96,9 +96,9 @@ test.describe("Spaces", () => {
|
||||
await page.getByRole("button", { name: "Go to my first room" }).click();
|
||||
|
||||
// Assert rooms exist in the room list
|
||||
await expect(page.getByRole("treeitem", { name: "General" })).toBeVisible();
|
||||
await expect(page.getByRole("treeitem", { name: "Random" })).toBeVisible();
|
||||
await expect(page.getByRole("treeitem", { name: "Jokes" })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: "General" })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: "Random" })).toBeVisible();
|
||||
await expect(page.getByRole("option", { name: "Jokes" })).toBeVisible();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -127,10 +127,10 @@ test.describe("Spaces", () => {
|
||||
await page.getByRole("button", { name: "Skip for now" }).click();
|
||||
|
||||
// Assert rooms exist in the room list
|
||||
const roomList = page.getByRole("tree", { name: "Rooms" });
|
||||
await expect(roomList.getByRole("treeitem", { name: "General", exact: true })).toBeVisible();
|
||||
await expect(roomList.getByRole("treeitem", { name: "Random", exact: true })).toBeVisible();
|
||||
await expect(roomList.getByRole("treeitem", { name: "Projects", exact: true })).toBeVisible();
|
||||
const roomList = page.getByRole("listbox", { name: "Room list", exact: true });
|
||||
await expect(roomList.getByRole("option", { name: "General" })).toBeVisible();
|
||||
await expect(roomList.getByRole("option", { name: "Random" })).toBeVisible();
|
||||
await expect(roomList.getByRole("option", { name: "Projects" })).toBeVisible();
|
||||
|
||||
// Assert rooms exist in the space explorer
|
||||
await expect(
|
||||
@@ -200,7 +200,7 @@ test.describe("Spaces", () => {
|
||||
|
||||
await page.getByRole("button", { name: "Skip for now" }).click();
|
||||
|
||||
await page.getByRole("button", { name: "Add room" }).click();
|
||||
await page.getByRole("main").getByRole("button", { name: "Add" }).click();
|
||||
await page.getByRole("menuitem", { name: "Add existing room" }).click();
|
||||
|
||||
await page.getByRole("checkbox", { name: "Sample Room" }).click();
|
||||
@@ -424,10 +424,10 @@ test.describe("Spaces", () => {
|
||||
await page.getByRole("button", { name: "Skip for now" }).click();
|
||||
|
||||
// Assert rooms exist in the room list
|
||||
const roomList = page.getByRole("tree", { name: "Rooms" });
|
||||
await expect(roomList.getByRole("treeitem", { name: "General", exact: true })).toBeVisible();
|
||||
await expect(roomList.getByRole("treeitem", { name: "Random", exact: true })).toBeVisible();
|
||||
await expect(roomList.getByRole("treeitem", { name: "Projects", exact: true })).toBeVisible();
|
||||
const roomList = page.getByRole("listbox", { name: "Room list", exact: true });
|
||||
await expect(roomList.getByRole("option", { name: "General" })).toBeVisible();
|
||||
await expect(roomList.getByRole("option", { name: "Random" })).toBeVisible();
|
||||
await expect(roomList.getByRole("option", { name: "Projects" })).toBeVisible();
|
||||
|
||||
// Assert rooms exist in the space explorer
|
||||
await expect(
|
||||
|
||||
@@ -377,7 +377,7 @@ export class Helpers {
|
||||
* Expand the space panel
|
||||
*/
|
||||
expandSpacePanel() {
|
||||
return this.page.getByRole("button", { name: "Expand" }).click();
|
||||
return this.page.getByRole("navigation", { name: "Spaces" }).getByRole("button", { name: "Expand" }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ async function startDM(app: ElementAppPage, page: Page, name: string): Promise<v
|
||||
await locator.press("Enter");
|
||||
// The DM room is created at this point, this can take a little bit of time
|
||||
await expect(page.locator(".mx_EventTile_body").getByText("Hey!")).toBeAttached({ timeout: 3000 });
|
||||
await expect(page.getByRole("group", { name: "People" }).getByText(name)).toBeAttached();
|
||||
await expect(page.getByTestId("room-list").getByRole("option", { name: `Open room ${name}` })).toBeVisible();
|
||||
}
|
||||
|
||||
type RoomRef = { name: string; roomId: string };
|
||||
@@ -266,7 +266,9 @@ test.describe("Spotlight", () => {
|
||||
|
||||
// Assert DM exists by checking for the first message and the room being in the room list
|
||||
await expect(page.locator(".mx_EventTile_body").filter({ hasText: "Hey!" })).toBeAttached({ timeout: 3000 });
|
||||
await expect(page.getByRole("group", { name: "People" })).toContainText(bot2.credentials.displayName);
|
||||
await expect(
|
||||
page.getByTestId("room-list").getByRole("option", { name: `Open room ${bot2.credentials.displayName}` }),
|
||||
).toBeVisible();
|
||||
|
||||
// Invite BotBob into existing DM with ByteBot
|
||||
const dmRooms = await app.client.evaluate((client, userId) => {
|
||||
@@ -279,7 +281,9 @@ test.describe("Spotlight", () => {
|
||||
const groupDmName = await app.client.evaluate((client, id) => client.getRoom(id).name, dmRooms[0]);
|
||||
await app.client.inviteUser(dmRooms[0], bot1.credentials.userId);
|
||||
await expect(roomHeaderName(page).first()).toContainText(groupDmName);
|
||||
await expect(page.getByRole("group", { name: "People" }).first()).toContainText(groupDmName);
|
||||
await expect(
|
||||
page.getByTestId("room-list").getByRole("option", { name: `Open room ${groupDmName}` }),
|
||||
).toBeVisible();
|
||||
|
||||
// Search for BotBob by id, should return group DM and user
|
||||
spotlight = await app.openSpotlight();
|
||||
|
||||
@@ -50,9 +50,12 @@ test.describe("Media preview settings", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
await expect(
|
||||
page.getByRole("tree", { name: "Rooms" }).getByRole("treeitem", { name: "Test room" }),
|
||||
).toMatchScreenshot("invite-room-tree-no-avatar.png");
|
||||
|
||||
const testRoomTile = page
|
||||
.getByRole("listbox", { name: "Room list" })
|
||||
.getByRole("option", { name: "Test room" });
|
||||
await expect(testRoomTile).toBeVisible();
|
||||
await expect(testRoomTile).toMatchScreenshot("invite-room-tree-no-avatar.png");
|
||||
|
||||
// And then go back to being visible
|
||||
settings = await app.settings.openUserSettings("Preferences");
|
||||
@@ -70,9 +73,7 @@ test.describe("Media preview settings", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
await expect(
|
||||
page.getByRole("tree", { name: "Rooms" }).getByRole("treeitem", { name: "Test room" }),
|
||||
).toMatchScreenshot("invite-room-tree-with-avatar.png");
|
||||
await expect(testRoomTile).toMatchScreenshot("invite-room-tree-with-avatar.png");
|
||||
});
|
||||
|
||||
test("should be able to hide media in rooms globally", async ({ page, app, room, user }) => {
|
||||
|
||||
@@ -24,7 +24,7 @@ test.describe("PSTN", () => {
|
||||
await toasts.rejectToast("Notifications");
|
||||
await toasts.assertNoToasts();
|
||||
|
||||
await expect(page.locator(".mx_LeftPanel_filterContainer")).toMatchScreenshot("dialpad-trigger.png");
|
||||
await expect(page.locator(".mx_RoomListSearch")).toMatchScreenshot("dialpad-trigger.png");
|
||||
await page.getByLabel("Open dial pad").click();
|
||||
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("dialpad.png");
|
||||
});
|
||||
|
||||
@@ -51,9 +51,10 @@ export class ElementAppPage {
|
||||
/**
|
||||
* Open room creation dialog.
|
||||
*/
|
||||
|
||||
public async openCreateRoomDialog(roomKindname: "New room" | "New video room" = "New room"): Promise<Locator> {
|
||||
await this.page.getByRole("button", { name: "Add room", exact: true }).click();
|
||||
await this.page.getByRole("menuitem", { name: roomKindname, exact: true }).click();
|
||||
await this.page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "Add" }).click();
|
||||
await this.page.getByRole("menuitem", { name: roomKindname }).click();
|
||||
return this.page.locator(".mx_CreateRoomDialog");
|
||||
}
|
||||
|
||||
@@ -70,12 +71,23 @@ export class ElementAppPage {
|
||||
|
||||
/**
|
||||
* Opens the given room by name. The room must be visible in the
|
||||
* room list and the room may contain unread messages.
|
||||
*
|
||||
* @param name The exact room name to find and click on/open.
|
||||
*/
|
||||
public async viewRoomByName(name: string): Promise<void> {
|
||||
// We get the room list by test-id which is a listbox and matching title=name
|
||||
return this.page.getByTestId("room-list").locator(`[title="${name}"]`).first().click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the given room on the old room list by name. The room must be visible in the
|
||||
* room list, but the room list may be folded horizontally, and the
|
||||
* room may contain unread messages.
|
||||
*
|
||||
* @param name The exact room name to find and click on/open.
|
||||
*/
|
||||
public async viewRoomByName(name: string): Promise<void> {
|
||||
public async viewRoomByNameOnOldRoomList(name: string): Promise<void> {
|
||||
// We look for the room inside the room list, which is a tree called Rooms.
|
||||
//
|
||||
// There are 3 cases:
|
||||
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 77 KiB |