Skip to content

Commit a942996

Browse files
🐛 refactor to not use async inside
1 parent 74dbbc9 commit a942996

File tree

2 files changed

+71
-4
lines changed

2 files changed

+71
-4
lines changed

packages/camera-web/src/Camera/hooks/useUserMedia.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ export function useUserMedia(
206206
const { handleError } = useMonitoring();
207207
const isActive = useRef(true);
208208

209+
let cameraPermissionState: PermissionStatus['state'] | null = null;
209210
useEffect(() => {
210211
return () => {
211212
isActive.current = false;
@@ -216,17 +217,18 @@ export function useUserMedia(
216217
let type = UserMediaErrorType.OTHER;
217218
if (err instanceof Error && err.name === 'NotAllowedError') {
218219
type = UserMediaErrorType.NOT_ALLOWED;
219-
try {
220-
const permission = await navigator.permissions.query({ name: 'camera' as PermissionName });
221-
switch (permission.state) {
220+
if (cameraPermissionState) {
221+
switch (cameraPermissionState) {
222222
case 'denied':
223223
type = UserMediaErrorType.NOT_ALLOWED_WEBPAGE;
224224
break;
225225
case 'granted':
226226
type = UserMediaErrorType.NOT_ALLOWED_BROWSER;
227227
break;
228+
default:
229+
type = UserMediaErrorType.NOT_ALLOWED;
228230
}
229-
} catch (error) {}
231+
}
230232
} else if (
231233
err instanceof Error &&
232234
Object.values(InvalidStreamErrorName).includes(err.name as InvalidStreamErrorName)
@@ -292,6 +294,14 @@ export function useUserMedia(
292294
}
293295
}
294296
};
297+
navigator.permissions
298+
.query({ name: 'camera' as PermissionName })
299+
.then((status) => {
300+
if (isActive.current) {
301+
cameraPermissionState = status.state;
302+
}
303+
})
304+
.catch(console.error);
295305
getUserMedia().catch(handleError);
296306
}, [constraints, stream, error, isLoading, lastConstraintsApplied]);
297307

packages/camera-web/test/Camera/hooks/useUserMedia.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ describe('useUserMedia hook', () => {
3232

3333
beforeEach(() => {
3434
gumMock = mockGetUserMedia();
35+
Object.defineProperty(global.navigator, 'permissions', {
36+
value: {
37+
query: jest.fn(() => Promise.reject()),
38+
},
39+
configurable: true,
40+
writable: true,
41+
});
3542
});
3643

3744
afterEach(() => {
@@ -125,6 +132,56 @@ describe('useUserMedia hook', () => {
125132
unmount();
126133
});
127134

135+
it('should return a NotAllowed for webpage error in case of camera permission error', async () => {
136+
const videoRef = { current: {} } as RefObject<HTMLVideoElement>;
137+
const nativeError = new Error();
138+
nativeError.name = 'NotAllowedError';
139+
mockGetUserMedia({ createMock: () => jest.fn(() => Promise.reject(nativeError)) });
140+
navigator.permissions.query = jest.fn(() =>
141+
Promise.resolve({ state: 'granted' } as PermissionStatus),
142+
);
143+
const { result } = renderUseUserMedia({ constraints: {}, videoRef });
144+
await waitFor(() => {
145+
expect(result.current).toEqual({
146+
stream: null,
147+
dimensions: null,
148+
error: {
149+
type: UserMediaErrorType.NOT_ALLOWED_BROWSER,
150+
nativeError,
151+
},
152+
isLoading: false,
153+
retry: expect.any(Function),
154+
availableCameraDevices: [],
155+
selectedCameraDeviceId: null,
156+
});
157+
});
158+
});
159+
160+
it('should return a NotAllowed for browser error in case of camera permission error', async () => {
161+
const videoRef = { current: {} } as RefObject<HTMLVideoElement>;
162+
const nativeError = new Error();
163+
nativeError.name = 'NotAllowedError';
164+
mockGetUserMedia({ createMock: () => jest.fn(() => Promise.reject(nativeError)) });
165+
navigator.permissions.query = jest.fn(() =>
166+
Promise.resolve({ state: 'denied' } as PermissionStatus),
167+
);
168+
const { result } = renderUseUserMedia({ constraints: {}, videoRef });
169+
await waitFor(() => {
170+
expect(result.current).toEqual({
171+
stream: null,
172+
dimensions: null,
173+
error: {
174+
type: UserMediaErrorType.NOT_ALLOWED_WEBPAGE,
175+
nativeError,
176+
},
177+
isLoading: false,
178+
retry: expect.any(Function),
179+
availableCameraDevices: [],
180+
selectedCameraDeviceId: null,
181+
});
182+
});
183+
});
184+
128185
it('should return an InvalidStream error if the stream has no tracks', async () => {
129186
const videoRef = { current: {} } as RefObject<HTMLVideoElement>;
130187
mockGetUserMedia({ tracks: [] });

0 commit comments

Comments
 (0)