1 |
|
2 |
|
3 |
|
4 |
|
5 | import test from "ava";
|
6 | import * as sinon from "sinon";
|
7 |
|
8 | import { BrowserHelper, Camera, CameraAccess } from "..";
|
9 |
|
10 | const getUserMediaStub: sinon.SinonStub = sinon.stub();
|
11 | const getVideoTracksStub: sinon.SinonStub = sinon.stub();
|
12 | const applyConstraintsStub: sinon.SinonStub = sinon.stub();
|
13 | const getCapabilitiesStub: sinon.SinonStub = sinon.stub();
|
14 | const getConstraintsStub: sinon.SinonStub = sinon.stub();
|
15 | const getSettingsStub: sinon.SinonStub = sinon.stub();
|
16 | const stopStub: sinon.SinonStub = sinon.stub();
|
17 | const getSourcesStub: sinon.SinonStub = sinon.stub();
|
18 | const enumerateDevicesStub: sinon.SinonStub = sinon.stub();
|
19 |
|
20 | const stubs: sinon.SinonStub[] = [
|
21 | getUserMediaStub,
|
22 | getVideoTracksStub,
|
23 | applyConstraintsStub,
|
24 | getCapabilitiesStub,
|
25 | getConstraintsStub,
|
26 | getSettingsStub,
|
27 | stopStub,
|
28 | getSourcesStub,
|
29 | enumerateDevicesStub
|
30 | ];
|
31 |
|
32 | const emptyCamera: MediaDeviceInfo = {
|
33 | deviceId: "1",
|
34 | groupId: "1",
|
35 | kind: "videoinput",
|
36 | label: "",
|
37 | toJSON(): MediaDeviceInfo {
|
38 | return this;
|
39 | }
|
40 | };
|
41 |
|
42 | const fakeCamera1: MediaDeviceInfo = {
|
43 | deviceId: "1",
|
44 | groupId: "1",
|
45 | kind: "videoinput",
|
46 | label: "Fake Camera Device (back)",
|
47 | toJSON(): MediaDeviceInfo {
|
48 | return this;
|
49 | }
|
50 | };
|
51 |
|
52 | const fakeCamera2: MediaDeviceInfo = {
|
53 | deviceId: "2",
|
54 | groupId: "1",
|
55 | kind: "videoinput",
|
56 | label: "Fake Camera Device (front)",
|
57 | toJSON(): MediaDeviceInfo {
|
58 | return this;
|
59 | }
|
60 | };
|
61 |
|
62 | const fakeCamera3: MediaDeviceInfo = {
|
63 | deviceId: "3",
|
64 | groupId: "1",
|
65 | kind: "videoinput",
|
66 | label: "Fake Camera Device (posteriore)",
|
67 | toJSON(): MediaDeviceInfo {
|
68 | return this;
|
69 | }
|
70 | };
|
71 |
|
72 | const fakeCamera4: MediaDeviceInfo = {
|
73 | deviceId: "4",
|
74 | groupId: "1",
|
75 | kind: "videoinput",
|
76 | label: "Fake Camera Device (unknown)",
|
77 | toJSON(): MediaDeviceInfo {
|
78 | return this;
|
79 | }
|
80 | };
|
81 |
|
82 | const fakeCamera5: MediaDeviceInfo = {
|
83 | deviceId: "5",
|
84 | groupId: "1",
|
85 | kind: "videoinput",
|
86 | label: "Fake Camera Device (unknown)",
|
87 | toJSON(): MediaDeviceInfo {
|
88 | return this;
|
89 | }
|
90 | };
|
91 |
|
92 | const fakeCamera6: MediaDeviceInfo = {
|
93 | deviceId: "6",
|
94 | groupId: "1",
|
95 | kind: "videoinput",
|
96 | label: "Fake Camera Device 5MP",
|
97 | toJSON(): MediaDeviceInfo {
|
98 | return this;
|
99 | }
|
100 | };
|
101 |
|
102 | const fakeCamera7: MediaDeviceInfo = {
|
103 | deviceId: "7",
|
104 | groupId: "1",
|
105 | kind: "videoinput",
|
106 | label: "Fake Camera Device 2MP",
|
107 | toJSON(): MediaDeviceInfo {
|
108 | return this;
|
109 | }
|
110 | };
|
111 |
|
112 | const fakeCamera8: MediaDeviceInfo = {
|
113 | deviceId: "8",
|
114 | groupId: "1",
|
115 | kind: "videoinput",
|
116 | label: "camera2 8, facing back",
|
117 | toJSON(): MediaDeviceInfo {
|
118 | return this;
|
119 | }
|
120 | };
|
121 |
|
122 | const fakeCamera9: MediaDeviceInfo = {
|
123 | deviceId: "9",
|
124 | groupId: "1",
|
125 | kind: "videoinput",
|
126 | label: "camera2 9, facing back",
|
127 | toJSON(): MediaDeviceInfo {
|
128 | return this;
|
129 | }
|
130 | };
|
131 |
|
132 | const illegalFakeCamera1: MediaDeviceInfo = <MediaDeviceInfo>(<unknown>{
|
133 | deviceId: "10",
|
134 | groupId: "1",
|
135 | kind: "videoinput"
|
136 | });
|
137 |
|
138 | const legacyFakeCamera1: MediaDeviceInfo = <MediaDeviceInfo>(<unknown>{
|
139 | groupId: "1",
|
140 | kind: "videoinput",
|
141 | label: "Fake Camera Device (back)"
|
142 | });
|
143 |
|
144 | const legacyFakeCamera2: MediaDeviceInfo = <MediaDeviceInfo>(<unknown>{
|
145 | deviceId: "100",
|
146 | groupId: "1",
|
147 | kind: "video",
|
148 | label: "Fake Camera Device (front)"
|
149 | });
|
150 |
|
151 | const fakeMicrophone: MediaDeviceInfo = {
|
152 | deviceId: "1000",
|
153 | groupId: "1",
|
154 | kind: "audioinput",
|
155 | label: "Fake Microhpone Device #2",
|
156 | toJSON(): MediaDeviceInfo {
|
157 | return this;
|
158 | }
|
159 | };
|
160 |
|
161 | function fakeCompatibleBrowser(): void {
|
162 | Object.defineProperty(navigator, "mediaDevices", {
|
163 | value: {
|
164 | getUserMedia: getUserMediaStub.resolves({
|
165 | getTracks: getVideoTracksStub,
|
166 | getVideoTracks: getVideoTracksStub
|
167 | })
|
168 | },
|
169 | configurable: true
|
170 | });
|
171 | getVideoTracksStub.returns([
|
172 | {
|
173 | applyConstraints: applyConstraintsStub.resolves(),
|
174 | getCapabilities: getCapabilitiesStub.returns(123),
|
175 | getConstraints: getConstraintsStub.returns(456),
|
176 | getSettings: getSettingsStub.returns(789),
|
177 | stop: stopStub
|
178 | }
|
179 | ]);
|
180 |
|
181 | window.Blob = <Window["Blob"]>(<unknown>(() => {
|
182 | return;
|
183 | }));
|
184 | window.URL = <Window["URL"]>(<unknown>{
|
185 | createObjectURL: () => {
|
186 | return;
|
187 | }
|
188 | });
|
189 | window.Worker = () => {
|
190 | return;
|
191 | };
|
192 | window.WebAssembly = {};
|
193 | }
|
194 |
|
195 | function resetStubs(): void {
|
196 | stubs.forEach(mock => {
|
197 | mock.resetHistory();
|
198 | });
|
199 | }
|
200 |
|
201 | function getFakeMediaStreamTrack(deviceId: string, facingMode: string, label: string): MediaStreamTrack {
|
202 | return <MediaStreamTrack>(<unknown>{
|
203 | getSettings(): object {
|
204 | return {
|
205 | deviceId,
|
206 | facingMode
|
207 | };
|
208 | },
|
209 | label
|
210 | });
|
211 | }
|
212 |
|
213 | function deepObjectArrayCopy<T>(objectArray: T[]): T[] {
|
214 | return objectArray.map(object => {
|
215 | return { ...object };
|
216 | });
|
217 | }
|
218 |
|
219 | test.beforeEach(() => {
|
220 | window.MediaStreamTrack = undefined;
|
221 | navigator.enumerateDevices = undefined;
|
222 | });
|
223 |
|
224 | test.serial("getCameras (errors)", async t => {
|
225 | resetStubs();
|
226 | let error: Error = await t.throwsAsync(CameraAccess.getCameras());
|
227 | t.is(error.name, "UnsupportedBrowserError");
|
228 | t.false(getUserMediaStub.called);
|
229 | t.false(getSourcesStub.called);
|
230 | fakeCompatibleBrowser();
|
231 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub
|
232 | .onFirstCall()
|
233 | .resolves([])
|
234 | .onSecondCall()
|
235 | .rejects(new Error("Test error 1"));
|
236 | resetStubs();
|
237 | error = await t.throwsAsync(CameraAccess.getCameras());
|
238 | t.is(error.message, "Test error 1");
|
239 | t.true(getUserMediaStub.called);
|
240 | t.false(getSourcesStub.called);
|
241 | enumerateDevicesStub.reset();
|
242 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([]);
|
243 | navigator.mediaDevices.getUserMedia = getUserMediaStub.rejects(new Error("Test error 2"));
|
244 | resetStubs();
|
245 | error = await t.throwsAsync(CameraAccess.getCameras());
|
246 | t.is(error.message, "Test error 2");
|
247 | t.true(getUserMediaStub.called);
|
248 | t.false(getSourcesStub.called);
|
249 | });
|
250 |
|
251 | test.serial("getCameras (MediaStreamTrack.getSources)", async t => {
|
252 | fakeCompatibleBrowser();
|
253 |
|
254 | window.MediaStreamTrack = {};
|
255 | resetStubs();
|
256 | let error: Error = await t.throwsAsync(CameraAccess.getCameras());
|
257 | t.is(error.name, "UnsupportedBrowserError");
|
258 | t.false(getUserMediaStub.called);
|
259 |
|
260 | window.MediaStreamTrack = {
|
261 | getSources: getSourcesStub.callsArgWith(0, null)
|
262 | };
|
263 | resetStubs();
|
264 | error = await t.throwsAsync(CameraAccess.getCameras());
|
265 | t.is(error.name, "UnsupportedBrowserError");
|
266 | t.false(getUserMediaStub.called);
|
267 | t.true(getSourcesStub.called);
|
268 | window.MediaStreamTrack = {
|
269 | getSources: getSourcesStub.callsArgWith(0, [emptyCamera])
|
270 | };
|
271 | resetStubs();
|
272 | let cameras: Camera[] = await CameraAccess.getCameras();
|
273 | t.true(getUserMediaStub.called);
|
274 | t.true(getSourcesStub.called);
|
275 | t.not(cameras, null);
|
276 | t.is(cameras.length, 1);
|
277 | window.MediaStreamTrack = {
|
278 | getSources: getSourcesStub.callsArgWith(0, [
|
279 | fakeCamera1,
|
280 | fakeCamera2,
|
281 | legacyFakeCamera1,
|
282 | legacyFakeCamera2,
|
283 | fakeMicrophone
|
284 | ])
|
285 | };
|
286 | resetStubs();
|
287 | cameras = await CameraAccess.getCameras();
|
288 | t.false(getUserMediaStub.called);
|
289 | t.true(getSourcesStub.called);
|
290 | t.not(cameras, null);
|
291 | t.is(cameras.length, 4);
|
292 | resetStubs();
|
293 | const newCameras: Camera[] = await CameraAccess.getCameras();
|
294 | t.false(getUserMediaStub.called);
|
295 | t.true(getSourcesStub.called);
|
296 | t.deepEqual(cameras, newCameras);
|
297 | t.is(cameras[0].deviceId, fakeCamera1.deviceId);
|
298 | t.is(cameras[0].label, fakeCamera1.label);
|
299 | t.is(cameras[0].cameraType, Camera.Type.BACK);
|
300 | t.is(cameras[0].currentResolution, undefined);
|
301 | t.is(cameras[1].deviceId, fakeCamera2.deviceId);
|
302 | t.is(cameras[1].label, fakeCamera2.label);
|
303 | t.is(cameras[1].cameraType, Camera.Type.FRONT);
|
304 | t.is(cameras[1].currentResolution, undefined);
|
305 | t.is(cameras[2].deviceId, "");
|
306 | t.is(cameras[2].label, legacyFakeCamera1.label);
|
307 | t.is(cameras[2].cameraType, Camera.Type.BACK);
|
308 | t.is(cameras[2].currentResolution, undefined);
|
309 | t.is(cameras[3].deviceId, legacyFakeCamera2.deviceId);
|
310 | t.is(cameras[3].label, legacyFakeCamera2.label);
|
311 | t.is(cameras[3].cameraType, Camera.Type.FRONT);
|
312 | t.is(cameras[3].currentResolution, undefined);
|
313 | });
|
314 |
|
315 | test.serial("getCameras (navigator.enumerateDevices & navigator.mediaDevices.enumerateDevices)", async t => {
|
316 | fakeCompatibleBrowser();
|
317 | window.MediaStreamTrack = {
|
318 | getSources: getSourcesStub
|
319 | };
|
320 | for (const baseObject of [navigator, navigator.mediaDevices]) {
|
321 | baseObject.enumerateDevices = enumerateDevicesStub.resolves([emptyCamera]);
|
322 | resetStubs();
|
323 | let cameras: Camera[] = await CameraAccess.getCameras();
|
324 | t.true(getUserMediaStub.called);
|
325 | t.true(enumerateDevicesStub.called);
|
326 | t.false(getSourcesStub.called);
|
327 | t.not(cameras, null);
|
328 | t.is(cameras.length, 1);
|
329 | baseObject.enumerateDevices = enumerateDevicesStub.resolves([
|
330 | fakeCamera1,
|
331 | fakeCamera2,
|
332 | illegalFakeCamera1,
|
333 | fakeMicrophone
|
334 | ]);
|
335 | resetStubs();
|
336 | cameras = await CameraAccess.getCameras();
|
337 | t.false(getUserMediaStub.called);
|
338 | t.true(enumerateDevicesStub.called);
|
339 | t.false(getSourcesStub.called);
|
340 | t.not(cameras, null);
|
341 | t.is(cameras.length, 3);
|
342 | resetStubs();
|
343 | const newCameras: Camera[] = await CameraAccess.getCameras();
|
344 | t.false(getUserMediaStub.called);
|
345 | t.true(enumerateDevicesStub.called);
|
346 | t.false(getSourcesStub.called);
|
347 | t.deepEqual(cameras, newCameras);
|
348 | t.is(cameras[0].deviceId, fakeCamera1.deviceId);
|
349 | t.is(cameras[0].label, fakeCamera1.label);
|
350 | t.is(cameras[0].cameraType, Camera.Type.BACK);
|
351 | t.is(cameras[0].currentResolution, undefined);
|
352 | t.is(cameras[1].deviceId, fakeCamera2.deviceId);
|
353 | t.is(cameras[1].label, fakeCamera2.label);
|
354 | t.is(cameras[1].cameraType, Camera.Type.FRONT);
|
355 | t.is(cameras[1].currentResolution, undefined);
|
356 | t.is(cameras[2].deviceId, illegalFakeCamera1.deviceId);
|
357 | t.is(cameras[2].label, "");
|
358 | t.is(cameras[2].cameraType, Camera.Type.FRONT);
|
359 | t.is(cameras[2].currentResolution, undefined);
|
360 | }
|
361 | });
|
362 |
|
363 | test.serial("getCameras (internationalized label)", async t => {
|
364 | fakeCompatibleBrowser();
|
365 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([fakeCamera3]);
|
366 | resetStubs();
|
367 | const cameras: Camera[] = await CameraAccess.getCameras();
|
368 | t.not(cameras, null);
|
369 | t.is(cameras.length, 1);
|
370 | t.is(cameras[0].deviceId, fakeCamera3.deviceId);
|
371 | t.is(cameras[0].label, fakeCamera3.label);
|
372 | t.is(cameras[0].cameraType, Camera.Type.BACK);
|
373 | t.is(cameras[0].currentResolution, undefined);
|
374 | });
|
375 |
|
376 | test.serial("getCameras (no front/back label information)", async t => {
|
377 | fakeCompatibleBrowser();
|
378 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([fakeCamera4, fakeCamera5]);
|
379 | resetStubs();
|
380 | const cameras: Camera[] = await CameraAccess.getCameras();
|
381 | t.not(cameras, null);
|
382 | t.is(cameras.length, 2);
|
383 | t.is(cameras[0].deviceId, fakeCamera4.deviceId);
|
384 | t.is(cameras[0].label, fakeCamera4.label);
|
385 | t.is(cameras[0].cameraType, Camera.Type.FRONT);
|
386 | t.is(cameras[0].currentResolution, undefined);
|
387 | t.is(cameras[1].deviceId, fakeCamera5.deviceId);
|
388 | t.is(cameras[1].label, fakeCamera5.label);
|
389 | t.is(cameras[1].cameraType, Camera.Type.BACK);
|
390 | t.is(cameras[1].currentResolution, undefined);
|
391 | });
|
392 |
|
393 | test.serial("getCameras (resolution label information)", async t => {
|
394 | fakeCompatibleBrowser();
|
395 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([fakeCamera6, fakeCamera7]);
|
396 | resetStubs();
|
397 | const cameras: Camera[] = await CameraAccess.getCameras();
|
398 | t.not(cameras, null);
|
399 | t.is(cameras.length, 2);
|
400 | t.is(cameras[0].deviceId, fakeCamera6.deviceId);
|
401 | t.is(cameras[0].label, fakeCamera6.label);
|
402 | t.is(cameras[0].cameraType, Camera.Type.BACK);
|
403 | t.is(cameras[0].currentResolution, undefined);
|
404 | t.is(cameras[1].deviceId, fakeCamera7.deviceId);
|
405 | t.is(cameras[1].label, fakeCamera7.label);
|
406 | t.is(cameras[1].cameraType, Camera.Type.FRONT);
|
407 | t.is(cameras[1].currentResolution, undefined);
|
408 | });
|
409 |
|
410 | test.serial("getCameras (quickly consecutively)", async t => {
|
411 | fakeCompatibleBrowser();
|
412 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([fakeCamera1, fakeCamera2]);
|
413 | resetStubs();
|
414 | await CameraAccess.getCameras();
|
415 | t.is(enumerateDevicesStub.callCount, 2);
|
416 | resetStubs();
|
417 |
|
418 | CameraAccess.getCameras();
|
419 | const cameras: Camera[] = await CameraAccess.getCameras();
|
420 | t.is(enumerateDevicesStub.callCount, 2);
|
421 | t.not(cameras, null);
|
422 | t.is(cameras.length, 2);
|
423 | t.is(cameras[0].deviceId, fakeCamera1.deviceId);
|
424 | t.is(cameras[0].label, fakeCamera1.label);
|
425 | t.is(cameras[0].cameraType, Camera.Type.BACK);
|
426 | t.is(cameras[0].currentResolution, undefined);
|
427 | t.is(cameras[1].deviceId, fakeCamera2.deviceId);
|
428 | t.is(cameras[1].label, fakeCamera2.label);
|
429 | t.is(cameras[1].cameraType, Camera.Type.FRONT);
|
430 | t.is(cameras[1].currentResolution, undefined);
|
431 | });
|
432 |
|
433 | test.serial("adjustCamerasFromMainCameraStream", async t => {
|
434 | fakeCompatibleBrowser();
|
435 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([fakeCamera1, fakeCamera2]);
|
436 | const originalCameras: Camera[] = await CameraAccess.getCameras();
|
437 | let cams: Camera[] = deepObjectArrayCopy(originalCameras);
|
438 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(<MediaStreamTrack>(<unknown>{}), cams), undefined);
|
439 | t.is(cams[0].cameraType, Camera.Type.BACK);
|
440 | t.is(cams[1].cameraType, Camera.Type.FRONT);
|
441 | cams = deepObjectArrayCopy(originalCameras);
|
442 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("1", "environment", ""), cams), cams[0]);
|
443 | t.is(cams[0].cameraType, Camera.Type.BACK);
|
444 | t.is(cams[1].cameraType, Camera.Type.FRONT);
|
445 | cams = deepObjectArrayCopy(originalCameras);
|
446 | t.is(
|
447 | CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("2", "environment", ""), cams),
|
448 | undefined
|
449 | );
|
450 | t.is(cams[0].cameraType, Camera.Type.BACK);
|
451 | t.is(cams[1].cameraType, Camera.Type.BACK);
|
452 | cams = deepObjectArrayCopy(originalCameras);
|
453 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("2", "user", ""), cams), undefined);
|
454 | t.is(cams[0].cameraType, Camera.Type.BACK);
|
455 | t.is(cams[1].cameraType, Camera.Type.FRONT);
|
456 | });
|
457 |
|
458 | test.serial("adjustCamerasFromMainCameraStream (unknown cameras)", async t => {
|
459 | fakeCompatibleBrowser();
|
460 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([fakeCamera4, fakeCamera5]);
|
461 | const originalCameras: Camera[] = await CameraAccess.getCameras();
|
462 | let cams: Camera[] = deepObjectArrayCopy(originalCameras);
|
463 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(<MediaStreamTrack>(<unknown>{}), cams), undefined);
|
464 | t.is(cams[0].cameraType, Camera.Type.FRONT);
|
465 | t.is(cams[1].cameraType, Camera.Type.BACK);
|
466 | cams = deepObjectArrayCopy(originalCameras);
|
467 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("4", "environment", ""), cams), cams[0]);
|
468 | t.is(cams[0].cameraType, Camera.Type.BACK);
|
469 | t.is(cams[1].cameraType, Camera.Type.FRONT);
|
470 | cams = deepObjectArrayCopy(originalCameras);
|
471 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("5", "environment", ""), cams), cams[1]);
|
472 | t.is(cams[0].cameraType, Camera.Type.FRONT);
|
473 | t.is(cams[1].cameraType, Camera.Type.BACK);
|
474 | cams = deepObjectArrayCopy(originalCameras);
|
475 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("5", "user", ""), cams), undefined);
|
476 | t.is(cams[0].cameraType, Camera.Type.FRONT);
|
477 | t.is(cams[1].cameraType, Camera.Type.BACK);
|
478 | });
|
479 |
|
480 | test.serial("adjustCamerasFromMainCameraStream (triple camera setup)", async t => {
|
481 |
|
482 | fakeCompatibleBrowser();
|
483 | navigator.mediaDevices.enumerateDevices = enumerateDevicesStub.resolves([fakeCamera2, fakeCamera9, fakeCamera8]);
|
484 | const originalCameras: Camera[] = await CameraAccess.getCameras();
|
485 | let cams: Camera[] = deepObjectArrayCopy(originalCameras);
|
486 | t.is(CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("8", "environment", ""), cams), cams[2]);
|
487 | t.is(cams[0].cameraType, Camera.Type.FRONT);
|
488 | t.is(cams[1].cameraType, Camera.Type.BACK);
|
489 | t.is(cams[2].cameraType, Camera.Type.BACK);
|
490 | cams = deepObjectArrayCopy(originalCameras);
|
491 | t.is(
|
492 | CameraAccess.adjustCamerasFromMainCameraStream(getFakeMediaStreamTrack("9", "environment", ""), cams),
|
493 | undefined
|
494 | );
|
495 | t.is(cams[0].cameraType, Camera.Type.FRONT);
|
496 | t.is(cams[1].cameraType, Camera.Type.BACK);
|
497 | t.is(cams[2].cameraType, Camera.Type.BACK);
|
498 | });
|
499 |
|
500 |
|
501 | test.serial("accessCameraStream", async t => {
|
502 | fakeCompatibleBrowser();
|
503 | const fakeEmptyBackCamera: Camera = {
|
504 | deviceId: "",
|
505 | label: "",
|
506 | cameraType: Camera.Type.BACK
|
507 | };
|
508 |
|
509 | resetStubs();
|
510 | let mediaStream: MediaStream = await CameraAccess.accessCameraStream(0, fakeEmptyBackCamera);
|
511 | t.true(getUserMediaStub.called);
|
512 | t.deepEqual(getUserMediaStub.args[0][0], {
|
513 | audio: false,
|
514 | video: {
|
515 | facingMode: { ideal: "environment" },
|
516 | width: { min: 1400, ideal: 1920, max: 1920 },
|
517 | height: { min: 900, ideal: 1440, max: 1440 }
|
518 | }
|
519 | });
|
520 | t.not(mediaStream, null);
|
521 |
|
522 | const fakeEmptyFrontCamera: Camera = {
|
523 | deviceId: "",
|
524 | label: "",
|
525 | cameraType: Camera.Type.FRONT
|
526 | };
|
527 |
|
528 | resetStubs();
|
529 | mediaStream = await CameraAccess.accessCameraStream(0, fakeEmptyFrontCamera);
|
530 | t.true(getUserMediaStub.called);
|
531 | t.deepEqual(getUserMediaStub.args[0][0], {
|
532 | audio: false,
|
533 | video: {
|
534 | facingMode: { ideal: "user" },
|
535 | width: { min: 1400, ideal: 1920, max: 1920 },
|
536 | height: { min: 900, ideal: 1440, max: 1440 }
|
537 | }
|
538 | });
|
539 | t.not(mediaStream, null);
|
540 |
|
541 | const fakeCamera: Camera = {
|
542 | deviceId: fakeCamera1.deviceId,
|
543 | label: fakeCamera1.label,
|
544 | cameraType: Camera.Type.BACK
|
545 | };
|
546 |
|
547 | resetStubs();
|
548 | mediaStream = await CameraAccess.accessCameraStream(0, fakeCamera);
|
549 | t.true(getUserMediaStub.called);
|
550 | t.deepEqual(getUserMediaStub.args[0][0], {
|
551 | audio: false,
|
552 | video: {
|
553 | deviceId: { exact: fakeCamera.deviceId },
|
554 | width: { min: 1400, ideal: 1920, max: 1920 },
|
555 | height: { min: 900, ideal: 1440, max: 1440 }
|
556 | }
|
557 | });
|
558 | t.not(mediaStream, null);
|
559 | resetStubs();
|
560 | mediaStream = await CameraAccess.accessCameraStream(1, fakeCamera);
|
561 | t.true(getUserMediaStub.called);
|
562 | t.deepEqual(getUserMediaStub.args[0][0], {
|
563 | audio: false,
|
564 | video: {
|
565 | deviceId: { exact: fakeCamera.deviceId },
|
566 | width: { min: 1200, ideal: 1920, max: 1920 },
|
567 | height: { min: 900, ideal: 1200, max: 1200 }
|
568 | }
|
569 | });
|
570 | t.not(mediaStream, null);
|
571 | resetStubs();
|
572 | mediaStream = await CameraAccess.accessCameraStream(2, fakeCamera);
|
573 | t.true(getUserMediaStub.called);
|
574 | t.deepEqual(getUserMediaStub.args[0][0], {
|
575 | audio: false,
|
576 | video: {
|
577 | deviceId: { exact: fakeCamera.deviceId },
|
578 | width: { min: 1080, ideal: 1920, max: 1920 },
|
579 | height: { min: 900, ideal: 1080, max: 1080 }
|
580 | }
|
581 | });
|
582 | t.not(mediaStream, null);
|
583 | resetStubs();
|
584 | mediaStream = await CameraAccess.accessCameraStream(3, fakeCamera);
|
585 | t.true(getUserMediaStub.called);
|
586 | t.deepEqual(getUserMediaStub.args[0][0], {
|
587 | audio: false,
|
588 | video: {
|
589 | deviceId: { exact: fakeCamera.deviceId },
|
590 | width: { min: 960, ideal: 1280, max: 1440 },
|
591 | height: { min: 480, ideal: 960, max: 960 }
|
592 | }
|
593 | });
|
594 | t.not(mediaStream, null);
|
595 | resetStubs();
|
596 | mediaStream = await CameraAccess.accessCameraStream(4, fakeCamera);
|
597 | t.true(getUserMediaStub.called);
|
598 | t.deepEqual(getUserMediaStub.args[0][0], {
|
599 | audio: false,
|
600 | video: {
|
601 | deviceId: { exact: fakeCamera.deviceId },
|
602 | width: { min: 720, ideal: 1280, max: 1440 },
|
603 | height: { min: 480, ideal: 720, max: 768 }
|
604 | }
|
605 | });
|
606 | t.not(mediaStream, null);
|
607 | resetStubs();
|
608 | mediaStream = await CameraAccess.accessCameraStream(5, fakeCamera);
|
609 | t.true(getUserMediaStub.called);
|
610 | t.deepEqual(getUserMediaStub.args[0][0], {
|
611 | audio: false,
|
612 | video: {
|
613 | deviceId: { exact: fakeCamera.deviceId },
|
614 | width: { min: 640, ideal: 960, max: 1440 },
|
615 | height: { min: 480, ideal: 720, max: 720 }
|
616 | }
|
617 | });
|
618 | t.not(mediaStream, null);
|
619 | resetStubs();
|
620 | mediaStream = await CameraAccess.accessCameraStream(6, fakeCamera);
|
621 | t.true(getUserMediaStub.called);
|
622 | t.deepEqual(getUserMediaStub.args[0][0], {
|
623 | audio: false,
|
624 | video: {
|
625 | deviceId: { exact: fakeCamera.deviceId }
|
626 | }
|
627 | });
|
628 | t.not(mediaStream, null);
|
629 | });
|
630 |
|
631 | test.serial("accessCameraStream (Safari)", async t => {
|
632 | fakeCompatibleBrowser();
|
633 | BrowserHelper.userAgentInfo.setUA(
|
634 | "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) " +
|
635 | "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
|
636 | );
|
637 |
|
638 | const fakeCamera: Camera = {
|
639 | deviceId: fakeCamera1.deviceId,
|
640 | label: fakeCamera1.label,
|
641 | cameraType: Camera.Type.BACK
|
642 | };
|
643 |
|
644 | resetStubs();
|
645 | let mediaStream: MediaStream = await CameraAccess.accessCameraStream(0, fakeCamera);
|
646 | t.true(getUserMediaStub.called);
|
647 | t.deepEqual(getUserMediaStub.args[0][0], {
|
648 | audio: false,
|
649 | video: {
|
650 | deviceId: { exact: fakeCamera.deviceId },
|
651 | width: { min: 1400, ideal: 1920, max: 1920 },
|
652 | height: { min: 900, ideal: 1080, max: 1440 }
|
653 | }
|
654 | });
|
655 | t.not(mediaStream, null);
|
656 | resetStubs();
|
657 | mediaStream = await CameraAccess.accessCameraStream(1, fakeCamera);
|
658 | t.true(getUserMediaStub.called);
|
659 | t.deepEqual(getUserMediaStub.args[0][0], {
|
660 | audio: false,
|
661 | video: {
|
662 | deviceId: { exact: fakeCamera.deviceId },
|
663 | width: { min: 1200, ideal: 1600, max: 1920 },
|
664 | height: { min: 900, ideal: 1080, max: 1200 }
|
665 | }
|
666 | });
|
667 | t.not(mediaStream, null);
|
668 | resetStubs();
|
669 | mediaStream = await CameraAccess.accessCameraStream(2, fakeCamera);
|
670 | t.true(getUserMediaStub.called);
|
671 | t.deepEqual(getUserMediaStub.args[0][0], {
|
672 | audio: false,
|
673 | video: {
|
674 | deviceId: { exact: fakeCamera.deviceId },
|
675 | width: { min: 1080, ideal: 1600, max: 1920 },
|
676 | height: { min: 900, ideal: 900, max: 1080 }
|
677 | }
|
678 | });
|
679 | t.not(mediaStream, null);
|
680 | resetStubs();
|
681 | mediaStream = await CameraAccess.accessCameraStream(3, fakeCamera);
|
682 | t.true(getUserMediaStub.called);
|
683 | t.deepEqual(getUserMediaStub.args[0][0], {
|
684 | audio: false,
|
685 | video: {
|
686 | deviceId: { exact: fakeCamera.deviceId },
|
687 | width: { min: 960, ideal: 1280, max: 1440 },
|
688 | height: { min: 480, ideal: 720, max: 960 }
|
689 | }
|
690 | });
|
691 | t.not(mediaStream, null);
|
692 | resetStubs();
|
693 | mediaStream = await CameraAccess.accessCameraStream(4, fakeCamera);
|
694 | t.true(getUserMediaStub.called);
|
695 | t.deepEqual(getUserMediaStub.args[0][0], {
|
696 | audio: false,
|
697 | video: {
|
698 | deviceId: { exact: fakeCamera.deviceId },
|
699 | width: { min: 720, ideal: 1024, max: 1440 },
|
700 | height: { min: 480, ideal: 768, max: 768 }
|
701 | }
|
702 | });
|
703 | t.not(mediaStream, null);
|
704 | resetStubs();
|
705 | mediaStream = await CameraAccess.accessCameraStream(5, fakeCamera);
|
706 | t.true(getUserMediaStub.called);
|
707 | t.deepEqual(getUserMediaStub.args[0][0], {
|
708 | audio: false,
|
709 | video: {
|
710 | deviceId: { exact: fakeCamera.deviceId },
|
711 | width: { min: 640, ideal: 800, max: 1440 },
|
712 | height: { min: 480, ideal: 600, max: 720 }
|
713 | }
|
714 | });
|
715 | t.not(mediaStream, null);
|
716 | resetStubs();
|
717 | mediaStream = await CameraAccess.accessCameraStream(6, fakeCamera);
|
718 | t.true(getUserMediaStub.called);
|
719 | t.deepEqual(getUserMediaStub.args[0][0], {
|
720 | audio: false,
|
721 | video: {
|
722 | deviceId: { exact: fakeCamera.deviceId }
|
723 | }
|
724 | });
|
725 | t.not(mediaStream, null);
|
726 | });
|