mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2025-12-30 11:22:31 +00:00
feat(tests): Adds avatar test. (#15382)
* feat(tests): Adds join options. * fix(tests): Fix opening tests by default with tenant. * fix(tests): Renames a method. * fix(tests): Moves a method from filmstrip to participants pane. * fix(tests): Adds ok button to base dialog. * fix(tests): Adds missing checks for using iframe API. * feat(tests): Prettify the result html on error. * fix(tests): Fixes checking when not in room. * fix(tests): Adds profile button to toolbar. * fix(tests): Adds avatar test. * fix(tests): Fix all execute methods and await. * fix(tests): Fix avatar checks.
This commit is contained in:
449
package-lock.json
generated
449
package-lock.json
generated
@@ -140,6 +140,7 @@
|
||||
"@types/moment-duration-format": "2.2.6",
|
||||
"@types/offscreencanvas": "2019.7.2",
|
||||
"@types/pixelmatch": "5.2.5",
|
||||
"@types/pretty": "2.0.3",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-dom": "17.0.14",
|
||||
@@ -176,6 +177,7 @@
|
||||
"jsonwebtoken": "9.0.2",
|
||||
"metro-react-native-babel-preset": "0.77.0",
|
||||
"patch-package": "6.4.7",
|
||||
"pretty": "2.0.0",
|
||||
"process": "0.11.10",
|
||||
"sass": "1.26.8",
|
||||
"style-loader": "3.3.1",
|
||||
@@ -4661,6 +4663,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@one-ini/wasm": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
||||
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@@ -7219,6 +7227,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pretty": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/pretty/-/pretty-2.0.3.tgz",
|
||||
"integrity": "sha512-xR96pShNlrxLd3gZqzCnbaAmbYhiRYjW51CDFjektZemqpBZBAAkMwxm4gBraJP/xSgKcsQhLXdlXOwDNWo4VQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
@@ -8659,6 +8673,15 @@
|
||||
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
||||
"deprecated": "Use your platform's native atob() and btoa() methods instead"
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
|
||||
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
@@ -10624,6 +10647,42 @@
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"node_modules/condense-newlines": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz",
|
||||
"integrity": "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-whitespace": "^0.3.0",
|
||||
"kind-of": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/condense-newlines/node_modules/kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-buffer": "^1.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/config-chain": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
||||
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ini": "^1.3.4",
|
||||
"proto-list": "~1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/connect": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
|
||||
@@ -11573,6 +11632,57 @@
|
||||
"node": "^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/editorconfig": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz",
|
||||
"integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@one-ini/wasm": "0.1.1",
|
||||
"commander": "^10.0.0",
|
||||
"minimatch": "9.0.1",
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"bin": {
|
||||
"editorconfig": "bin/editorconfig"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/editorconfig/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/editorconfig/node_modules/commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/editorconfig/node_modules/minimatch": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
|
||||
"integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -12922,6 +13032,18 @@
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"node_modules/extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extendable": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/external-editor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||
@@ -14451,6 +14573,12 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/inline-style-prefixer": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz",
|
||||
@@ -14708,6 +14836,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extendable": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
||||
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@@ -14987,6 +15124,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-whitespace": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz",
|
||||
"integrity": "sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-wsl": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||
@@ -15754,6 +15900,80 @@
|
||||
"resolved": "https://registry.npmjs.org/jquery-i18next/-/jquery-i18next-1.2.1.tgz",
|
||||
"integrity": "sha512-UNcw3rgxoKjGEg4w23FEn2h3OlPJU7rPzsgDuXDBZktIzeiVbJohs9Cv9hj8oP8KNfBRKOoErL/OVxg2FaAR4g=="
|
||||
},
|
||||
"node_modules/js-beautify": {
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz",
|
||||
"integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"config-chain": "^1.1.13",
|
||||
"editorconfig": "^1.0.4",
|
||||
"glob": "^10.3.3",
|
||||
"js-cookie": "^3.0.5",
|
||||
"nopt": "^7.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"css-beautify": "js/bin/css-beautify.js",
|
||||
"html-beautify": "js/bin/html-beautify.js",
|
||||
"js-beautify": "js/bin/js-beautify.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||
@@ -17945,6 +18165,21 @@
|
||||
"url": "https://github.com/sponsors/antelle"
|
||||
}
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
|
||||
"integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"abbrev": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-package-data": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
|
||||
@@ -18909,6 +19144,20 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz",
|
||||
"integrity": "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"condense-newlines": "^0.2.1",
|
||||
"extend-shallow": "^2.0.1",
|
||||
"js-beautify": "^1.6.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
|
||||
@@ -19040,6 +19289,12 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proto-list": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
||||
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@@ -27445,6 +27700,12 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@one-ini/wasm": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
||||
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
|
||||
"dev": true
|
||||
},
|
||||
"@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@@ -29247,6 +29508,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/pretty": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/pretty/-/pretty-2.0.3.tgz",
|
||||
"integrity": "sha512-xR96pShNlrxLd3gZqzCnbaAmbYhiRYjW51CDFjektZemqpBZBAAkMwxm4gBraJP/xSgKcsQhLXdlXOwDNWo4VQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
@@ -30332,6 +30599,12 @@
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
|
||||
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
|
||||
"dev": true
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
@@ -31769,6 +32042,38 @@
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"condense-newlines": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz",
|
||||
"integrity": "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-whitespace": "^0.3.0",
|
||||
"kind-of": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"config-chain": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
||||
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ini": "^1.3.4",
|
||||
"proto-list": "~1.2.1"
|
||||
}
|
||||
},
|
||||
"connect": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
|
||||
@@ -32449,6 +32754,44 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"editorconfig": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz",
|
||||
"integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@one-ini/wasm": "0.1.1",
|
||||
"commander": "^10.0.0",
|
||||
"minimatch": "9.0.1",
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
|
||||
"integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -33435,6 +33778,15 @@
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"external-editor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||
@@ -34547,6 +34899,12 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true
|
||||
},
|
||||
"inline-style-prefixer": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz",
|
||||
@@ -34733,6 +35091,12 @@
|
||||
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
|
||||
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="
|
||||
},
|
||||
"is-extendable": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
||||
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
|
||||
"dev": true
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@@ -34897,6 +35261,12 @@
|
||||
"call-bind": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"is-whitespace": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz",
|
||||
"integrity": "sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-wsl": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||
@@ -35454,6 +35824,59 @@
|
||||
"resolved": "https://registry.npmjs.org/jquery-i18next/-/jquery-i18next-1.2.1.tgz",
|
||||
"integrity": "sha512-UNcw3rgxoKjGEg4w23FEn2h3OlPJU7rPzsgDuXDBZktIzeiVbJohs9Cv9hj8oP8KNfBRKOoErL/OVxg2FaAR4g=="
|
||||
},
|
||||
"js-beautify": {
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz",
|
||||
"integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"config-chain": "^1.1.13",
|
||||
"editorconfig": "^1.0.4",
|
||||
"glob": "^10.3.3",
|
||||
"js-cookie": "^3.0.5",
|
||||
"nopt": "^7.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
}
|
||||
},
|
||||
"js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"js-cookie": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||
@@ -37117,6 +37540,15 @@
|
||||
"resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz",
|
||||
"integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw=="
|
||||
},
|
||||
"nopt": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
|
||||
"integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"abbrev": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
|
||||
@@ -37784,6 +38216,17 @@
|
||||
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz",
|
||||
"integrity": "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"condense-newlines": "^0.2.1",
|
||||
"extend-shallow": "^2.0.1",
|
||||
"js-beautify": "^1.6.12"
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
|
||||
@@ -37885,6 +38328,12 @@
|
||||
"integrity": "sha512-qYNxyMj1JeW54i/EWEFsM1cVwxJbtgPp8+0Wg9XjNaK6VE/c4oRi6PNu5p7w1mNXEIQIjV5Wwn8v8Gz82/QzdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"proto-list": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
||||
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
|
||||
"dev": true
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
|
||||
@@ -146,6 +146,7 @@
|
||||
"@types/moment-duration-format": "2.2.6",
|
||||
"@types/offscreencanvas": "2019.7.2",
|
||||
"@types/pixelmatch": "5.2.5",
|
||||
"@types/pretty": "2.0.3",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-dom": "17.0.14",
|
||||
@@ -182,6 +183,7 @@
|
||||
"jsonwebtoken": "9.0.2",
|
||||
"metro-react-native-babel-preset": "0.77.0",
|
||||
"patch-package": "6.4.7",
|
||||
"pretty": "2.0.0",
|
||||
"process": "0.11.10",
|
||||
"sass": "1.26.8",
|
||||
"style-loader": "3.3.1",
|
||||
|
||||
@@ -106,7 +106,8 @@ const StageParticipantNameLabel = () => {
|
||||
classes.badgeContainer,
|
||||
toolboxVisible && classes.containerElevated,
|
||||
_isScreenShareParticipant && classes.screenSharing
|
||||
) }>
|
||||
) }
|
||||
data-testid = 'stage-display-name' >
|
||||
<DisplayNameBadge name = { nameToDisplay } />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,11 +7,12 @@ import { urlObjectToString } from '../../react/features/base/util/uri';
|
||||
import Filmstrip from '../pageobjects/Filmstrip';
|
||||
import IframeAPI from '../pageobjects/IframeAPI';
|
||||
import ParticipantsPane from '../pageobjects/ParticipantsPane';
|
||||
import SettingsDialog from '../pageobjects/SettingsDialog';
|
||||
import Toolbar from '../pageobjects/Toolbar';
|
||||
import VideoQualityDialog from '../pageobjects/VideoQualityDialog';
|
||||
|
||||
import { LOG_PREFIX, logInfo } from './browserLogger';
|
||||
import { IContext } from './types';
|
||||
import { IContext, IJoinOptions } from './types';
|
||||
|
||||
/**
|
||||
* Participant.
|
||||
@@ -112,21 +113,25 @@ export class Participant {
|
||||
* Joins conference.
|
||||
*
|
||||
* @param {IContext} context - The context.
|
||||
* @param {boolean} skipInMeetingChecks - Whether to skip in meeting checks.
|
||||
* @param {IJoinOptions} options - Options for joining.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async joinConference(context: IContext, skipInMeetingChecks = false): Promise<void> {
|
||||
async joinConference(context: IContext, options: IJoinOptions = {}): Promise<void> {
|
||||
const config = {
|
||||
room: context.roomName,
|
||||
configOverwrite: this.config,
|
||||
interfaceConfigOverwrite: {
|
||||
SHOW_CHROME_EXTENSION_BANNER: false
|
||||
},
|
||||
userInfo: {
|
||||
displayName: this._name
|
||||
}
|
||||
};
|
||||
|
||||
if (!options.skipDisplayName) {
|
||||
// @ts-ignore
|
||||
config.userInfo = {
|
||||
displayName: this._name
|
||||
};
|
||||
}
|
||||
|
||||
if (context.iframeAPI) {
|
||||
config.room = 'iframeAPITest.html';
|
||||
}
|
||||
@@ -168,7 +173,7 @@ export class Participant {
|
||||
|
||||
await this.waitToJoinMUC();
|
||||
|
||||
await this.postLoadProcess(skipInMeetingChecks);
|
||||
await this.postLoadProcess(options.skipInMeetingChecks);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +183,7 @@ export class Participant {
|
||||
* @returns {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
private async postLoadProcess(skipInMeetingChecks: boolean): Promise<void> {
|
||||
private async postLoadProcess(skipInMeetingChecks = false): Promise<void> {
|
||||
const driver = this.driver;
|
||||
|
||||
const parallel = [];
|
||||
@@ -227,7 +232,7 @@ export class Participant {
|
||||
*/
|
||||
async waitForPageToLoad(): Promise<void> {
|
||||
return this.driver.waitUntil(
|
||||
() => this.driver.execute(() => document.readyState === 'complete'),
|
||||
async () => await this.driver.execute(() => document.readyState === 'complete'),
|
||||
{
|
||||
timeout: 30_000, // 30 seconds
|
||||
timeoutMsg: 'Timeout waiting for Page Load Request to complete.'
|
||||
@@ -238,8 +243,8 @@ export class Participant {
|
||||
/**
|
||||
* Checks if the participant is in the meeting.
|
||||
*/
|
||||
isInMuc() {
|
||||
return this.driver.execute(() => APP.conference.isJoined());
|
||||
async isInMuc() {
|
||||
return await this.driver.execute(() => typeof APP !== 'undefined' && APP.conference?.isJoined());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,7 +271,7 @@ export class Participant {
|
||||
const driver = this.driver;
|
||||
|
||||
return driver.waitUntil(async () =>
|
||||
driver.execute(() => APP.conference.getConnectionState() === 'connected'), {
|
||||
await driver.execute(() => APP.conference.getConnectionState() === 'connected'), {
|
||||
timeout: 15_000,
|
||||
timeoutMsg: 'expected ICE to be connected for 15s'
|
||||
});
|
||||
@@ -281,7 +286,7 @@ export class Participant {
|
||||
const driver = this.driver;
|
||||
|
||||
return driver.waitUntil(async () =>
|
||||
driver.execute(() => {
|
||||
await driver.execute(() => {
|
||||
const stats = APP.conference.getStats();
|
||||
const bitrateMap = stats?.bitrate || {};
|
||||
const rtpStats = {
|
||||
@@ -306,7 +311,7 @@ export class Participant {
|
||||
const driver = this.driver;
|
||||
|
||||
return driver.waitUntil(async () =>
|
||||
driver.execute(count => APP.conference.getNumberOfParticipantsWithTracks() >= count, number), {
|
||||
await driver.execute(count => APP.conference.getNumberOfParticipantsWithTracks() >= count, number), {
|
||||
timeout: 15_000,
|
||||
timeoutMsg: 'expected remote streams in 15s'
|
||||
});
|
||||
@@ -348,6 +353,15 @@ export class Participant {
|
||||
return new VideoQualityDialog(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings Dialog.
|
||||
*
|
||||
* @returns {SettingsDialog}
|
||||
*/
|
||||
getSettingsDialog(): SettingsDialog {
|
||||
return new SettingsDialog(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to the iframe API context
|
||||
*/
|
||||
@@ -371,6 +385,13 @@ export class Participant {
|
||||
return new IframeAPI(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hangups the participant by leaving the page. base.html is an empty page on all deployments.
|
||||
*/
|
||||
async hangup() {
|
||||
await this.driver.url('/base.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local display name.
|
||||
*/
|
||||
@@ -383,4 +404,92 @@ export class Participant {
|
||||
|
||||
return await localDisplayName.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets avatar SRC attribute for the one displayed on local video thumbnail.
|
||||
*/
|
||||
async getLocalVideoAvatar() {
|
||||
const avatar
|
||||
= this.driver.$('//span[@id="localVideoContainer"]//img[contains(@class,"userAvatar")]');
|
||||
|
||||
return await avatar.isExisting() ? await avatar.getAttribute('src') : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets avatar SRC attribute for the one displayed on large video.
|
||||
*/
|
||||
async getLargeVideoAvatar() {
|
||||
const avatar = this.driver.$('//img[@id="dominantSpeakerAvatar"]');
|
||||
|
||||
return await avatar.isExisting() ? await avatar.getAttribute('src') : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns resource part of the JID of the user who is currently displayed in the large video area.
|
||||
*/
|
||||
async getLargeVideoResource() {
|
||||
return await this.driver.execute(() => APP.UI.getLargeVideoID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the avatar is displayed in the local thumbnail and that the video is not displayed.
|
||||
* There are 3 options for avatar:
|
||||
* - defaultAvatar: true - the default avatar (with grey figure) is used
|
||||
* - image: true - the avatar is an image set in the settings
|
||||
* - defaultAvatar: false, image: false - the avatar is produced from the initials of the display name
|
||||
*/
|
||||
async assertThumbnailShowsAvatar(
|
||||
participant: Participant, reverse = false, defaultAvatar = false, image = false): Promise<void> {
|
||||
const id = participant === this
|
||||
? 'localVideoContainer' : `participant_${await participant.getEndpointId()}`;
|
||||
|
||||
const xpath = defaultAvatar
|
||||
? `//span[@id='${id}']//div[contains(@class,'userAvatar') and contains(@class, 'defaultAvatar')]`
|
||||
: `//span[@id="${id}"]//${image ? 'img' : 'div'}[contains(@class,"userAvatar")]`;
|
||||
|
||||
await this.driver.$(xpath).waitForDisplayed({
|
||||
reverse,
|
||||
timeout: 2000,
|
||||
timeoutMsg: `Avatar is ${reverse ? '' : 'not'} displayed in the local thumbnail for ${participant.name}`
|
||||
});
|
||||
|
||||
await this.driver.$(`//span[@id="${id}"]//video`).waitForDisplayed({
|
||||
reverse: !reverse,
|
||||
timeout: 2000,
|
||||
timeoutMsg: `Video is ${reverse ? 'not' : ''} displayed in the local thumbnail for ${participant.name}`
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the default avatar is used.
|
||||
*/
|
||||
async assertDefaultAvatarExist(participant: Participant): Promise<void> {
|
||||
const id = participant === this
|
||||
? 'localVideoContainer' : `participant_${await participant.getEndpointId()}`;
|
||||
|
||||
await this.driver.$(
|
||||
`//span[@id='${id}']//div[contains(@class,'userAvatar') and contains(@class, 'defaultAvatar')]`)
|
||||
.waitForExist({
|
||||
timeout: 2000,
|
||||
timeoutMsg: `Default avatar does not exist for ${participant.name}`
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the local video is displayed in the local thumbnail and that the avatar is not displayed.
|
||||
*/
|
||||
async asserLocalThumbnailShowsVideo(): Promise<void> {
|
||||
await this.assertThumbnailShowsAvatar(this, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure a display name is visible on the stage.
|
||||
* @param value
|
||||
*/
|
||||
async assertDisplayNameVisibleOnStage(value: string) {
|
||||
const displayNameEl = this.driver.$('div[data-testid="stage-display-name"]');
|
||||
|
||||
expect(await displayNameEl.isDisplayed()).toBeTrue();
|
||||
expect(await displayNameEl.getText()).toBe(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { Participant } from './Participant';
|
||||
import WebhookProxy from './WebhookProxy';
|
||||
import { IContext } from './types';
|
||||
import { IContext, IJoinOptions } from './types';
|
||||
|
||||
/**
|
||||
* Generate a random room name.
|
||||
@@ -31,16 +31,20 @@ function generateRandomRoomName(): string {
|
||||
* Ensure that there is on participant.
|
||||
*
|
||||
* @param {IContext} context - The context.
|
||||
* @param {IJoinOptions} options - The options to use when joining the participant.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function ensureOneParticipant(context: IContext): Promise<void> {
|
||||
export async function ensureOneParticipant(context: IContext, options?: IJoinOptions): Promise<void> {
|
||||
if (!context.roomName) {
|
||||
context.roomName = generateRandomRoomName();
|
||||
}
|
||||
|
||||
context.p1 = new Participant('participant1');
|
||||
|
||||
await context.p1.joinConference(context, true);
|
||||
await context.p1.joinConference(context, {
|
||||
...options,
|
||||
skipInMeetingChecks: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,9 +84,10 @@ export async function ensureThreeParticipants(context: IContext): Promise<void>
|
||||
* Ensure that there are two participants.
|
||||
*
|
||||
* @param {Object} context - The context.
|
||||
* @param {IJoinOptions} options - The options to join.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function ensureTwoParticipants(context: IContext): Promise<void> {
|
||||
export async function ensureTwoParticipants(context: IContext, options?: IJoinOptions): Promise<void> {
|
||||
if (!context.roomName) {
|
||||
context.roomName = generateRandomRoomName();
|
||||
}
|
||||
@@ -98,12 +103,15 @@ export async function ensureTwoParticipants(context: IContext): Promise<void> {
|
||||
// make sure the first participant is moderator, if supported by deployment
|
||||
await _joinParticipant(p1DisplayName, context.p1, p => {
|
||||
context.p1 = p;
|
||||
}, true, token);
|
||||
}, {
|
||||
...options,
|
||||
skipInMeetingChecks: true
|
||||
}, token);
|
||||
|
||||
await Promise.all([
|
||||
_joinParticipant('participant2', context.p2, p => {
|
||||
context.p2 = p;
|
||||
}),
|
||||
}, options),
|
||||
context.p1.waitForRemoteStreams(1),
|
||||
context.p2.waitForRemoteStreams(1)
|
||||
]);
|
||||
@@ -114,24 +122,28 @@ export async function ensureTwoParticipants(context: IContext): Promise<void> {
|
||||
* @param name - The name of the participant.
|
||||
* @param p - The participant instance to prepare or undefined if new one is needed.
|
||||
* @param setter - The setter to use for setting the new participant instance into the context if needed.
|
||||
* @param {boolean} skipInMeetingChecks - Whether to skip in meeting checks.
|
||||
* @param {boolean} options - Join options.
|
||||
* @param {string?} jwtToken - The token to use if any.
|
||||
*/
|
||||
async function _joinParticipant( // eslint-disable-line max-params
|
||||
name: string,
|
||||
p: Participant,
|
||||
setter: (p: Participant) => void,
|
||||
skipInMeetingChecks = false,
|
||||
options: IJoinOptions = {},
|
||||
jwtToken?: string) {
|
||||
if (p) {
|
||||
await p.switchInPage();
|
||||
if (context.iframeAPI) {
|
||||
await p.switchInPage();
|
||||
}
|
||||
|
||||
if (await p.isInMuc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// when loading url make sure we are on the top page context or strange errors may occur
|
||||
await p.switchToAPI();
|
||||
if (context.iframeAPI) {
|
||||
// when loading url make sure we are on the top page context or strange errors may occur
|
||||
await p.switchToAPI();
|
||||
}
|
||||
|
||||
// Change the page so we can reload same url if we need to, base.html is supposed to be empty or close to empty
|
||||
await p.driver.url('/base.html');
|
||||
@@ -144,7 +156,7 @@ async function _joinParticipant( // eslint-disable-line max-params
|
||||
// set the new participant instance, pass it to setter
|
||||
setter(newParticipant);
|
||||
|
||||
return newParticipant.joinConference(context, skipInMeetingChecks);
|
||||
await newParticipant.joinConference(context, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,13 +169,25 @@ async function _joinParticipant( // eslint-disable-line max-params
|
||||
* the mute state of {@code testee}.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function toggleMuteAndCheck(testee: Participant, observer: Participant): Promise<void> {
|
||||
export async function muteAudioAndCheck(testee: Participant, observer: Participant): Promise<void> {
|
||||
await testee.getToolbar().clickAudioMuteButton();
|
||||
|
||||
await observer.getFilmstrip().assertAudioMuteIconIsDisplayed(testee);
|
||||
await testee.getFilmstrip().assertAudioMuteIconIsDisplayed(testee);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the video on testee and check on observer.
|
||||
* @param testee
|
||||
* @param observer
|
||||
*/
|
||||
export async function unMuteVideoAndCheck(testee: Participant, observer: Participant): Promise<void> {
|
||||
await testee.getToolbar().clickVideoUnmuteButton();
|
||||
|
||||
await observer.getParticipantsPane().assertVideoMuteIconIsDisplayed(testee, true);
|
||||
await testee.getParticipantsPane().assertVideoMuteIconIsDisplayed(testee, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JWT token for a moderator.
|
||||
*/
|
||||
|
||||
@@ -13,3 +13,16 @@ export type IContext = {
|
||||
roomName: string;
|
||||
webhooksProxy: WebhookProxy;
|
||||
};
|
||||
|
||||
export type IJoinOptions = {
|
||||
|
||||
/**
|
||||
* Whether to skip setting display name.
|
||||
*/
|
||||
skipDisplayName?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to skip in meeting checks like ice connected and send receive data. For single in meeting participant.
|
||||
*/
|
||||
skipInMeetingChecks?: boolean;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Participant } from '../helpers/Participant';
|
||||
|
||||
const CLOSE_BUTTON = 'modal-header-close-button';
|
||||
const OK_BUTTON = 'modal-dialog-ok-button';
|
||||
|
||||
/**
|
||||
* Base class for all dialogs.
|
||||
@@ -23,4 +24,11 @@ export default class BaseDialog {
|
||||
async clickCloseButton(): Promise<void> {
|
||||
await this.participant.driver.$(`#${CLOSE_BUTTON}`).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the ok button.
|
||||
*/
|
||||
async clickOkButton(): Promise<void> {
|
||||
await this.participant.driver.$(`#${OK_BUTTON}`).click();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,37 +44,6 @@ export default class Filmstrip {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@code participant} shows or doesn't show the video mute icon for the conference participant
|
||||
* identified by {@code testee}.
|
||||
*
|
||||
* @param {Participant} testee - The {@code Participant} for whom we're checking the status of audio muted icon.
|
||||
* @param {boolean} reverse - If {@code true}, the method will assert the absence of the "mute" icon;
|
||||
* otherwise, it will assert its presence.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async assertVideoMuteIconIsDisplayed(testee: Participant, reverse = false): Promise<void> {
|
||||
const isOpen = await this.participant.getParticipantsPane().isOpen();
|
||||
|
||||
if (!isOpen) {
|
||||
await this.participant.getParticipantsPane().open();
|
||||
}
|
||||
|
||||
const id = `participant-item-${await testee.getEndpointId()}`;
|
||||
const mutedIconXPath
|
||||
= `//div[@id='${id}']//div[contains(@class, 'indicators')]//*[local-name()='svg' and @id='videoMuted']`;
|
||||
|
||||
await this.participant.driver.$(mutedIconXPath).waitForDisplayed({
|
||||
reverse,
|
||||
timeout: 2000,
|
||||
timeoutMsg: `Video mute icon is ${reverse ? '' : 'not'} displayed for ${testee.name}`
|
||||
});
|
||||
|
||||
if (!isOpen) {
|
||||
await this.participant.getParticipantsPane().close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remote display name for an endpoint.
|
||||
* @param endpointId The endpoint id.
|
||||
@@ -86,4 +55,26 @@ export default class Filmstrip {
|
||||
|
||||
return await remoteDisplayName.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a participant by clicking on their thumbnail.
|
||||
* @param participant The participant.
|
||||
*/
|
||||
async pinParticipant(participant: Participant) {
|
||||
const id = participant === this.participant
|
||||
? 'localVideoContainer' : `participant_${await participant.getEndpointId()}`;
|
||||
|
||||
await this.participant.driver.$(`//span[@id="${id}"]`).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets avatar SRC attribute for the one displayed on small video thumbnail.
|
||||
* @param endpointId
|
||||
*/
|
||||
async getAvatar(endpointId: string) {
|
||||
const elem = this.participant.driver.$(
|
||||
`//span[@id='participant_${endpointId}']//img[contains(@class,'userAvatar')]`);
|
||||
|
||||
return await elem.isExisting() ? elem.getAttribute('src') : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class IframeAPI {
|
||||
* @param event
|
||||
*/
|
||||
async getEventResult(event: string): Promise<any> {
|
||||
return this.participant.driver.execute(
|
||||
return await this.participant.driver.execute(
|
||||
eventName => {
|
||||
const result = window.jitsiAPI.test[eventName];
|
||||
|
||||
@@ -37,28 +37,29 @@ export default class IframeAPI {
|
||||
* @param eventName The event name.
|
||||
*/
|
||||
async addEventListener(eventName: string) {
|
||||
return this.participant.driver.executeAsync((event, prefix, done) => {
|
||||
console.log(`${new Date().toISOString()} ${prefix} Adding listener for event: ${event}`);
|
||||
window.jitsiAPI.addListener(event, evt => {
|
||||
console.log(`${new Date().toISOString()} ${prefix} Received ${event} event: ${JSON.stringify(evt)}`);
|
||||
window.jitsiAPI.test[event] = evt;
|
||||
});
|
||||
done();
|
||||
}, eventName, LOG_PREFIX);
|
||||
return await this.participant.driver.execute(
|
||||
(event, prefix) => {
|
||||
console.log(`${new Date().toISOString()} ${prefix} Adding listener for event: ${event}`);
|
||||
window.jitsiAPI.addListener(event, evt => {
|
||||
console.log(
|
||||
`${new Date().toISOString()} ${prefix} Received ${event} event: ${JSON.stringify(evt)}`);
|
||||
window.jitsiAPI.test[event] = evt;
|
||||
});
|
||||
}, eventName, LOG_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of available rooms and details of it.
|
||||
*/
|
||||
async getRoomsInfo() {
|
||||
return this.participant.driver.execute(() => window.jitsiAPI.getRoomsInfo());
|
||||
return await this.participant.driver.execute(() => window.jitsiAPI.getRoomsInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of participants in the conference.
|
||||
*/
|
||||
async getNumberOfParticipants() {
|
||||
return this.participant.driver.execute(() => window.jitsiAPI.getNumberOfParticipants());
|
||||
return await this.participant.driver.execute(() => window.jitsiAPI.getNumberOfParticipants());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +68,7 @@ export default class IframeAPI {
|
||||
* @param args The arguments.
|
||||
*/
|
||||
async executeCommand(command: string, ...args: any[]) {
|
||||
return this.participant.driver.execute(
|
||||
return await this.participant.driver.execute(
|
||||
(commandName, commandArgs) =>
|
||||
window.jitsiAPI.executeCommand(commandName, ...commandArgs)
|
||||
, command, args);
|
||||
@@ -77,14 +78,14 @@ export default class IframeAPI {
|
||||
* Returns the current state of the participant's pane.
|
||||
*/
|
||||
async isParticipantsPaneOpen() {
|
||||
return this.participant.driver.execute(() => window.jitsiAPI.isParticipantsPaneOpen());
|
||||
return await this.participant.driver.execute(() => window.jitsiAPI.isParticipantsPaneOpen());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the embedded Jitsi Meet conference.
|
||||
*/
|
||||
async dispose() {
|
||||
return this.participant.driver.execute(() => window.jitsiAPI.dispose());
|
||||
return await this.participant.driver.execute(() => window.jitsiAPI.dispose());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,4 +44,35 @@ export default class ParticipantsPane {
|
||||
|
||||
await this.participant.driver.$(`.${PARTICIPANTS_PANE}`).waitForDisplayed({ reverse: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@code participant} shows or doesn't show the video mute icon for the conference participant
|
||||
* identified by {@code testee}.
|
||||
*
|
||||
* @param {Participant} testee - The {@code Participant} for whom we're checking the status of audio muted icon.
|
||||
* @param {boolean} reverse - If {@code true}, the method will assert the absence of the "mute" icon;
|
||||
* otherwise, it will assert its presence.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async assertVideoMuteIconIsDisplayed(testee: Participant, reverse = false): Promise<void> {
|
||||
const isOpen = await this.isOpen();
|
||||
|
||||
if (!isOpen) {
|
||||
await this.open();
|
||||
}
|
||||
|
||||
const id = `participant-item-${await testee.getEndpointId()}`;
|
||||
const mutedIconXPath
|
||||
= `//div[@id='${id}']//div[contains(@class, 'indicators')]//*[local-name()='svg' and @id='videoMuted']`;
|
||||
|
||||
await this.participant.driver.$(mutedIconXPath).waitForDisplayed({
|
||||
reverse,
|
||||
timeout: 2000,
|
||||
timeoutMsg: `Video mute icon is ${reverse ? '' : 'not'} displayed for ${testee.name}`
|
||||
});
|
||||
|
||||
if (!isOpen) {
|
||||
await this.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
62
tests/pageobjects/SettingsDialog.ts
Normal file
62
tests/pageobjects/SettingsDialog.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import BaseDialog from './BaseDialog';
|
||||
|
||||
const EMAIL_FIELD = '#setEmail';
|
||||
const SETTINGS_DIALOG_CONTENT = '.settings-pane';
|
||||
const X_PATH_PROFILE_TAB = '//div[contains(@class, "settings-dialog")]//*[text()="Profile"]';
|
||||
|
||||
/**
|
||||
* The settings dialog.
|
||||
*/
|
||||
export default class SettingsDialog extends BaseDialog {
|
||||
/**
|
||||
* Waits for the settings dialog to be visible.
|
||||
*/
|
||||
async waitForDisplay() {
|
||||
await this.participant.driver.$(SETTINGS_DIALOG_CONTENT).waitForDisplayed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a specific tab in the settings dialog.
|
||||
* @param xpath
|
||||
* @private
|
||||
*/
|
||||
private async openTab(xpath: string) {
|
||||
const elem = this.participant.driver.$(xpath);
|
||||
|
||||
await elem.waitForClickable();
|
||||
await elem.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the Profile tab to be displayed.
|
||||
*/
|
||||
async openProfileTab() {
|
||||
await this.openTab(X_PATH_PROFILE_TAB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters the passed in email into the email field.
|
||||
* @param email
|
||||
*/
|
||||
async setEmail(email: string) {
|
||||
await this.openProfileTab();
|
||||
|
||||
await this.participant.driver.$(EMAIL_FIELD).setValue(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the participant's email displayed in the settings dialog.
|
||||
*/
|
||||
async getEmail() {
|
||||
await this.openProfileTab();
|
||||
|
||||
return await this.participant.driver.$(EMAIL_FIELD).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks the OK button on the settings dialog to close the dialog and save any changes made.
|
||||
*/
|
||||
async submit() {
|
||||
await this.clickOkButton();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ const CLOSE_PARTICIPANTS_PANE = 'Close participants pane';
|
||||
const OVERFLOW_MENU = 'More actions menu';
|
||||
const OVERFLOW = 'More actions';
|
||||
const PARTICIPANTS = 'Open participants pane';
|
||||
const PROFILE = 'Edit your profile';
|
||||
const VIDEO_QUALITY = 'Manage video quality';
|
||||
const VIDEO_MUTE = 'Stop camera';
|
||||
const VIDEO_UNMUTE = 'Start camera';
|
||||
@@ -134,6 +135,13 @@ export default class Toolbar {
|
||||
return this.clickButtonInOverflowMenu(VIDEO_QUALITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the profile toolbar button which opens or closes the profile panel.
|
||||
*/
|
||||
async clickProfileButton(): Promise<void> {
|
||||
return this.clickButtonInOverflowMenu(PROFILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the overflow menu is open and clicks on a specified button.
|
||||
* @param accessibilityLabel The accessibility label of the button to be clicked.
|
||||
@@ -203,4 +211,15 @@ export default class Toolbar {
|
||||
timeoutMsg: `Overflow menu is not ${visible ? 'visible' : 'hidden'}`
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the participant's avatar image element located in the toolbar.
|
||||
*/
|
||||
async getProfileImage() {
|
||||
await this.openOverflowMenu();
|
||||
|
||||
const elem = this.participant.driver.$(`[aria-label^="${PROFILE}"] img`);
|
||||
|
||||
return await elem.isExisting() ? await elem.getAttribute('src') : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,7 @@ describe('Audio only - ', () => {
|
||||
await context.p1.driver.$('//div[@id="dominantSpeaker"]').waitForDisplayed();
|
||||
|
||||
// Makes sure that the avatar is displayed in the local thumbnail and that the video is not displayed.
|
||||
await context.p1.driver.$('//span[@id="localVideoContainer"]//div[contains(@class,"userAvatar")]')
|
||||
.waitForDisplayed();
|
||||
await context.p1.driver.$('//span[@id="localVideoWrapper"]//video').waitForDisplayed({ reverse: true });
|
||||
await context.p1.assertThumbnailShowsAvatar(context.p1);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -51,10 +49,10 @@ describe('Audio only - ', () => {
|
||||
*/
|
||||
async function verifyVideoMute(muted: boolean) {
|
||||
// Verify the observer sees the testee in the desired muted state.
|
||||
await context.p2.getFilmstrip().assertVideoMuteIconIsDisplayed(context.p1, !muted);
|
||||
await context.p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1, !muted);
|
||||
|
||||
// Verify the testee sees itself in the desired muted state.
|
||||
await context.p1.getFilmstrip().assertVideoMuteIconIsDisplayed(context.p1, !muted);
|
||||
await context.p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1, !muted);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/* global APP */
|
||||
import type { Participant } from '../../helpers/Participant';
|
||||
import { ensureThreeParticipants, toggleMuteAndCheck } from '../../helpers/participants';
|
||||
import { ensureThreeParticipants, muteAudioAndCheck } from '../../helpers/participants';
|
||||
|
||||
describe('ActiveSpeaker ', () => {
|
||||
it('testActiveSpeaker', async () => {
|
||||
await ensureThreeParticipants(context);
|
||||
|
||||
await toggleMuteAndCheck(context.p1, context.p2);
|
||||
await toggleMuteAndCheck(context.p2, context.p1);
|
||||
await toggleMuteAndCheck(context.p3, context.p1);
|
||||
await muteAudioAndCheck(context.p1, context.p2);
|
||||
await muteAudioAndCheck(context.p2, context.p1);
|
||||
await muteAudioAndCheck(context.p3, context.p1);
|
||||
|
||||
// participant1 becomes active speaker - check from participant2's perspective
|
||||
await testActiveSpeaker(context.p1, context.p2, context.p3);
|
||||
@@ -60,7 +60,8 @@ async function testActiveSpeaker(
|
||||
const otherParticipant1Driver = otherParticipant1.driver;
|
||||
|
||||
await otherParticipant1Driver.waitUntil(
|
||||
() => otherParticipant1Driver.execute((id: string) => APP.UI.getLargeVideoID() === id, speakerEndpoint),
|
||||
async () => await otherParticipant1Driver.execute(
|
||||
id => APP.UI.getLargeVideoID() === id, speakerEndpoint),
|
||||
{
|
||||
timeout: 30_000, // 30 seconds
|
||||
timeoutMsg: 'Active speaker not displayed on large video.'
|
||||
|
||||
189
tests/specs/3way/avatarTest.spec.ts
Normal file
189
tests/specs/3way/avatarTest.spec.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import {
|
||||
ensureThreeParticipants,
|
||||
ensureTwoParticipants,
|
||||
unMuteVideoAndCheck
|
||||
} from '../../helpers/participants';
|
||||
|
||||
const EMAIL = 'support@jitsi.org';
|
||||
const HASH = '38f014e4b7dde0f64f8157d26a8c812e';
|
||||
|
||||
describe('Avatar - ', () => {
|
||||
it('setup the meeting', async () => {
|
||||
// Start p1
|
||||
await ensureTwoParticipants(context, {
|
||||
skipDisplayName: true
|
||||
});
|
||||
});
|
||||
|
||||
it('change and check', async () => {
|
||||
// check default avatar for p1 on p2
|
||||
await context.p2.assertDefaultAvatarExist(context.p1);
|
||||
|
||||
await context.p1.getToolbar().clickProfileButton();
|
||||
|
||||
const settings = context.p1.getSettingsDialog();
|
||||
|
||||
await settings.waitForDisplay();
|
||||
await settings.setEmail(EMAIL);
|
||||
await settings.submit();
|
||||
|
||||
// check if the local avatar in the toolbar menu has changed
|
||||
await context.p1.driver.waitUntil(
|
||||
async () => (await context.p1.getToolbar().getProfileImage())?.includes(HASH), {
|
||||
timeout: 3000, // give more time for the initial download of the image
|
||||
timeoutMsg: 'Avatar has not changed for p1'
|
||||
});
|
||||
|
||||
// check if the avatar in the local thumbnail has changed
|
||||
expect(await context.p1.getLocalVideoAvatar()).toContain(HASH);
|
||||
|
||||
const p1EndpointId = await context.p1.getEndpointId();
|
||||
|
||||
await context.p2.driver.waitUntil(
|
||||
async () => (await context.p2.getFilmstrip().getAvatar(p1EndpointId))?.includes(HASH), {
|
||||
timeout: 5000,
|
||||
timeoutMsg: 'Avatar has not changed for p1 on p2'
|
||||
});
|
||||
|
||||
// check if the avatar in the large video has changed
|
||||
expect(await context.p2.getLargeVideoAvatar()).toContain(HASH);
|
||||
|
||||
// we check whether the default avatar of participant2 is displayed on both sides
|
||||
await context.p1.assertDefaultAvatarExist(context.p2);
|
||||
await context.p2.assertDefaultAvatarExist(context.p2);
|
||||
|
||||
// the problem on FF where we can send keys to the input field,
|
||||
// and the m from the text can mute the call, check whether we are muted
|
||||
await context.p2.getFilmstrip().assertAudioMuteIconIsDisplayed(context.p1, true);
|
||||
});
|
||||
|
||||
it('when video muted', async () => {
|
||||
await context.p2.hangup();
|
||||
|
||||
// Mute p1's video
|
||||
await context.p1.getToolbar().clickVideoMuteButton();
|
||||
|
||||
await context.p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1);
|
||||
|
||||
await context.p1.driver.waitUntil(
|
||||
async () => (await context.p1.getLargeVideoAvatar())?.includes(HASH), {
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'Avatar on large video did not change'
|
||||
});
|
||||
|
||||
const p1LargeSrc = await context.p1.getLargeVideoAvatar();
|
||||
const p1ThumbSrc = await context.p1.getLocalVideoAvatar();
|
||||
|
||||
// Check if avatar on large video is the same as on local thumbnail
|
||||
expect(p1ThumbSrc).toBe(p1LargeSrc);
|
||||
|
||||
// Join p2
|
||||
await ensureTwoParticipants(context, {
|
||||
skipDisplayName: true
|
||||
});
|
||||
|
||||
// Verify that p1 is muted from the perspective of p2
|
||||
await context.p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1);
|
||||
|
||||
await context.p2.getFilmstrip().pinParticipant(context.p1);
|
||||
|
||||
// Check if p1's avatar is on large video now
|
||||
await context.p2.driver.waitUntil(
|
||||
async () => await context.p2.getLargeVideoAvatar() === p1LargeSrc, {
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'Avatar on large video did not change'
|
||||
});
|
||||
|
||||
// p1 pins p2's video
|
||||
await context.p1.getFilmstrip().pinParticipant(context.p2);
|
||||
|
||||
// Check if avatar is displayed on p1's local video thumbnail
|
||||
await context.p1.assertThumbnailShowsAvatar(context.p1, false, false, true);
|
||||
|
||||
// Unmute - now local avatar should be hidden and local video displayed
|
||||
await unMuteVideoAndCheck(context.p1, context.p2);
|
||||
|
||||
await context.p1.asserLocalThumbnailShowsVideo();
|
||||
|
||||
// Now both p1 and p2 have video muted
|
||||
await context.p1.getToolbar().clickVideoMuteButton();
|
||||
await context.p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1);
|
||||
await context.p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1);
|
||||
|
||||
await context.p2.getToolbar().clickVideoMuteButton();
|
||||
await context.p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p2);
|
||||
await context.p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p2);
|
||||
|
||||
// Start the third participant
|
||||
await ensureThreeParticipants(context);
|
||||
|
||||
// Pin local video and verify avatars are displayed
|
||||
await context.p3.getFilmstrip().pinParticipant(context.p3);
|
||||
|
||||
await context.p3.assertThumbnailShowsAvatar(context.p1, false, false, true);
|
||||
await context.p3.assertThumbnailShowsAvatar(context.p2, false, true);
|
||||
|
||||
const p1EndpointId = await context.p1.getEndpointId();
|
||||
const p2EndpointId = await context.p2.getEndpointId();
|
||||
|
||||
expect(await context.p3.getFilmstrip().getAvatar(p1EndpointId)).toBe(p1ThumbSrc);
|
||||
|
||||
// Click on p1's video
|
||||
await context.p3.getFilmstrip().pinParticipant(context.p1);
|
||||
|
||||
// The avatar should be on large video and display name instead of an avatar, local video displayed
|
||||
await context.p3.driver.waitUntil(
|
||||
async () => await context.p3.getLargeVideoResource() === p1EndpointId, {
|
||||
timeout: 2000,
|
||||
timeoutMsg: `Large video did not switch to ${context.p1.name}`
|
||||
});
|
||||
|
||||
await context.p3.assertDisplayNameVisibleOnStage(
|
||||
await context.p3.getFilmstrip().getRemoteDisplayName(p1EndpointId));
|
||||
|
||||
// p2 has the default avatar
|
||||
await context.p3.assertThumbnailShowsAvatar(context.p2, false, true);
|
||||
await context.p3.assertThumbnailShowsAvatar(context.p3, true);
|
||||
|
||||
// Click on p2's video
|
||||
await context.p3.getFilmstrip().pinParticipant(context.p2);
|
||||
|
||||
// The avatar should be on large video and display name instead of an avatar, local video displayed
|
||||
await context.p3.driver.waitUntil(
|
||||
async () => await context.p3.getLargeVideoResource() === p2EndpointId, {
|
||||
timeout: 2000,
|
||||
timeoutMsg: `Large video did not switch to ${context.p2.name}`
|
||||
});
|
||||
|
||||
await context.p3.assertDisplayNameVisibleOnStage(
|
||||
await context.p3.getFilmstrip().getRemoteDisplayName(p2EndpointId)
|
||||
);
|
||||
|
||||
await context.p3.assertThumbnailShowsAvatar(context.p1, false, false, true);
|
||||
await context.p3.assertThumbnailShowsAvatar(context.p3, true);
|
||||
|
||||
await context.p3.hangup();
|
||||
|
||||
// Unmute p1's and p2's videos
|
||||
await context.p1.getToolbar().clickVideoUnmuteButton();
|
||||
|
||||
await context.p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1, true);
|
||||
await context.p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(context.p1, true);
|
||||
});
|
||||
|
||||
it('email persistence', async () => {
|
||||
await context.p1.getToolbar().clickProfileButton();
|
||||
|
||||
expect(await context.p1.getSettingsDialog().getEmail()).toBe(EMAIL);
|
||||
|
||||
await context.p1.hangup();
|
||||
|
||||
await ensureTwoParticipants(context, {
|
||||
skipDisplayName: true
|
||||
});
|
||||
|
||||
await context.p1.getToolbar().clickProfileButton();
|
||||
|
||||
expect(await context.p1.getSettingsDialog().getEmail()).toBe(EMAIL);
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@ import { multiremotebrowser } from '@wdio/globals';
|
||||
import { Buffer } from 'buffer';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import pretty from 'pretty';
|
||||
|
||||
import { getLogs, initLogger, logInfo } from './helpers/browserLogger';
|
||||
import { IContext } from './helpers/types';
|
||||
@@ -58,7 +59,7 @@ export const config: WebdriverIO.MultiremoteConfig = {
|
||||
],
|
||||
maxInstances: 1,
|
||||
|
||||
baseUrl: process.env.BASE_URL || 'https://alpha.jitsi.net/torture',
|
||||
baseUrl: process.env.BASE_URL || 'https://alpha.jitsi.net/torture/',
|
||||
tsConfigPath: './tsconfig.json',
|
||||
|
||||
// Default timeout for all waitForXXX commands.
|
||||
@@ -249,7 +250,7 @@ export const config: WebdriverIO.MultiremoteConfig = {
|
||||
AllureReporter.addAttachment(`console-logs-${instance}`, getLogs(bInstance) || '', 'text/plain');
|
||||
|
||||
allProcessing.push(bInstance.getPageSource().then(source => {
|
||||
AllureReporter.addAttachment(`html-source-${instance}`, source, 'text/plain');
|
||||
AllureReporter.addAttachment(`html-source-${instance}`, pretty(source), 'text/plain');
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user