From 1b5b5cfd68bea751a6fcc9a89d880fe6edf8f4e8 Mon Sep 17 00:00:00 2001 From: Anton Karlovskiy Date: Fri, 27 Mar 2020 03:30:28 +0300 Subject: [PATCH] [core] Bugfix/media capabilities use effect (#55) * doc: improved code styling in readme * infra: uninstalled react-dom * chore: cleaned up * infra: extracted supported from hook in useMediaCapabilities * doc: cleaned code snippet for useMediaCapabilities in README * [fix] added use effect dependencies in useMediaCapabilitiesDecodingInfo * fix: removed unnecessary code * [fix] fixed media capabilities unit test in the basic level * [fix] push supported into hook for easy unit test * [fix] uninstalled @babel/plugin-transform-runtime --- babel.config.js | 42 ++-- media-capabilities/index.js | 74 +++--- media-capabilities/media-capabilities.test.js | 229 +++++++++--------- package-lock.json | 39 ++- package.json | 1 + 5 files changed, 212 insertions(+), 173 deletions(-) diff --git a/babel.config.js b/babel.config.js index 6881bf1..0d671ff 100755 --- a/babel.config.js +++ b/babel.config.js @@ -1,21 +1,21 @@ -/* - * Copyright 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the 'License'); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -module.exports = { - presets: [ - "@babel/preset-env" - ] -}; +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module.exports = { + presets: [ + "@babel/preset-env" + ] +}; diff --git a/media-capabilities/index.js b/media-capabilities/index.js index 87b85f5..57f1a63 100644 --- a/media-capabilities/index.js +++ b/media-capabilities/index.js @@ -1,39 +1,35 @@ -/* - * Copyright 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { useState, useEffect } from 'react'; - -const supported = typeof window !== 'undefined' && 'mediaCapabilities' in navigator; - -const useMediaCapabilitiesDecodingInfo = (mediaDecodingConfig, initialMediaCapabilitiesInfo = {}) => { - initialMediaCapabilitiesInfo = { - ...initialMediaCapabilitiesInfo - }; - - const [mediaCapabilitiesInfo, setMediaCapabilitiesInfo] = useState(initialMediaCapabilitiesInfo); - - useEffect(() => { - supported && - navigator - .mediaCapabilities - .decodingInfo(mediaDecodingConfig) - .then(setMediaCapabilitiesInfo) - .catch(error => console.error(error)); - }, []); - - return { supported, mediaCapabilitiesInfo }; -}; - -export { useMediaCapabilitiesDecodingInfo }; \ No newline at end of file +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useState, useEffect } from 'react'; + +const useMediaCapabilitiesDecodingInfo = (mediaDecodingConfig, initialMediaCapabilitiesInfo = {}) => { + const supported = typeof navigator !== 'undefined' && 'mediaCapabilities' in navigator; + const [mediaCapabilitiesInfo, setMediaCapabilitiesInfo] = useState(initialMediaCapabilitiesInfo); + + useEffect(() => { + supported && + navigator + .mediaCapabilities + .decodingInfo(mediaDecodingConfig) + .then(setMediaCapabilitiesInfo) + .catch(error => console.error(error)); + }, [mediaDecodingConfig]); + + return { supported, mediaCapabilitiesInfo }; +}; + +export { useMediaCapabilitiesDecodingInfo }; diff --git a/media-capabilities/media-capabilities.test.js b/media-capabilities/media-capabilities.test.js index bd0842e..fc1e74c 100644 --- a/media-capabilities/media-capabilities.test.js +++ b/media-capabilities/media-capabilities.test.js @@ -1,112 +1,117 @@ -/* - * Copyright 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the 'License'); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { renderHook } from '@testing-library/react-hooks'; - -const mediaDecodingConfig = { - type: 'file', - audio: { - contentType: 'audio/mp3', - channels: 2, - bitrate: 132700, - samplerate: 5200 - } -}; - -const mediaCapabilitiesMapper = { - 'audio/mp3': { - powerEfficient: true, - smooth: true, - supported: true - } -}; - -describe('useMediaCapabilitiesDecodingInfo', () => { - test('should return supported flag on unsupported platforms', () => { - jest.isolateModules(() => { - const { useMediaCapabilitiesDecodingInfo } = require('.'); - const { result } = renderHook(() => useMediaCapabilitiesDecodingInfo(mediaDecodingConfig)); - - expect(result.current.supported).toEqual(false); - }) - }); - - test('should return supported flag on unsupported platforms and no config given', () => { - jest.isolateModules(() => { - const { useMediaCapabilitiesDecodingInfo } = require('.'); - const { result } = renderHook(() => useMediaCapabilitiesDecodingInfo()); - - expect(result.current.supported).toEqual(false); - }) - }); - - test('should return initialMediaCapabilitiesInfo for unsupported', () => { - jest.isolateModules(() => { - const initialMediaCapabilitiesInfo = { - supported: true, - smooth: false, - powerEfficient: true - }; - - const { useMediaCapabilitiesDecodingInfo } = require('.'); - const { result } = renderHook(() => useMediaCapabilitiesDecodingInfo(mediaDecodingConfig, initialMediaCapabilitiesInfo)); - - expect(result.current.mediaCapabilitiesInfo.supported).toBe(true); - expect(result.current.mediaCapabilitiesInfo.smooth).toEqual(false); - expect(result.current.mediaCapabilitiesInfo.powerEfficient).toEqual(true); - }); - }); - - test('should return supported flag when no config given', (done) => { - jest.isolateModules(() => { - global.navigator.mediaCapabilities = { - decodingInfo: () => new Promise(resolve => resolve(true)) - }; - - const { useMediaCapabilitiesDecodingInfo } = require('.'); - const { result, waitForNextUpdate } = renderHook(() => useMediaCapabilitiesDecodingInfo()); - - waitForNextUpdate() - .then(() => { - expect(result.current.supported).toEqual(true); - - done(); - }) - .catch(err => done(err)); - }); - }); - - test('should return mediaCapabilitiesInfo for given media configuration', (done) => { - jest.isolateModules(() => { - global.navigator.mediaCapabilities = { - decodingInfo: () => new Promise(resolve => resolve(mediaCapabilitiesMapper[mediaDecodingConfig.audio.contentType])) - }; - - const { useMediaCapabilitiesDecodingInfo } = require('.'); - const { result, waitForNextUpdate } = renderHook(() => useMediaCapabilitiesDecodingInfo(mediaDecodingConfig)); - - waitForNextUpdate() - .then(() => { - expect(result.current.mediaCapabilitiesInfo.powerEfficient).toEqual(true); - expect(result.current.mediaCapabilitiesInfo.smooth).toEqual(true); - expect(result.current.mediaCapabilitiesInfo.supported).toEqual(true); - - done(); - }) - .catch(err => done(err)); - }); - }); -}); \ No newline at end of file +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'babel-polyfill'; +import { renderHook } from '@testing-library/react-hooks'; + +const mediaDecodingConfig = { + type: 'file', + audio: { + contentType: 'audio/mp3', + channels: 2, + bitrate: 132700, + samplerate: 5200 + } +}; + +const mediaCapabilitiesMapper = { + 'audio/mp3': { + powerEfficient: true, + smooth: true, + supported: true + } +}; + +describe('useMediaCapabilitiesDecodingInfo', () => { + test('should return supported flag on unsupported platforms', () => { + const { useMediaCapabilitiesDecodingInfo } = require('./'); + const { result } = renderHook(() => useMediaCapabilitiesDecodingInfo(mediaDecodingConfig)); + + expect(result.current.supported).toEqual(false); + }); + + test('should return supported flag on unsupported platforms and no config given', () => { + const { useMediaCapabilitiesDecodingInfo } = require('./'); + const { result } = renderHook(() => useMediaCapabilitiesDecodingInfo()); + + expect(result.current.supported).toEqual(false); + }); + + test('should return initialMediaCapabilitiesInfo for unsupported', () => { + const initialMediaCapabilitiesInfo = { + supported: true, + smooth: false, + powerEfficient: true + }; + + const { useMediaCapabilitiesDecodingInfo } = require('./'); + const { result } = renderHook(() => useMediaCapabilitiesDecodingInfo(mediaDecodingConfig, initialMediaCapabilitiesInfo)); + + expect(result.current.mediaCapabilitiesInfo.supported).toBe(true); + expect(result.current.mediaCapabilitiesInfo.smooth).toEqual(false); + expect(result.current.mediaCapabilitiesInfo.powerEfficient).toEqual(true); + }); + + test('should return supported flag when no config given', async () => { + const originalError = console.error; + console.error = jest.fn(); + + const mockDecodingInfo = jest.fn().mockImplementation(() => Promise.resolve({ + supported: true + })); + + global.navigator.mediaCapabilities = { + decodingInfo: mockDecodingInfo + }; + + const { useMediaCapabilitiesDecodingInfo } = require('./'); + + try { + const { result, waitForNextUpdate } = renderHook(() => useMediaCapabilitiesDecodingInfo()); + await waitForNextUpdate(); + + expect(result.current.supported).toEqual(true); + } finally { + console.error = originalError; + } + }); + + test('should return mediaCapabilitiesInfo for given media configuration', async () => { + const originalError = console.error; + console.error = jest.fn(); + + const mockDecodingInfo = jest.fn().mockImplementation(() => Promise.resolve({ + ...mediaCapabilitiesMapper[mediaDecodingConfig.audio.contentType] + })); + + global.navigator.mediaCapabilities = { + decodingInfo: mockDecodingInfo + }; + + const { useMediaCapabilitiesDecodingInfo } = require('./'); + + try { + const { result, waitForNextUpdate } = renderHook(() => useMediaCapabilitiesDecodingInfo(mediaDecodingConfig)); + await waitForNextUpdate(); + + expect(result.current.mediaCapabilitiesInfo.powerEfficient).toEqual(true); + expect(result.current.mediaCapabilitiesInfo.smooth).toEqual(true); + expect(result.current.mediaCapabilitiesInfo.supported).toEqual(true); + } finally { + console.error = originalError; + } + }); +}); diff --git a/package-lock.json b/package-lock.json index 079b725..5b34c33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-adaptive-hooks", - "version": "0.0.8", + "version": "0.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1505,6 +1505,25 @@ "integrity": "sha512-fDXP68ZqcinZO2WCiimCL9zhGjGXOnn3D33zvbh+yheZ/qOrNVVDDIBtAaM3Faz8TRvQzHiRKsu3hfrBAhEncQ==", "dev": true }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + } + } + }, "babel-preset-jest": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", @@ -1515,6 +1534,24 @@ "babel-plugin-jest-hoist": "^24.9.0" } }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + } + } + }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", diff --git a/package.json b/package.json index 3258d3d..03c6f46 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "devDependencies": { "@babel/preset-env": "^7.5.5", "@testing-library/react-hooks": "^1.1.0", + "babel-polyfill": "^6.26.0", "jest": "^24.8.0", "microbundle": "0.11.0", "react": "16.9.0",