From 9a4c65b10fe3cd5f3786ef75b89e25414cf2d4fc Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Tue, 29 Aug 2023 21:45:48 +0200 Subject: [PATCH 01/14] Add playwright and stream-video-buddy packages --- package.json | 4 +- sample-apps/react/egress-composite/.gitignore | 3 + .../react/egress-composite/package.json | 4 +- yarn.lock | 265 ++++++++++++++++-- 4 files changed, 258 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 9dc969b601..451aa55179 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,8 @@ "release:18n": "yarn workspace @stream-io/i18n npm publish --access=public", "release:react-bindings": "yarn workspace @stream-io/video-react-bindings npm publish --access=public", "release:react-sdk": "yarn workspace @stream-io/video-react-sdk npm publish --access=public", - "release:react-native-sdk": "yarn workspace @stream-io/video-react-native-sdk npm publish --access=public" + "release:react-native-sdk": "yarn workspace @stream-io/video-react-native-sdk npm publish --access=public", + "buddy": "stream-video-buddy" }, "devDependencies": { "@commitlint/cli": "^17.0.0", @@ -74,6 +75,7 @@ "ngx-deploy-npm": "^5.2.0", "nx": "16.0.1", "prettier": "^2.8.4", + "stream-video-buddy": "https://github.com/GetStream/stream-video-buddy#1.6.10", "typescript": "^4.9.5", "vercel": "^32.1.0", "vite": "^4.4.9" diff --git a/sample-apps/react/egress-composite/.gitignore b/sample-apps/react/egress-composite/.gitignore index fc5ae9f0cc..1b6016cd16 100644 --- a/sample-apps/react/egress-composite/.gitignore +++ b/sample-apps/react/egress-composite/.gitignore @@ -23,3 +23,6 @@ dist-ssr *.sln *.sw? .vercel +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/sample-apps/react/egress-composite/package.json b/sample-apps/react/egress-composite/package.json index 5b08a4aa2b..0bfc9b2143 100644 --- a/sample-apps/react/egress-composite/package.json +++ b/sample-apps/react/egress-composite/package.json @@ -7,7 +7,8 @@ "start": "vite", "dev": "vite", "build": "tsc && vite build", - "preview": "vite preview" + "preview": "vite preview", + "test:e2e": "playwright test" }, "dependencies": { "@stream-io/video-react-sdk": "workspace:^", @@ -17,6 +18,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { + "@playwright/test": "^1.37.1", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", "@vitejs/plugin-react": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index b08e68decf..4c43592f70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4533,6 +4533,22 @@ __metadata: languageName: node linkType: hard +"@playwright/test@npm:^1.37.1": + version: 1.37.1 + resolution: "@playwright/test@npm:1.37.1" + dependencies: + "@types/node": "*" + fsevents: 2.3.2 + playwright-core: 1.37.1 + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: b7038f29000289103c08b215eff7aabdda70cdc1375fa7dad0e81651be71086a1e2fc0e0e29dc70348037c366cf0cc69f762373fda34ba1a74aa1658741d9195 + languageName: node + linkType: hard + "@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.3": version: 0.5.10 resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.10" @@ -6850,6 +6866,7 @@ __metadata: version: 0.0.0-use.local resolution: "@stream-io/egress-composite@workspace:sample-apps/react/egress-composite" dependencies: + "@playwright/test": ^1.37.1 "@stream-io/video-react-sdk": "workspace:^" "@types/react": ^18.0.28 "@types/react-dom": ^18.0.11 @@ -7080,6 +7097,7 @@ __metadata: ngx-deploy-npm: ^5.2.0 nx: 16.0.1 prettier: ^2.8.4 + stream-video-buddy: "https://github.com/GetStream/stream-video-buddy#1.6.10" typescript: ^4.9.5 vercel: ^32.1.0 vite: ^4.4.9 @@ -7556,6 +7574,15 @@ __metadata: languageName: node linkType: hard +"@types/debug@npm:^4.1.0": + version: 4.1.8 + resolution: "@types/debug@npm:4.1.8" + dependencies: + "@types/ms": "*" + checksum: a9a9bb40a199e9724aa944e139a7659173a9b274798ea7efbc277cb084bc37d32fc4c00877c3496fac4fed70a23243d284adb75c00b5fdabb38a22154d18e5df + languageName: node + linkType: hard + "@types/eslint-scope@npm:^3.7.3": version: 3.7.4 resolution: "@types/eslint-scope@npm:3.7.4" @@ -11484,6 +11511,19 @@ __metadata: languageName: node linkType: hard +"clone-deep@npm:^0.2.4": + version: 0.2.4 + resolution: "clone-deep@npm:0.2.4" + dependencies: + for-own: ^0.1.3 + is-plain-object: ^2.0.1 + kind-of: ^3.0.2 + lazy-cache: ^1.0.3 + shallow-clone: ^0.1.2 + checksum: bcf9752052130c270c47d3e1c357497354b91d682f507e0079bec5950975b3293b619d9e100d70874606d716f2376e84956b045759a09af703e1038ecad6c438 + languageName: node + linkType: hard + "clone-deep@npm:^2.0.1": version: 2.0.2 resolution: "clone-deep@npm:2.0.2" @@ -11713,7 +11753,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^9.4.1": +"commander@npm:^9.4.1, commander@npm:^9.5.0": version: 9.5.0 resolution: "commander@npm:9.5.0" checksum: c7a3e27aa59e913b54a1bafd366b88650bc41d6651f0cbe258d4ff09d43d6a7394232a4dadd0bf518b3e696fdf595db1028a0d82c785b88bd61f8a440cecfade @@ -15628,6 +15668,15 @@ __metadata: languageName: node linkType: hard +"for-own@npm:^0.1.3": + version: 0.1.5 + resolution: "for-own@npm:0.1.5" + dependencies: + for-in: ^1.0.1 + checksum: 07eb0a2e98eb55ce13b56dd11ef4fb5e619ba7380aaec388b9eec1946153d74fa734ce409e8434020557e9489a50c34bc004d55754f5863bf7d77b441d8dee8c + languageName: node + linkType: hard + "for-own@npm:^1.0.0": version: 1.0.0 resolution: "for-own@npm:1.0.0" @@ -15800,7 +15849,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:10.1.0, fs-extra@npm:^10.1.0": +"fs-extra@npm:10.1.0, fs-extra@npm:^10.0.0, fs-extra@npm:^10.1.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" dependencies: @@ -15903,6 +15952,16 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:2.3.2, fsevents@npm:^2.1.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": + version: 2.3.2 + resolution: "fsevents@npm:2.3.2" + dependencies: + node-gyp: latest + checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@npm:^1.2.7": version: 1.2.13 resolution: "fsevents@npm:1.2.13" @@ -15914,12 +15973,11 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.1.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": +"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.1.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 - resolution: "fsevents@npm:2.3.2" + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" dependencies: node-gyp: latest - checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f conditions: os=darwin languageName: node linkType: hard @@ -15934,15 +15992,6 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@^2.1.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" - dependencies: - node-gyp: latest - conditions: os=darwin - languageName: node - linkType: hard - "function-bind@npm:^1.1.1": version: 1.1.1 resolution: "function-bind@npm:1.1.1" @@ -17545,7 +17594,7 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^1.1.5, is-buffer@npm:~1.1.1, is-buffer@npm:~1.1.6": +"is-buffer@npm:^1.0.2, is-buffer@npm:^1.1.5, is-buffer@npm:~1.1.1, is-buffer@npm:~1.1.6": version: 1.1.6 resolution: "is-buffer@npm:1.1.6" checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707 @@ -17905,7 +17954,7 @@ __metadata: languageName: node linkType: hard -"is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4": +"is-plain-object@npm:^2.0.1, is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4": version: 2.0.4 resolution: "is-plain-object@npm:2.0.4" dependencies: @@ -19194,6 +19243,13 @@ __metadata: languageName: node linkType: hard +"jssha@npm:^3.3.0": + version: 3.3.1 + resolution: "jssha@npm:3.3.1" + checksum: 4f2b636305710d5275d5e48a323ceaed80b6400fd545321fccdb4e904392a7b808fa79cdf355073766a290d731756eb5bd5ceb2341cc53e57b686c7bb3a18488 + languageName: node + linkType: hard + "jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.3": version: 3.3.3 resolution: "jsx-ast-utils@npm:3.3.3" @@ -19246,6 +19302,15 @@ __metadata: languageName: node linkType: hard +"kind-of@npm:^2.0.1": + version: 2.0.1 + resolution: "kind-of@npm:2.0.1" + dependencies: + is-buffer: ^1.0.2 + checksum: 043df2943e113bca612d26224947395e9673bb3808d94aed30e47fbf0bafd618e2a29ff0ca2d5498f64332c320fff07f0aa9d6edfc20906a93c1b8792f11759c + languageName: node + linkType: hard + "kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0": version: 3.2.2 resolution: "kind-of@npm:3.2.2" @@ -19324,6 +19389,20 @@ __metadata: languageName: node linkType: hard +"lazy-cache@npm:^0.2.3": + version: 0.2.7 + resolution: "lazy-cache@npm:0.2.7" + checksum: b4538aff20db586c354f31de3ed59ea2c8d5dc4f01141bf49f07601e7ca0d7ed43a3f49362ade49b1e18ab1f3d121df0f2c9ea9b599b44dd54fb0c0db253c8b9 + languageName: node + linkType: hard + +"lazy-cache@npm:^1.0.3": + version: 1.0.4 + resolution: "lazy-cache@npm:1.0.4" + checksum: e6650c22e5de1cc3f4a0c25d2b35fe9cd400473c1b3562be9fceadf8f368d708b54d24f5aa51b321b090da65b36426823a8f706b8dbdd68270db0daba812c5d3 + languageName: node + linkType: hard + "lazy-universal-dotenv@npm:^3.0.1": version: 3.0.1 resolution: "lazy-universal-dotenv@npm:3.0.1" @@ -20372,6 +20451,17 @@ __metadata: languageName: node linkType: hard +"merge-deep@npm:^3.0.1": + version: 3.0.3 + resolution: "merge-deep@npm:3.0.3" + dependencies: + arr-union: ^3.1.0 + clone-deep: ^0.2.4 + kind-of: ^3.0.2 + checksum: d2eb367b8300327c66a3e1e01eb06251f51b440bf5bfa5f0f8065ae95bf3af620d21fcd0ab2eb50e74f5119aac40ffd26c85e3bf82f79082e8757675f5885d3d + languageName: node + linkType: hard + "merge-descriptors@npm:1.0.1": version: 1.0.1 resolution: "merge-descriptors@npm:1.0.1" @@ -23589,6 +23679,43 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:1.37.1": + version: 1.37.1 + resolution: "playwright-core@npm:1.37.1" + bin: + playwright-core: cli.js + checksum: 69f818da2230057584140d5b3af7778a4f4a822b5b18d133abfc5d259128becb943c343a2ddf6b0635277a69f28983e83e2bc3fce23595ececb1e410475b6368 + languageName: node + linkType: hard + +"playwright-extra@npm:^4.3.6": + version: 4.3.6 + resolution: "playwright-extra@npm:4.3.6" + dependencies: + debug: ^4.3.4 + peerDependencies: + playwright: "*" + playwright-core: "*" + peerDependenciesMeta: + playwright: + optional: true + playwright-core: + optional: true + checksum: 2ecaef65036895a9c6aa8d97be7d01677690a103bf39b514b8a2c153cf29932b4b205040a6e132f145868323891dcfbb32c7b2d97f9ac64a9f25e2e83a2f706e + languageName: node + linkType: hard + +"playwright@npm:^1.35.0": + version: 1.37.1 + resolution: "playwright@npm:1.37.1" + dependencies: + playwright-core: 1.37.1 + bin: + playwright: cli.js + checksum: 99406ef3e15b83a659cb23ef1d92d9935789aad430580d1e0371087dfdf266891483c6f97cfa06bf5f49f081eacd44245d05d20714f98531edef4cc317044d6b + languageName: node + linkType: hard + "plist@npm:^3.0.5": version: 3.1.0 resolution: "plist@npm:3.1.0" @@ -24171,6 +24298,84 @@ __metadata: languageName: node linkType: hard +"puppeteer-extra-plugin-stealth@npm:^2.11.2": + version: 2.11.2 + resolution: "puppeteer-extra-plugin-stealth@npm:2.11.2" + dependencies: + debug: ^4.1.1 + puppeteer-extra-plugin: ^3.2.3 + puppeteer-extra-plugin-user-preferences: ^2.4.1 + peerDependencies: + playwright-extra: "*" + puppeteer-extra: "*" + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + checksum: 13ab2b906c1cd1a75bb346074e6ed75dd33da426e9b7d2e111dee6d497ae9ff42f44c2e5b0d48a04b545e862f9d27d8ecf61fa1863201afc8a9410121ed65a4b + languageName: node + linkType: hard + +"puppeteer-extra-plugin-user-data-dir@npm:^2.4.1": + version: 2.4.1 + resolution: "puppeteer-extra-plugin-user-data-dir@npm:2.4.1" + dependencies: + debug: ^4.1.1 + fs-extra: ^10.0.0 + puppeteer-extra-plugin: ^3.2.3 + rimraf: ^3.0.2 + peerDependencies: + playwright-extra: "*" + puppeteer-extra: "*" + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + checksum: f360b3bb22eeb899b23b6e2a38412ddfeda4b2333e08f77452732e16f094f33725272ee81150428e2c20b39d4d88edc87584d8344bd761c9ef8ae5d681968399 + languageName: node + linkType: hard + +"puppeteer-extra-plugin-user-preferences@npm:^2.4.1": + version: 2.4.1 + resolution: "puppeteer-extra-plugin-user-preferences@npm:2.4.1" + dependencies: + debug: ^4.1.1 + deepmerge: ^4.2.2 + puppeteer-extra-plugin: ^3.2.3 + puppeteer-extra-plugin-user-data-dir: ^2.4.1 + peerDependencies: + playwright-extra: "*" + puppeteer-extra: "*" + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + checksum: e0e50145d1d32626a8bb75afeb0dc238d63c05a8d264e12bb249b06aa34f7c116f6ec531335e964ea715837759dacd505d2fa8f6c9d478e983303eb2cb701ec9 + languageName: node + linkType: hard + +"puppeteer-extra-plugin@npm:^3.2.3": + version: 3.2.3 + resolution: "puppeteer-extra-plugin@npm:3.2.3" + dependencies: + "@types/debug": ^4.1.0 + debug: ^4.1.1 + merge-deep: ^3.0.1 + peerDependencies: + playwright-extra: "*" + puppeteer-extra: "*" + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + checksum: 18c2780a151e023ed145cd7768a6cf2dba1c124bce920de5f7815dcd872550288554161b1474037e8819969b1adfad41bdc09a9aadfd155338abc6d22699b7ed + languageName: node + linkType: hard + "pure-rand@npm:^6.0.0": version: 6.0.1 resolution: "pure-rand@npm:6.0.1" @@ -26573,6 +26778,18 @@ __metadata: languageName: node linkType: hard +"shallow-clone@npm:^0.1.2": + version: 0.1.2 + resolution: "shallow-clone@npm:0.1.2" + dependencies: + is-extendable: ^0.1.1 + kind-of: ^2.0.1 + lazy-cache: ^0.2.3 + mixin-object: ^2.0.1 + checksum: cc4c85c6e42186fec33a81a85622c48dbcfdf280f3a7bd0800b4de57df8e365a8760aa2e31dd79df365b317dddb2fd0bbd92be0aab14dbd2de6a65992eab2177 + languageName: node + linkType: hard + "shallow-clone@npm:^1.0.0": version: 1.0.0 resolution: "shallow-clone@npm:1.0.0" @@ -27319,6 +27536,22 @@ __metadata: languageName: node linkType: hard +"stream-video-buddy@https://github.com/GetStream/stream-video-buddy#1.6.10": + version: 1.6.10 + resolution: "stream-video-buddy@https://github.com/GetStream/stream-video-buddy.git#commit=b73181a7486f259ff270b1c172ecd715c9324806" + dependencies: + commander: ^9.5.0 + express: ^4.18.2 + jssha: ^3.3.0 + playwright: ^1.35.0 + playwright-extra: ^4.3.6 + puppeteer-extra-plugin-stealth: ^2.11.2 + bin: + stream-video-buddy: ./lib/index.js + checksum: 210f0e3af0e04da0cca1e8f99996abb8defa9afd889209d285f6a9e48c07d86ec3d309be6a54e5094a766adb84473f0c07786e557656080a904e03b6aa4e1a4e + languageName: node + linkType: hard + "streamsearch@npm:^1.1.0": version: 1.1.0 resolution: "streamsearch@npm:1.1.0" From 7a11e71e077027bf28de2584c3955ff23bef64d7 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Tue, 29 Aug 2023 21:46:01 +0200 Subject: [PATCH 02/14] Add playwright.config --- .../egress-composite/playwright.config.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 sample-apps/react/egress-composite/playwright.config.ts diff --git a/sample-apps/react/egress-composite/playwright.config.ts b/sample-apps/react/egress-composite/playwright.config.ts new file mode 100644 index 0000000000..a0918bc438 --- /dev/null +++ b/sample-apps/react/egress-composite/playwright.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from '@playwright/test'; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + fullyParallel: false, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: 'list', + snapshotDir: './tests/snapshots', + use: { + headless: false, + trace: 'on-first-retry', + viewport: { width: 1920, height: 1080 }, + }, + webServer: [ + { + timeout: 10000, + command: 'yarn dev', + reuseExistingServer: false, + port: 5173, + }, + { + timeout: 30000, + command: 'yarn buddy auth && yarn buddy server --port 4567', + reuseExistingServer: false, + port: 4567, + }, + ], +}); From 6dd6d2a5c8190c58f9f0ce71c006d97cf4281aa8 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Tue, 29 Aug 2023 21:46:19 +0200 Subject: [PATCH 03/14] Add testIds to layout components --- .../components/layouts/DominantSpeaker/DominantSpeaker.tsx | 5 ++++- .../src/components/layouts/PaginatedGrid/PaginatedGrid.tsx | 2 +- .../src/components/layouts/Spotlight/Spotlight.tsx | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sample-apps/react/egress-composite/src/components/layouts/DominantSpeaker/DominantSpeaker.tsx b/sample-apps/react/egress-composite/src/components/layouts/DominantSpeaker/DominantSpeaker.tsx index e644087cec..4e1ae14019 100644 --- a/sample-apps/react/egress-composite/src/components/layouts/DominantSpeaker/DominantSpeaker.tsx +++ b/sample-apps/react/egress-composite/src/components/layouts/DominantSpeaker/DominantSpeaker.tsx @@ -24,7 +24,10 @@ export const DominantSpeaker = () => { if (!activeCall) return

No active call

; return ( <> -
+
{speakerInSpotlight && ( { } = useConfigurationContext(); return ( -
+
{ } = useConfigurationContext(); return ( -
+
Date: Wed, 30 Aug 2023 19:38:30 +0200 Subject: [PATCH 04/14] Move packages --- package.json | 4 +--- sample-apps/react/egress-composite/package.json | 6 +++++- yarn.lock | 15 ++++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 451aa55179..9dc969b601 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,7 @@ "release:18n": "yarn workspace @stream-io/i18n npm publish --access=public", "release:react-bindings": "yarn workspace @stream-io/video-react-bindings npm publish --access=public", "release:react-sdk": "yarn workspace @stream-io/video-react-sdk npm publish --access=public", - "release:react-native-sdk": "yarn workspace @stream-io/video-react-native-sdk npm publish --access=public", - "buddy": "stream-video-buddy" + "release:react-native-sdk": "yarn workspace @stream-io/video-react-native-sdk npm publish --access=public" }, "devDependencies": { "@commitlint/cli": "^17.0.0", @@ -75,7 +74,6 @@ "ngx-deploy-npm": "^5.2.0", "nx": "16.0.1", "prettier": "^2.8.4", - "stream-video-buddy": "https://github.com/GetStream/stream-video-buddy#1.6.10", "typescript": "^4.9.5", "vercel": "^32.1.0", "vite": "^4.4.9" diff --git a/sample-apps/react/egress-composite/package.json b/sample-apps/react/egress-composite/package.json index 0bfc9b2143..b4a972e9eb 100644 --- a/sample-apps/react/egress-composite/package.json +++ b/sample-apps/react/egress-composite/package.json @@ -8,7 +8,8 @@ "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", - "test:e2e": "playwright test" + "test:e2e": "playwright test", + "buddy": "stream-video-buddy" }, "dependencies": { "@stream-io/video-react-sdk": "workspace:^", @@ -22,6 +23,9 @@ "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", "@vitejs/plugin-react": "^4.0.0", + "axios": "^1.5.0", + "nanoid": "^4.0.2", + "stream-video-buddy": "https://github.com/GetStream/stream-video-buddy#1.6.10", "typescript": "^4.9.5", "vercel": "^32.1.0", "vite": "^4.4.9" diff --git a/yarn.lock b/yarn.lock index 4c43592f70..04de8d100c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6871,10 +6871,13 @@ __metadata: "@types/react": ^18.0.28 "@types/react-dom": ^18.0.11 "@vitejs/plugin-react": ^4.0.0 + axios: ^1.5.0 clsx: ^1.2.1 js-base64: ^3.7.5 + nanoid: ^4.0.2 react: ^18.2.0 react-dom: ^18.2.0 + stream-video-buddy: "https://github.com/GetStream/stream-video-buddy#1.6.10" typescript: ^4.9.5 vercel: ^32.1.0 vite: ^4.4.9 @@ -7097,7 +7100,6 @@ __metadata: ngx-deploy-npm: ^5.2.0 nx: 16.0.1 prettier: ^2.8.4 - stream-video-buddy: "https://github.com/GetStream/stream-video-buddy#1.6.10" typescript: ^4.9.5 vercel: ^32.1.0 vite: ^4.4.9 @@ -10045,6 +10047,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.5.0": + version: 1.5.0 + resolution: "axios@npm:1.5.0" + dependencies: + follow-redirects: ^1.15.0 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: e7405a5dbbea97760d0e6cd58fecba311b0401ddb4a8efbc4108f5537da9b3f278bde566deb777935a960beec4fa18e7b8353881f2f465e4f2c0e949fead35be + languageName: node + linkType: hard + "axobject-query@npm:^3.1.1": version: 3.1.1 resolution: "axobject-query@npm:3.1.1" From 4ee28ad7551f090716142d531237e96cb5e4b229 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Wed, 30 Aug 2023 19:38:49 +0200 Subject: [PATCH 05/14] Add testId to ParticipantView --- .../src/core/components/ParticipantView/ParticipantView.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-sdk/src/core/components/ParticipantView/ParticipantView.tsx b/packages/react-sdk/src/core/components/ParticipantView/ParticipantView.tsx index 090b0c8161..604a89eef9 100644 --- a/packages/react-sdk/src/core/components/ParticipantView/ParticipantView.tsx +++ b/packages/react-sdk/src/core/components/ParticipantView/ParticipantView.tsx @@ -147,6 +147,7 @@ export const ParticipantView = forwardRef( return (
{ applyElementToRef(ref, element); setTrackedElement(element); From ff613f4cb23a10417f9f962d9a79205c65d02bd3 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Wed, 30 Aug 2023 19:40:52 +0200 Subject: [PATCH 06/14] Update Playwright configuration, add test and screenshots --- .../egress-composite/playwright.config.ts | 17 ++--- .../layouts.spec.ts/Layouts-grid-1.png | Bin 0 -> 10711 bytes .../Layouts-single-participant-1.png | Bin 0 -> 10592 bytes .../layouts.spec.ts/Layouts-spotlight-1.png | Bin 0 -> 10713 bytes .../egress-composite/tests/layouts.spec.ts | 61 ++++++++++++++++++ 5 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-grid-1.png create mode 100644 sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-single-participant-1.png create mode 100644 sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-spotlight-1.png create mode 100644 sample-apps/react/egress-composite/tests/layouts.spec.ts diff --git a/sample-apps/react/egress-composite/playwright.config.ts b/sample-apps/react/egress-composite/playwright.config.ts index a0918bc438..d6ef59f434 100644 --- a/sample-apps/react/egress-composite/playwright.config.ts +++ b/sample-apps/react/egress-composite/playwright.config.ts @@ -5,28 +5,29 @@ import { defineConfig } from '@playwright/test'; */ export default defineConfig({ testDir: './tests', - fullyParallel: false, + fullyParallel: true, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'list', - snapshotDir: './tests/snapshots', + snapshotPathTemplate: './tests/__screenshots__/{testFilePath}/{arg}{ext}', use: { - headless: false, + headless: !!process.env.CI, trace: 'on-first-retry', viewport: { width: 1920, height: 1080 }, + baseURL: 'http://localhost:5173', }, webServer: [ { timeout: 10000, - command: 'yarn dev', + command: 'yarn buddy server --port 4567', reuseExistingServer: false, - port: 5173, + port: 4567, }, { - timeout: 30000, - command: 'yarn buddy auth && yarn buddy server --port 4567', + timeout: 10000, + command: 'yarn dev', reuseExistingServer: false, - port: 4567, + port: 5173, }, ], }); diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-grid-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-grid-1.png new file mode 100644 index 0000000000000000000000000000000000000000..ae647c2d7966427bb6ab7517ddf5c9a141bdb74f GIT binary patch literal 10711 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-ahlL4m>3 z#WAE}&YRnYe1{c8SRFfR{%cQG4mcuou4>uR%BR!A&KMq(0%`(*KYP!=WP~so?l?1m zj0A!Xfd;6c5=#PDgrR|hQ3AqJa2izx42jVIfh32~6ao&1VV`9lS=ll)v_~vwXJELK zlXvf~J%hv9cmEh4i2fNZ4n~WE(Fy}p3XE2b;IeSEY6J%Z!)VnA4u@f1HI6ojLGe7A z>qm3_XblKS1EYCiG%t+ih0(k)I+TVvXgDLer?iR%k~SFje`dy1L2_qu-DPHmijLAM z28IJ?pFO+#mzm+pn|JaIaR>Pm8uEXaSHZ>m)4qT>bU1gpAD2rAhjYGj@{#MEYLs_pTmboaE35$%DUeyQv+|_( z*4dDoRj)+>+AnkOKpAnkzIS@p?{*yF=R{@s=c~W8YfqgNdk+VVhPBl`~agALFJ9c})R9Kr|i55Tgo8M&rQdpkZKhU~>SqKrMj2Kwn@+(j1@` z3=H%I`U15;Er7m2U*H_caNzG+c>L^MsUf8(Uw)il+rU;xU80mKX-H7F<58rU@eHb)wYlmdNIW)5Zz#sjH^QH=-3 z3)8cJGpYUs7~Qwzo2h8QuNB5C#RJAG#w$q!#w*4v)ebm)`R{n(tv$Pk(b>(bf;Zl* JhV39}{sOKDBgg;% literal 0 HcmV?d00001 diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-spotlight-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-spotlight-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6587bb6f210694df27d9dc4054381b223f75c14c GIT binary patch literal 10713 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-ahlL4m>3 z#WAE}&YRl@IU5WZSPr_p+5a@c*@0u7vFM%potDQUn1MQgpyB*(KYj?4;ejlZ0fgz$ z!oUMz2`Dl^Rl0B-fT|N5RR#))(EtIbhtU)Q4u;Vz0}ciT{Ds4vS%ifT5&hTLlf5MPY@^;I`85C0H$1(h{e*I|9Z>Bp>_c7!b#y4z_*{jd+p?Mhi zkf`=*fvndI1_sV{&{_b7(Izf9S&z2)!ND-v#03Y#XcHGw)(_pnA;NgGzdp1Vf1ucI rv_lV!(9z62nz=^@w;(0k;K>X7mhlVZU%$8rJoxD8>gTe~DWM4f#Tx8U literal 0 HcmV?d00001 diff --git a/sample-apps/react/egress-composite/tests/layouts.spec.ts b/sample-apps/react/egress-composite/tests/layouts.spec.ts new file mode 100644 index 0000000000..cf41611eb3 --- /dev/null +++ b/sample-apps/react/egress-composite/tests/layouts.spec.ts @@ -0,0 +1,61 @@ +import { test as base, expect } from '@playwright/test'; +import { customAlphabet } from 'nanoid'; +import axios from 'axios'; + +const nanoid = customAlphabet('1234567890abcdefghijklmnop', 10); + +// TODO: move to some shared folder +const test = base.extend<{ callId: string }>({ + callId: async ({ page }, use) => { + const callId = nanoid(); + + // TODO: have proper abstractions with typing like StreamVideoBuddy.join(...) -> id and StreamVideoBuddy.teardown(id) + await axios.post('http://localhost:4567/stream-video-buddy?async=true', { + duration: 60, + 'call-id': callId, + 'user-count': 4, + }); + + // TODO: have proper ?asyncJoin=true + // which waits only for successfull call creation + // but asyncs user joins + await new Promise((resolve) => setTimeout(resolve, 2000)); + + await page.goto('/', { waitUntil: 'domcontentloaded' }); + + // run tests + await use(callId); + + // teardown + // TODO: await StreamVideoBuddy.teardown()... + }, +}); + +test.describe('Layouts', () => { + [ + { name: 'grid', participantCountPerWindow: 4 }, + { name: 'single_participant', participantCountPerWindow: 1 }, + // egress is not filtered for this one + { name: 'spotlight', participantCountPerWindow: 5 }, + ].forEach((layout) => { + test(`${layout.name}`, async ({ page, callId }) => { + await page.addScriptTag({ + content: ` + window.setupLayout({ + call_id: "${callId}", + layout: "${layout.name}", + }); + `, + }); + + await expect(page.getByTestId('participant-view')).toHaveCount( + layout.participantCountPerWindow, + ); + await expect(page.getByTestId(layout.name)).toBeVisible(); + await expect(page).toHaveScreenshot({ + mask: [page.getByTestId('participant-view')], + maskColor: 'lime', + }); + }); + }); +}); From 104cc97dc3bf9e9713d3cca51fe45436dcb8e849 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Wed, 30 Aug 2023 19:47:07 +0200 Subject: [PATCH 07/14] Add CI job --- .github/workflows/egress-composite-e2e.yml | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/egress-composite-e2e.yml diff --git a/.github/workflows/egress-composite-e2e.yml b/.github/workflows/egress-composite-e2e.yml new file mode 100644 index 0000000000..60ee84cd17 --- /dev/null +++ b/.github/workflows/egress-composite-e2e.yml @@ -0,0 +1,68 @@ +name: Playwright Tests +on: + pull_request: + types: + - opened + - synchronize + - reopened + paths: + - 'sample-apps/react/egress-composite/**' + - 'packages/client/**' + - 'packages/react-sdk/**' + - 'packages/styling/**' + - 'packages/react-bindings/**' +env: + VITE_STREAM_API_KEY: ${{ vars.EGRESS_STREAM_API_KEY }} + VITE_STREAM_USER_TOKEN: ${{ secrets.EGRESS_USER_TOKEN }} + STREAM_SDK_TEST_APP: ${{ secrets.STREAM_SDK_TEST_APP }} + STREAM_SDK_TEST_ACCOUNT_EMAIL: ${{ secrets.STREAM_SDK_TEST_ACCOUNT_EMAIL }} + STREAM_SDK_TEST_ACCOUNT_PASSWORD: ${{ secrets.STREAM_SDK_TEST_ACCOUNT_PASSWORD }} + STREAM_SDK_TEST_ACCOUNT_OTP_SECRET: ${{ secrets.STREAM_SDK_TEST_ACCOUNT_OTP_SECRET }} + +jobs: + test: + timeout-minutes: 15 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: 'yarn' + + - name: Install dependencies + run: yarn install --immutable + + - name: Build packages + env: + NODE_ENV: production + run: yarn build:react:deps + + - name: 💾 Cache Playwright browsers + uses: actions/cache@v3 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: ${{ runner.os }}${{ runner.arch }}-playwright-browsers + + - name: Install Playwright browsers if not cached + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: npx playwright install chromium + + - name: Install Playwright system dependencies (always) + run: npx playwright install-deps + + - name: Run Playwright tests + working-directory: sample-apps/react/egress-composite + run: yarn buddy auth && yarn test:e2e + + - uses: actions/upload-artifact@v3 + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 From 51ba025d22ff3ac15b3c4f2d3eaff4ff06757331 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Tue, 12 Sep 2023 17:18:23 +0200 Subject: [PATCH 08/14] Update testId attributes --- .../egress-composite/src/components/LogoAndTitleOverlay.tsx | 4 ++-- .../components/layouts/DominantSpeaker/DominantSpeaker.tsx | 5 +++-- .../src/components/layouts/PaginatedGrid/PaginatedGrid.tsx | 2 +- .../src/components/layouts/Spotlight/Spotlight.tsx | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sample-apps/react/egress-composite/src/components/LogoAndTitleOverlay.tsx b/sample-apps/react/egress-composite/src/components/LogoAndTitleOverlay.tsx index 378763fc7f..241f875fbb 100644 --- a/sample-apps/react/egress-composite/src/components/LogoAndTitleOverlay.tsx +++ b/sample-apps/react/egress-composite/src/components/LogoAndTitleOverlay.tsx @@ -17,7 +17,7 @@ export const LogoAndTitleOverlay = () => { > {/* {text?.length && (
{text} @@ -25,7 +25,7 @@ export const LogoAndTitleOverlay = () => { )} */} {image_url && ( logo { const activeCall = useCall(); const speakerInSpotlight = useSpotlightParticipant(); @@ -26,7 +27,7 @@ export const DominantSpeaker = () => { <>
{speakerInSpotlight && ( { } = useConfigurationContext(); return ( -
+
{ } = useConfigurationContext(); return ( -
+
Date: Tue, 12 Sep 2023 17:20:00 +0200 Subject: [PATCH 09/14] Introduce state mocking, move stuff around --- .../egress-composite/src/CompositeApp.tsx | 67 ++---------- .../src/ConfigurationContext.tsx | 32 ++++++ .../react/egress-composite/src/hooks/index.ts | 1 + .../src/hooks/useInitializeClient.ts | 100 ++++++++++++++++++ .../react/egress-composite/src/main.tsx | 26 +---- 5 files changed, 143 insertions(+), 83 deletions(-) create mode 100644 sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts diff --git a/sample-apps/react/egress-composite/src/CompositeApp.tsx b/sample-apps/react/egress-composite/src/CompositeApp.tsx index c3b1dd7f39..5ef6b8e1b7 100644 --- a/sample-apps/react/egress-composite/src/CompositeApp.tsx +++ b/sample-apps/react/egress-composite/src/CompositeApp.tsx @@ -1,72 +1,21 @@ -import { PropsWithChildren, useEffect, useState } from 'react'; +import { PropsWithChildren } from 'react'; import { - Call, - CallingState, StreamCallProvider, - StreamClientOptions, StreamTheme, StreamVideo, - StreamVideoClient, } from '@stream-io/video-react-sdk'; -import { useConfigurationContext } from './ConfigurationContext'; -import { EgressReadyNotificationProvider, useExternalCSS } from './hooks'; +import { + EgressReadyNotificationProvider, + useExternalCSS, + useInitializeClient, +} from './hooks'; import { UIDispatcher, LogoAndTitleOverlay } from './components'; import './CompositeApp.scss'; export const CompositeApp = () => { - const { - base_url: baseURL, - api_key: apiKey, - user_id: userId, - call_type: callType, - call_id: callId, - token, - } = useConfigurationContext(); - - const options: StreamClientOptions = {}; - if (baseURL) { - options.baseURL = baseURL; - } - const [client] = useState( - () => new StreamVideoClient(apiKey, options), - ); - - useEffect(() => { - client.connectUser( - { - id: userId, - }, - token, - ); - - return () => { - client.disconnectUser(); - }; - }, [client, token, userId]); - - const [activeCall, setActiveCall] = useState(); - useEffect(() => { - if (!client) return; - let joinInterrupted = false; - const call = client.call(callType, callId); - const currentCall = call.join().then(() => { - if (!joinInterrupted) { - setActiveCall(call); - } - return call; - }); - return () => { - joinInterrupted = true; - currentCall.then((theCall) => { - if (theCall && theCall.state.callingState !== CallingState.LEFT) { - theCall.leave(); - } - setActiveCall(undefined); - }); - }; - }, [client, callType, callId]); + const { client, call: activeCall } = useInitializeClient(); if (!client) { return

Connecting...

; @@ -89,7 +38,7 @@ export const CompositeApp = () => { ); }; -const StreamThemeWrapper = ({ children }: PropsWithChildren) => { +export const StreamThemeWrapper = ({ children }: PropsWithChildren) => { // TODO: background style useExternalCSS(); diff --git a/sample-apps/react/egress-composite/src/ConfigurationContext.tsx b/sample-apps/react/egress-composite/src/ConfigurationContext.tsx index 5a5c811db4..39d39cf85c 100644 --- a/sample-apps/react/egress-composite/src/ConfigurationContext.tsx +++ b/sample-apps/react/egress-composite/src/ConfigurationContext.tsx @@ -1,5 +1,9 @@ import { createContext, useContext } from 'react'; import { decode } from 'js-base64'; +import { StreamVideoParticipant } from '@stream-io/video-react-sdk'; + +const DEFAULT_USER_ID = 'egress'; +const DEFAULT_CALL_TYPE = 'default'; export type ConfigurationValue = { base_url?: string; @@ -15,6 +19,10 @@ export type ConfigurationValue = { layout?: 'grid' | 'single_participant' | 'spotlight' | 'mobile'; screenshare_layout?: 'single_participant' | 'spotlight'; + test_environment?: { + participants?: Partial[]; + }; + options: { 'video.background_color'?: string; 'video.scale_mode'?: 'fill' | 'fit'; @@ -72,3 +80,27 @@ export const extractPayloadFromToken = (token: string) => { }; export const useConfigurationContext = () => useContext(ConfigurationContext); + +export const applyConfigurationDefaults = ( + configuration: ConfigurationValue, +) => { + const { + // apply defaults + api_key = import.meta.env.VITE_STREAM_API_KEY as string, + token = import.meta.env.VITE_STREAM_USER_TOKEN as string, + user_id = (extractPayloadFromToken(token as string)['user_id'] ?? + DEFAULT_USER_ID) as string, + call_type = DEFAULT_CALL_TYPE, + options = {}, + ...rest + } = configuration; + + return { + api_key, + token, + user_id, + call_type, + options, + ...rest, + }; +}; diff --git a/sample-apps/react/egress-composite/src/hooks/index.ts b/sample-apps/react/egress-composite/src/hooks/index.ts index cb8cb3b2c6..675d1571cb 100644 --- a/sample-apps/react/egress-composite/src/hooks/index.ts +++ b/sample-apps/react/egress-composite/src/hooks/index.ts @@ -1,2 +1,3 @@ export * from './useExternalCSS'; export * from './useNotifyEgress'; +export * from './useInitializeClient'; diff --git a/sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts b/sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts new file mode 100644 index 0000000000..021331394f --- /dev/null +++ b/sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts @@ -0,0 +1,100 @@ +import { useEffect, useMemo, useState } from 'react'; +import { + CallingState, + StreamVideoClient, + Call, + StreamVideoParticipant, +} from '@stream-io/video-react-sdk'; + +import { useConfigurationContext } from '../ConfigurationContext'; + +const useVideoStateMocks = ({ + client, + call, +}: { + client: StreamVideoClient; + call: Call; +}) => { + const { test_environment: testEnvironment } = useConfigurationContext(); + + useEffect(() => { + if (!testEnvironment) return; + + const { participants = [] } = testEnvironment; + // @ts-ignore + client.writeableStateStore.registerCall(call); + call.state.setParticipants(participants as StreamVideoParticipant[]); + console.log({ client, call }); + }, [client, call, testEnvironment]); +}; + +export const useInitializeClient = () => { + const { + base_url: baseURL, + api_key: apiKey, + user_id: userId, + call_type: callType, + call_id: callId, + test_environment: testEnvironment, + token, + } = useConfigurationContext(); + + const client = useMemo(() => { + return new StreamVideoClient(apiKey, { + baseURL, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [apiKey, baseURL, testEnvironment]); + + // TODO: clean up this solution, have call always exist and check CallingState only + // probably wrap in useMemo instead as well + const [activeCall, setActiveCall] = useState(() => { + if (testEnvironment) { + return client.call(callType, callId); + } + + return; + }); + + // mock state of client and call if "test_environment" exists + useVideoStateMocks({ client, call: activeCall! }); + + useEffect(() => { + if (testEnvironment) return; + + client.connectUser( + { + id: userId, + }, + token, + ); + + return () => { + client.disconnectUser(); + }; + }, [client, testEnvironment, token, userId]); + + useEffect(() => { + if (!client || testEnvironment) return; + + let joinInterrupted = false; + const call = client.call(callType, callId); + const currentCall = call.join().then(() => { + if (!joinInterrupted) { + setActiveCall(call); + } + return call; + }); + return () => { + joinInterrupted = true; + currentCall.then((theCall) => { + if (theCall && theCall.state.callingState !== CallingState.LEFT) { + theCall.leave(); + } + setActiveCall(undefined); + }); + }; + }, [client, callType, callId, testEnvironment]); + + return { client, call: activeCall }; +}; diff --git a/sample-apps/react/egress-composite/src/main.tsx b/sample-apps/react/egress-composite/src/main.tsx index e121d40526..0f123a29b5 100644 --- a/sample-apps/react/egress-composite/src/main.tsx +++ b/sample-apps/react/egress-composite/src/main.tsx @@ -2,37 +2,15 @@ import { createRoot } from 'react-dom/client'; import { ConfigurationContext, ConfigurationValue, - extractPayloadFromToken, + applyConfigurationDefaults, } from './ConfigurationContext'; import { CompositeApp } from './CompositeApp'; import '@stream-io/video-react-sdk/dist/css/styles.css'; -const DEFAULT_USER_ID = 'egress'; -const DEFAULT_CALL_TYPE = 'default'; - // @ts-expect-error TODO: this is a global function, we need to declare it window.setupLayout = (configuration: ConfigurationValue) => { - const { - // apply defaults - api_key = import.meta.env.VITE_STREAM_API_KEY as string, - token = import.meta.env.VITE_STREAM_USER_TOKEN as string, - user_id = (extractPayloadFromToken(token as string)['user_id'] ?? - DEFAULT_USER_ID) as string, - call_type = DEFAULT_CALL_TYPE, - options = {}, - ...rest - } = configuration; - - const newConfiguration = { - api_key, - token, - user_id, - call_type, - options, - ...rest, - }; - + const newConfiguration = applyConfigurationDefaults(configuration); console.log('Mounting with config:', { configuration: newConfiguration }); createRoot(document.getElementById('root') as HTMLElement).render( From 0b1c0b5818087505e3e4d7d74bfddd4986a6f4a4 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Tue, 12 Sep 2023 17:20:28 +0200 Subject: [PATCH 10/14] Adjust configuration & tests --- .../egress-composite/playwright.config.ts | 3 + .../layouts.spec.ts/Layouts-grid-1.png | Bin 10711 -> 11016 bytes .../egress-composite/tests/layouts.spec.ts | 56 +++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/sample-apps/react/egress-composite/playwright.config.ts b/sample-apps/react/egress-composite/playwright.config.ts index d6ef59f434..2c3a8dd7d3 100644 --- a/sample-apps/react/egress-composite/playwright.config.ts +++ b/sample-apps/react/egress-composite/playwright.config.ts @@ -9,12 +9,15 @@ export default defineConfig({ retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'list', + // custom path to omit architecture/system from file name (darwin-amd64/darwin-arm64/linux-amd64...) snapshotPathTemplate: './tests/__screenshots__/{testFilePath}/{arg}{ext}', use: { headless: !!process.env.CI, trace: 'on-first-retry', viewport: { width: 1920, height: 1080 }, baseURL: 'http://localhost:5173', + // TODO: find out why custom data-test-id does not work + // testIdAttribute: 'data-testid', }, webServer: [ { diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-grid-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-grid-1.png index ae647c2d7966427bb6ab7517ddf5c9a141bdb74f..757166959f9fa2ed2eea0b02bf6e62d9726557cc 100644 GIT binary patch delta 718 zcmcZ}+z~dx((%qkFX==H*NgTGS(;vGZ?AoD=~7bgl3Du>^eC5&urbDk>zt@2~4S{j}~U|Ge9!v-v-)yIIrlH=^`2;|*O#iH6Gg^Xq>ay*r+|=fPnP zhTFe>HGRKP)4(>He}laK%^HTXlh-XK7c#llCtUhjv-vA0!a?Ex+ko$n3;s0~-$p_W+ zH2!2i?<WS0f&~8V@j9I0oSISzk9A%rTUtly{gTe~DWM4f DTx~V# delta 242 zcmeAOyB<8j(&)A!-(dw2R>zK-|Jsw41C9utt6H|S^6B)jGls{c7$D%!-t#XRq3k=( zn*$kTSfn0V*)lY=M=WP&V7QZ$ckiw}gTvW({}>;L{@FZHY$@kv1*R@Gff>m?rBy6Y zo%=sCPgZ1fHePp`nW3Viw2Fb@z}aWd?*3(Fxbo(mJVV?;{)C47-(@+>3_OPobpHN- z@vMW7mE{xD`zFTCiQ-o|fJSmN@h}`{pTxkx+3M-y7_#xA4=ewH cQI$n>Ba1qJ{)?GgcY-85UHx3vIVCg!00hZcYybcN diff --git a/sample-apps/react/egress-composite/tests/layouts.spec.ts b/sample-apps/react/egress-composite/tests/layouts.spec.ts index cf41611eb3..8b0cf0d02f 100644 --- a/sample-apps/react/egress-composite/tests/layouts.spec.ts +++ b/sample-apps/react/egress-composite/tests/layouts.spec.ts @@ -1,11 +1,14 @@ import { test as base, expect } from '@playwright/test'; import { customAlphabet } from 'nanoid'; import axios from 'axios'; +import { StreamVideoParticipant } from '@stream-io/video-react-sdk'; +import { ConfigurationValue } from '../src/ConfigurationContext'; const nanoid = customAlphabet('1234567890abcdefghijklmnop', 10); // TODO: move to some shared folder -const test = base.extend<{ callId: string }>({ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const buddyTest = base.extend<{ callId: string }>({ callId: async ({ page }, use) => { const callId = nanoid(); @@ -31,11 +34,55 @@ const test = base.extend<{ callId: string }>({ }, }); +const test = base.extend<{ callId: string }>({ + callId: async ({ page }, use) => { + const callId = nanoid(); + + await page.goto('/', { waitUntil: 'domcontentloaded' }); + + // run tests + await use(callId); + }, +}); + +const participants: Partial[] = [ + { + userId: 'john', + sessionId: '1', + publishedTracks: [], + isSpeaking: false, + }, + { + userId: 'jane', + name: 'Jane Strong', + sessionId: '2', + publishedTracks: [], + isSpeaking: false, + }, + { + userId: 'mark', + sessionId: '3', + publishedTracks: [], + isSpeaking: false, + }, + { + userId: 'martin', + sessionId: '4', + publishedTracks: [], + isSpeaking: false, + }, + { + userId: 'anne', + sessionId: '5', + publishedTracks: [], + isSpeaking: false, + }, +]; + test.describe('Layouts', () => { [ - { name: 'grid', participantCountPerWindow: 4 }, + { name: 'grid', participantCountPerWindow: 5 }, { name: 'single_participant', participantCountPerWindow: 1 }, - // egress is not filtered for this one { name: 'spotlight', participantCountPerWindow: 5 }, ].forEach((layout) => { test(`${layout.name}`, async ({ page, callId }) => { @@ -44,6 +91,9 @@ test.describe('Layouts', () => { window.setupLayout({ call_id: "${callId}", layout: "${layout.name}", + test_environment: ${JSON.stringify({ + participants, + } satisfies ConfigurationValue['test_environment'])} }); `, }); From a56d217ea38ecd55fdc153e64b367d0ed8ac70e8 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Tue, 12 Sep 2023 17:34:15 +0200 Subject: [PATCH 11/14] Account for pixel difference with ratio --- sample-apps/react/egress-composite/playwright.config.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sample-apps/react/egress-composite/playwright.config.ts b/sample-apps/react/egress-composite/playwright.config.ts index 2c3a8dd7d3..84b3b2438f 100644 --- a/sample-apps/react/egress-composite/playwright.config.ts +++ b/sample-apps/react/egress-composite/playwright.config.ts @@ -11,6 +11,12 @@ export default defineConfig({ reporter: 'list', // custom path to omit architecture/system from file name (darwin-amd64/darwin-arm64/linux-amd64...) snapshotPathTemplate: './tests/__screenshots__/{testFilePath}/{arg}{ext}', + expect: { + toHaveScreenshot: { + // to account for CI headless + maxDiffPixelRatio: 0.05, + }, + }, use: { headless: !!process.env.CI, trace: 'on-first-retry', From cc92ce422a90d9589b1d59a08e23a1f25fe19782 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Tue, 12 Sep 2023 21:50:54 +0200 Subject: [PATCH 12/14] Adjust GH workflow --- .github/workflows/egress-composite-e2e.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/egress-composite-e2e.yml b/.github/workflows/egress-composite-e2e.yml index 60ee84cd17..8ad7c8b71f 100644 --- a/.github/workflows/egress-composite-e2e.yml +++ b/.github/workflows/egress-composite-e2e.yml @@ -1,4 +1,4 @@ -name: Playwright Tests +name: Egress Composite E2E on: pull_request: types: @@ -27,13 +27,14 @@ jobs: steps: - uses: actions/checkout@v3 with: - fetch-depth: 0 + fetch-depth: 1 - name: Setup Node uses: actions/setup-node@v3 with: node-version: 18.x cache: 'yarn' + cache-dependency-path: 'yarn.lock' - name: Install dependencies run: yarn install --immutable @@ -43,7 +44,7 @@ jobs: NODE_ENV: production run: yarn build:react:deps - - name: 💾 Cache Playwright browsers + - name: Cache Playwright browsers uses: actions/cache@v3 id: playwright-cache with: @@ -60,9 +61,3 @@ jobs: - name: Run Playwright tests working-directory: sample-apps/react/egress-composite run: yarn buddy auth && yarn test:e2e - - - uses: actions/upload-artifact@v3 - with: - name: playwright-report - path: playwright-report/ - retention-days: 30 From 7a042bc37fcfa01f2055e0856afc8bbeeace6a4a Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Wed, 13 Sep 2023 00:46:20 +0200 Subject: [PATCH 13/14] Cleanup, updated test names, updated screenshots --- .../src/components/UIDispatcher.tsx | 1 - ...ld-render-default-screenshare-layout-1.png | Bin 0 -> 25067 bytes ...outs-Should-render-layout---default-1.png} | Bin ...Layouts-Should-render-layout---grid-1.png} | Bin ...-render-layout---single-participant-1.png} | Bin ...uts-Should-render-layout---spotlight-1.png | Bin 0 -> 10713 bytes .../react/egress-composite/tests/baseTests.ts | 43 ++++++ .../egress-composite/tests/layouts.spec.ts | 141 ++++++------------ .../react/egress-composite/tests/mocks.ts | 27 ++++ 9 files changed, 118 insertions(+), 94 deletions(-) create mode 100644 sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-default-screenshare-layout-1.png rename sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/{Layouts-spotlight-1.png => Layouts-Should-render-layout---default-1.png} (100%) rename sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/{Layouts-grid-1.png => Layouts-Should-render-layout---grid-1.png} (100%) rename sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/{Layouts-single-participant-1.png => Layouts-Should-render-layout---single-participant-1.png} (100%) create mode 100644 sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---spotlight-1.png create mode 100644 sample-apps/react/egress-composite/tests/baseTests.ts create mode 100644 sample-apps/react/egress-composite/tests/mocks.ts diff --git a/sample-apps/react/egress-composite/src/components/UIDispatcher.tsx b/sample-apps/react/egress-composite/src/components/UIDispatcher.tsx index 34677500c5..d11242310d 100644 --- a/sample-apps/react/egress-composite/src/components/UIDispatcher.tsx +++ b/sample-apps/react/egress-composite/src/components/UIDispatcher.tsx @@ -16,7 +16,6 @@ export const UIDispatcher = () => { const hasScreenShare = useHasOngoingScreenShare(); const DefaultView = layoutMap[layout]?.[0] ?? Spotlight; - const ScreenShareView = layoutMap[screenshare_layout]?.[1] ?? Spotlight; return hasScreenShare ? : ; diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-default-screenshare-layout-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-default-screenshare-layout-1.png new file mode 100644 index 0000000000000000000000000000000000000000..bc444c86a9417f5223eb795d84485be545f30cfe GIT binary patch literal 25067 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 RE|Z0;S_Ya0m#zQt{{UA1C=>ty literal 0 HcmV?d00001 diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-spotlight-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---default-1.png similarity index 100% rename from sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-spotlight-1.png rename to sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---default-1.png diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-grid-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---grid-1.png similarity index 100% rename from sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-grid-1.png rename to sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---grid-1.png diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-single-participant-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---single-participant-1.png similarity index 100% rename from sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-single-participant-1.png rename to sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---single-participant-1.png diff --git a/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---spotlight-1.png b/sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---spotlight-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6587bb6f210694df27d9dc4054381b223f75c14c GIT binary patch literal 10713 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-ahlL4m>3 z#WAE}&YRl@IU5WZSPr_p+5a@c*@0u7vFM%potDQUn1MQgpyB*(KYj?4;ejlZ0fgz$ z!oUMz2`Dl^Rl0B-fT|N5RR#))(EtIbhtU)Q4u;Vz0}ciT{Ds4vS%ifT5&hTLlf5MPY@^;I`85C0H$1(h{e*I|9Z>Bp>_c7!b#y4z_*{jd+p?Mhi zkf`=*fvndI1_sV{&{_b7(Izf9S&z2)!ND-v#03Y#XcHGw)(_pnA;NgGzdp1Vf1ucI rv_lV!(9z62nz=^@w;(0k;K>X7mhlVZU%$8rJoxD8>gTe~DWM4f#Tx8U literal 0 HcmV?d00001 diff --git a/sample-apps/react/egress-composite/tests/baseTests.ts b/sample-apps/react/egress-composite/tests/baseTests.ts new file mode 100644 index 0000000000..e5207db2ca --- /dev/null +++ b/sample-apps/react/egress-composite/tests/baseTests.ts @@ -0,0 +1,43 @@ +import { test as base } from '@playwright/test'; +import { customAlphabet } from 'nanoid'; +import axios from 'axios'; + +const nanoid = customAlphabet('1234567890abcdefghijklmnop', 10); + +export const testWithCallId = base.extend<{ callId: string }>({ + callId: async ({ page }, use) => { + const callId = nanoid(); + + await page.goto('/', { waitUntil: 'domcontentloaded' }); + + // run tests + await use(callId); + }, +}); + +// TODO: find better name +export const testWithBuddy = base.extend<{ callId: string }>({ + callId: async ({ page }, use) => { + const callId = nanoid(); + + // TODO: have proper abstractions with typing like StreamVideoBuddy.join(...) -> id and StreamVideoBuddy.teardown(id) + await axios.post('http://localhost:4567/stream-video-buddy?async=true', { + duration: 60, + 'call-id': callId, + 'user-count': 4, + }); + + // TODO: have proper ?asyncJoin=true + // which waits only for successfull call creation + // but asyncs user joins + await new Promise((resolve) => setTimeout(resolve, 2000)); + + await page.goto('/', { waitUntil: 'domcontentloaded' }); + + // run tests + await use(callId); + + // teardown + // TODO: await StreamVideoBuddy.teardown()... + }, +}); diff --git a/sample-apps/react/egress-composite/tests/layouts.spec.ts b/sample-apps/react/egress-composite/tests/layouts.spec.ts index 8b0cf0d02f..f5fd2477cf 100644 --- a/sample-apps/react/egress-composite/tests/layouts.spec.ts +++ b/sample-apps/react/egress-composite/tests/layouts.spec.ts @@ -1,111 +1,66 @@ -import { test as base, expect } from '@playwright/test'; -import { customAlphabet } from 'nanoid'; -import axios from 'axios'; -import { StreamVideoParticipant } from '@stream-io/video-react-sdk'; -import { ConfigurationValue } from '../src/ConfigurationContext'; +import { expect } from '@playwright/test'; -const nanoid = customAlphabet('1234567890abcdefghijklmnop', 10); +import { testWithCallId as test } from './baseTests'; +import { + generateScriptTagContent, + participants, + participantsWithScreenShare, +} from './mocks'; -// TODO: move to some shared folder -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const buddyTest = base.extend<{ callId: string }>({ - callId: async ({ page }, use) => { - const callId = nanoid(); - - // TODO: have proper abstractions with typing like StreamVideoBuddy.join(...) -> id and StreamVideoBuddy.teardown(id) - await axios.post('http://localhost:4567/stream-video-buddy?async=true', { - duration: 60, - 'call-id': callId, - 'user-count': 4, - }); - - // TODO: have proper ?asyncJoin=true - // which waits only for successfull call creation - // but asyncs user joins - await new Promise((resolve) => setTimeout(resolve, 2000)); - - await page.goto('/', { waitUntil: 'domcontentloaded' }); - - // run tests - await use(callId); - - // teardown - // TODO: await StreamVideoBuddy.teardown()... - }, -}); - -const test = base.extend<{ callId: string }>({ - callId: async ({ page }, use) => { - const callId = nanoid(); - - await page.goto('/', { waitUntil: 'domcontentloaded' }); - - // run tests - await use(callId); - }, -}); - -const participants: Partial[] = [ - { - userId: 'john', - sessionId: '1', - publishedTracks: [], - isSpeaking: false, - }, - { - userId: 'jane', - name: 'Jane Strong', - sessionId: '2', - publishedTracks: [], - isSpeaking: false, - }, - { - userId: 'mark', - sessionId: '3', - publishedTracks: [], - isSpeaking: false, - }, - { - userId: 'martin', - sessionId: '4', - publishedTracks: [], - isSpeaking: false, - }, - { - userId: 'anne', - sessionId: '5', - publishedTracks: [], - isSpeaking: false, - }, -]; +const DEFAULT_LAYOUT = 'spotlight'; test.describe('Layouts', () => { - [ - { name: 'grid', participantCountPerWindow: 5 }, - { name: 'single_participant', participantCountPerWindow: 1 }, - { name: 'spotlight', participantCountPerWindow: 5 }, - ].forEach((layout) => { - test(`${layout.name}`, async ({ page, callId }) => { + ( + [ + { name: undefined, participantCountPerWindow: 5 }, // default + { name: 'grid', participantCountPerWindow: 5 }, + { name: 'single_participant', participantCountPerWindow: 1 }, + { name: 'spotlight', participantCountPerWindow: 5 }, + ] as const + ).forEach((layout) => { + test(`Should render layout - ${layout.name ?? 'default'}`, async ({ + page, + callId, + }) => { await page.addScriptTag({ - content: ` - window.setupLayout({ - call_id: "${callId}", - layout: "${layout.name}", - test_environment: ${JSON.stringify({ + content: generateScriptTagContent({ + call_id: callId, + layout: layout.name, + test_environment: { participants, - } satisfies ConfigurationValue['test_environment'])} - }); - `, + }, + }), }); await expect(page.getByTestId('participant-view')).toHaveCount( layout.participantCountPerWindow, ); - await expect(page.getByTestId(layout.name)).toBeVisible(); + + await expect( + page.getByTestId(layout.name ?? DEFAULT_LAYOUT), + ).toBeVisible(); + await expect(page).toHaveScreenshot({ mask: [page.getByTestId('participant-view')], maskColor: 'lime', }); }); }); + + test('Should render default screenshare layout', async ({ page, callId }) => { + await page.addScriptTag({ + content: generateScriptTagContent({ + call_id: callId, + test_environment: { + participants: participantsWithScreenShare, + }, + }), + }); + + await expect(page.getByTestId('participant-view')).toHaveCount(6); + + await expect(page.getByTestId(DEFAULT_LAYOUT)).toBeVisible(); + + await expect(page).toHaveScreenshot(); + }); }); diff --git a/sample-apps/react/egress-composite/tests/mocks.ts b/sample-apps/react/egress-composite/tests/mocks.ts new file mode 100644 index 0000000000..bb495d58ab --- /dev/null +++ b/sample-apps/react/egress-composite/tests/mocks.ts @@ -0,0 +1,27 @@ +import { StreamVideoParticipant } from '@stream-io/video-react-sdk'; +import { ConfigurationValue } from '../src/ConfigurationContext'; + +const users = ['john', 'jane', 'mark', 'martin', 'anne']; + +export const generateScriptTagContent = (data: Partial) => { + return `window.setupLayout(${JSON.stringify(data)});`; +}; + +export const participants = users.map>( + (user, index) => ({ + userId: user, + sessionId: `${user}_${index}`, + publishedTracks: [], + isSpeaking: false, + }), +); + +export const participantsWithScreenShare = users.map< + Partial +>((user, index) => ({ + userId: user, + sessionId: `${user}_${index}`, + // FIXME: figure out why SfuModels cannot be imported + publishedTracks: !index ? [] : [3], + isSpeaking: false, +})); From 471a9b31062bd1f589eb375e94152177fbf91d91 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Wed, 13 Sep 2023 12:25:13 +0200 Subject: [PATCH 14/14] Cleanup - useInitializeClientAndCall --- .../egress-composite/src/CompositeApp.tsx | 18 +-- .../src/hooks/useInitializeClient.ts | 103 +++++++++--------- 2 files changed, 55 insertions(+), 66 deletions(-) diff --git a/sample-apps/react/egress-composite/src/CompositeApp.tsx b/sample-apps/react/egress-composite/src/CompositeApp.tsx index 5ef6b8e1b7..fde2b7cc71 100644 --- a/sample-apps/react/egress-composite/src/CompositeApp.tsx +++ b/sample-apps/react/egress-composite/src/CompositeApp.tsx @@ -8,29 +8,23 @@ import { import { EgressReadyNotificationProvider, useExternalCSS, - useInitializeClient, + useInitializeClientAndCall, } from './hooks'; import { UIDispatcher, LogoAndTitleOverlay } from './components'; import './CompositeApp.scss'; export const CompositeApp = () => { - const { client, call: activeCall } = useInitializeClient(); - - if (!client) { - return

Connecting...

; - } + const { client, call } = useInitializeClientAndCall(); return ( - {activeCall && ( - - - - - )} + + + + {/* */} diff --git a/sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts b/sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts index 021331394f..94166b6620 100644 --- a/sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts +++ b/sample-apps/react/egress-composite/src/hooks/useInitializeClient.ts @@ -1,6 +1,5 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo } from 'react'; import { - CallingState, StreamVideoClient, Call, StreamVideoParticipant, @@ -11,56 +10,38 @@ import { useConfigurationContext } from '../ConfigurationContext'; const useVideoStateMocks = ({ client, call, + enabled, }: { client: StreamVideoClient; call: Call; + enabled: boolean; }) => { const { test_environment: testEnvironment } = useConfigurationContext(); useEffect(() => { - if (!testEnvironment) return; + if (!enabled) return; - const { participants = [] } = testEnvironment; + const { participants = [] } = testEnvironment ?? {}; // @ts-ignore client.writeableStateStore.registerCall(call); call.state.setParticipants(participants as StreamVideoParticipant[]); console.log({ client, call }); - }, [client, call, testEnvironment]); + }, [client, call, testEnvironment, enabled]); }; -export const useInitializeClient = () => { - const { - base_url: baseURL, - api_key: apiKey, - user_id: userId, - call_type: callType, - call_id: callId, - test_environment: testEnvironment, - token, - } = useConfigurationContext(); - - const client = useMemo(() => { - return new StreamVideoClient(apiKey, { - baseURL, - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [apiKey, baseURL, testEnvironment]); - - // TODO: clean up this solution, have call always exist and check CallingState only - // probably wrap in useMemo instead as well - const [activeCall, setActiveCall] = useState(() => { - if (testEnvironment) { - return client.call(callType, callId); - } - - return; - }); - - // mock state of client and call if "test_environment" exists - useVideoStateMocks({ client, call: activeCall! }); +const useJoinCall = ({ + client, + call, + enabled, +}: { + client: StreamVideoClient; + call: Call; + enabled: boolean; +}) => { + const { token, user_id: userId } = useConfigurationContext(); useEffect(() => { - if (testEnvironment) return; + if (!enabled) return; client.connectUser( { @@ -72,29 +53,43 @@ export const useInitializeClient = () => { return () => { client.disconnectUser(); }; - }, [client, testEnvironment, token, userId]); + }, [client, enabled, token, userId]); useEffect(() => { - if (!client || testEnvironment) return; + if (!client || !enabled) return; - let joinInterrupted = false; - const call = client.call(callType, callId); - const currentCall = call.join().then(() => { - if (!joinInterrupted) { - setActiveCall(call); - } - return call; - }); + const callJoinPromise = call.join(); return () => { - joinInterrupted = true; - currentCall.then((theCall) => { - if (theCall && theCall.state.callingState !== CallingState.LEFT) { - theCall.leave(); - } - setActiveCall(undefined); + callJoinPromise.then(() => { + call.leave(); }); }; - }, [client, callType, callId, testEnvironment]); + }, [call, client, enabled]); +}; + +export const useInitializeClientAndCall = () => { + const { + base_url: baseURL, + api_key: apiKey, + call_type: callType, + call_id: callId, + test_environment: testEnvironment, + } = useConfigurationContext(); + + const client = useMemo(() => { + return new StreamVideoClient(apiKey, { + baseURL, + }); + }, [apiKey, baseURL]); + + const call = useMemo(() => { + return client.call(callType, callId); + }, [callId, callType, client]); + + // mock state of client and call if "test_environment" exists + useVideoStateMocks({ client, call, enabled: !!testEnvironment }); + // join call and proceed normally + useJoinCall({ client, call, enabled: !testEnvironment }); - return { client, call: activeCall }; + return { client, call }; };