Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ jobs:
- store_artifacts:
path: coverage

- run:
name: "Eslint"
command: npm run lint -- --max-warnings 0

- run:
name: "Build app with Firebase auth disabled"
command: npm run build
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 0.2.3

### Bugfixes

- Update `VideoInputList` so that the app doesn't crash when the deivce is changed while the camera is off. [#412](https://github.com/twilio/twilio-video-app-react/pull/412)

### Dependency Upgrades

- `react-scripts` has been upgraded from 3.4.4 to 4.0.2. [#416](https://github.com/twilio/twilio-video-app-react/pull/416)

## 0.2.2

### Bugfixes
Expand Down
1,324 changes: 789 additions & 535 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "twilio-video-app-react",
"version": "0.2.2",
"version": "0.2.3",
"private": true,
"license": "Apache-2.0",
"dependencies": {
Expand Down Expand Up @@ -28,10 +28,10 @@
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2",
"react-scripts": "4.0.2",
"react-scripts": "4.0.3",
"strip-color": "^0.1.0",
"twilio": "^3.39.3",
"twilio-video": "^2.11.0",
"twilio-video": "^2.12.0",
"typescript": "^3.8.3"
},
"devDependencies": {
Expand All @@ -53,7 +53,7 @@
"puppeteer": "^5.3.1",
"react-test-renderer": "^16.12.0",
"start-server-and-test": "^1.10.8",
"ts-jest": "^24.3.0"
"ts-jest": "^26.5.1"
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
Expand All @@ -67,7 +67,7 @@
"build": "node ./scripts/build.js",
"test": "jest",
"eject": "react-scripts eject",
"lint": "eslint src/**/*.{ts,tsx}",
"lint": "eslint src",
"server": "node server.js",
"test:ci": "jest --ci --runInBand --reporters=default --reporters=jest-junit --coverage",
"cypress:open": "cypress open",
Expand All @@ -78,7 +78,10 @@
"eslintConfig": {
"extends": "react-app",
"rules": {
"no-shadow": "warn"
"no-shadow": "off",
"@typescript-eslint/no-shadow": [
"warn"
]
}
},
"browserslist": {
Expand Down
3 changes: 2 additions & 1 deletion src/components/IntroContainer/swoosh.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export default `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='296' height='378' viewBox='0 0 296 378'%3E%3Cdefs%3E%3ClinearGradient id='utbttnlrpc' x1='78.976%25' x2='63.882%25' y1='60.873%25' y2='45.554%25'%3E%3Cstop offset='0%25' stop-opacity='0'/%3E%3Cstop offset='100%25'/%3E%3C/linearGradient%3E%3ClinearGradient id='aim8r3oczd' x1='78.976%25' x2='63.882%25' y1='56.106%25' y2='47.503%25'%3E%3Cstop offset='0%25' stop-opacity='0'/%3E%3Cstop offset='100%25'/%3E%3C/linearGradient%3E%3Cpath id='5tk4i6f80a' d='M0 0H296V378H0z'/%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cmask id='m1ihwluuxb' fill='%23fff'%3E%3Cuse xlink:href='%235tk4i6f80a'/%3E%3C/mask%3E%3Cuse fill='%23DE5858' xlink:href='%235tk4i6f80a'/%3E%3Cg mask='url(%23m1ihwluuxb)'%3E%3Cg%3E%3Cpath fill='url(%23utbttnlrpc)' d='M0 286.83c87.695-83.937 175.802-132.682 264.323-146.233 132.78-20.328 183.24 4.255 225.143-23.414 73.409-48.471 93.039-15.154 148.326-20.892 44.84-4.654 98.48-77.401 135.81-91.717C795.596-3.86 821.469.801 851.22 18.56L891 476.5H0V286.83z' opacity='.06' transform='translate(-457 -22.5)'/%3E%3Cpath fill='url(%23aim8r3oczd)' d='M137 604.5c63.759-109.686 155.8-165.124 276.126-166.315 180.488-1.786 157.888-146.686 387.11-146.33 229.223.356 170.665-151.786 341.36-166.888 113.797-10.068 180.265 10.685 199.404 62.26V604.5H137z' opacity='.08' transform='translate(-457 -22.5)'/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A");`;
const Swoosh = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='296' height='378' viewBox='0 0 296 378'%3E%3Cdefs%3E%3ClinearGradient id='utbttnlrpc' x1='78.976%25' x2='63.882%25' y1='60.873%25' y2='45.554%25'%3E%3Cstop offset='0%25' stop-opacity='0'/%3E%3Cstop offset='100%25'/%3E%3C/linearGradient%3E%3ClinearGradient id='aim8r3oczd' x1='78.976%25' x2='63.882%25' y1='56.106%25' y2='47.503%25'%3E%3Cstop offset='0%25' stop-opacity='0'/%3E%3Cstop offset='100%25'/%3E%3C/linearGradient%3E%3Cpath id='5tk4i6f80a' d='M0 0H296V378H0z'/%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cmask id='m1ihwluuxb' fill='%23fff'%3E%3Cuse xlink:href='%235tk4i6f80a'/%3E%3C/mask%3E%3Cuse fill='%23DE5858' xlink:href='%235tk4i6f80a'/%3E%3Cg mask='url(%23m1ihwluuxb)'%3E%3Cg%3E%3Cpath fill='url(%23utbttnlrpc)' d='M0 286.83c87.695-83.937 175.802-132.682 264.323-146.233 132.78-20.328 183.24 4.255 225.143-23.414 73.409-48.471 93.039-15.154 148.326-20.892 44.84-4.654 98.48-77.401 135.81-91.717C795.596-3.86 821.469.801 851.22 18.56L891 476.5H0V286.83z' opacity='.06' transform='translate(-457 -22.5)'/%3E%3Cpath fill='url(%23aim8r3oczd)' d='M137 604.5c63.759-109.686 155.8-165.124 276.126-166.315 180.488-1.786 157.888-146.686 387.11-146.33 229.223.356 170.665-151.786 341.36-166.888 113.797-10.068 180.265 10.685 199.404 62.26V604.5H137z' opacity='.08' transform='translate(-457 -22.5)'/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A");`;
export default Swoosh;
92 changes: 0 additions & 92 deletions src/components/MenuBar/FlipCameraButton/FlipCameraButton.test.tsx

This file was deleted.

55 changes: 53 additions & 2 deletions src/components/MenuBar/Menu/Menu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ import AboutDialog from '../../AboutDialog/AboutDialog';
import { Button, MenuItem } from '@material-ui/core';
import DeviceSelectionDialog from '../../DeviceSelectionDialog/DeviceSelectionDialog';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import FlipCameraIcon from '../../../icons/FlipCameraIcon';
import Menu from './Menu';
import MenuContainer from '@material-ui/core/Menu';
import MoreIcon from '@material-ui/icons/MoreVert';
import { shallow } from 'enzyme';
import useFlipCameraToggle from '../../../hooks/useFlipCameraToggle/useFlipCameraToggle';
import useMediaQuery from '@material-ui/core/useMediaQuery';

jest.mock('../../../hooks/useFlipCameraToggle/useFlipCameraToggle');
jest.mock('@material-ui/core/useMediaQuery');
const mockUseFlipCameraToggle = useFlipCameraToggle as jest.Mock<any>;
const mockUseMediaQuery = useMediaQuery as jest.Mock<boolean>;

describe('the Menu component', () => {
describe('on desktop devices', () => {
beforeAll(() => {
mockUseMediaQuery.mockImplementation(() => false);
mockUseFlipCameraToggle.mockImplementation(() => ({
flipCameraDisabled: false,
flipCameraSupported: false,
}));
});

it('should open the Menu when the Button is clicked', () => {
Expand All @@ -30,7 +38,7 @@ describe('the Menu component', () => {
expect(wrapper.find(AboutDialog).prop('open')).toBe(false);
wrapper
.find(MenuItem)
.at(0)
.at(1)
.simulate('click');
expect(wrapper.find(AboutDialog).prop('open')).toBe(true);
});
Expand All @@ -40,7 +48,7 @@ describe('the Menu component', () => {
expect(wrapper.find(DeviceSelectionDialog).prop('open')).toBe(false);
wrapper
.find(MenuItem)
.at(1)
.at(0)
.simulate('click');
expect(wrapper.find(DeviceSelectionDialog).prop('open')).toBe(true);
});
Expand All @@ -50,17 +58,60 @@ describe('the Menu component', () => {
expect(wrapper.find(ExpandMoreIcon).exists()).toBe(true);
expect(wrapper.find(MoreIcon).exists()).toBe(false);
});

it('should not render the Flip Camera button', () => {
const wrapper = shallow(<Menu />);
expect(wrapper.find(FlipCameraIcon).exists()).toBe(false);
});
});

describe('on mobile devices', () => {
beforeAll(() => {
mockUseMediaQuery.mockImplementation(() => true);
mockUseFlipCameraToggle.mockImplementation(() => ({
flipCameraDisabled: false,
flipCameraSupported: true,
}));
});

it('should render the correct icon', () => {
const wrapper = shallow(<Menu />);
expect(wrapper.find(ExpandMoreIcon).exists()).toBe(false);
expect(wrapper.find(MoreIcon).exists()).toBe(true);
});

it('should render non-disabled Flip Camera button when flipCameraSupported is true', () => {
const wrapper = shallow(<Menu />);
expect(wrapper.find(FlipCameraIcon).exists()).toBe(true);
expect(
wrapper
.find(MenuItem)
.at(0)
.prop('disabled')
).toBe(false);
});

it('should render a disabled Flip Camera button when flipCameraSupported is true, and flipCameraDisabled is true', () => {
mockUseFlipCameraToggle.mockImplementationOnce(() => ({
flipCameraDisabled: true,
flipCameraSupported: true,
}));
const wrapper = shallow(<Menu />);
expect(wrapper.find(FlipCameraIcon).exists()).toBe(true);
expect(
wrapper
.find(MenuItem)
.at(0)
.prop('disabled')
).toBe(true);
});

it('should not render Flip Camera button when flipCameraSupported is false', () => {
mockUseFlipCameraToggle.mockImplementationOnce(() => ({
flipCameraSupported: false,
}));
const wrapper = shallow(<Menu />);
expect(wrapper.find(FlipCameraIcon).exists()).toBe(false);
});
});
});
36 changes: 32 additions & 4 deletions src/components/MenuBar/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,22 @@ import AboutDialog from '../../AboutDialog/AboutDialog';
import Button from '@material-ui/core/Button';
import DeviceSelectionDialog from '../../DeviceSelectionDialog/DeviceSelectionDialog';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import FlipCameraIcon from '../../../icons/FlipCameraIcon';
import InfoIconOutlined from '../../../icons/InfoIconOutlined';
import MenuContainer from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import MoreIcon from '@material-ui/icons/MoreVert';
import SettingsIcon from '../../../icons/SettingsIcon';
import Typography from '@material-ui/core/Typography';
import { Theme, useMediaQuery } from '@material-ui/core';
import { styled, Theme, useMediaQuery } from '@material-ui/core';
import useFlipCameraToggle from '../../../hooks/useFlipCameraToggle/useFlipCameraToggle';

export const IconContainer = styled('div')({
display: 'flex',
justifyContent: 'center',
width: '1.5em',
marginRight: '0.3em',
});

export default function Menu(props: { buttonClassName?: string }) {
const isMobile = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'));
Expand All @@ -16,6 +27,7 @@ export default function Menu(props: { buttonClassName?: string }) {
const [settingsOpen, setSettingsOpen] = useState(false);

const anchorRef = useRef<HTMLButtonElement>(null);
const { flipCameraDisabled, toggleFacingMode, flipCameraSupported } = useFlipCameraToggle();

return (
<>
Expand All @@ -42,12 +54,28 @@ export default function Menu(props: { buttonClassName?: string }) {
horizontal: 'center',
}}
>
<MenuItem onClick={() => setAboutOpen(true)}>
<Typography variant="body1">About</Typography>
</MenuItem>
{flipCameraSupported && (
<MenuItem disabled={flipCameraDisabled} onClick={toggleFacingMode}>
<IconContainer>
<FlipCameraIcon />
</IconContainer>
<Typography variant="body1">Flip Camera</Typography>
</MenuItem>
)}

<MenuItem onClick={() => setSettingsOpen(true)}>
<IconContainer>
<SettingsIcon />
</IconContainer>
<Typography variant="body1">Audio and Video Settings</Typography>
</MenuItem>

<MenuItem onClick={() => setAboutOpen(true)}>
<IconContainer>
<InfoIconOutlined />
</IconContainer>
<Typography variant="body1">About</Typography>
</MenuItem>
</MenuContainer>
<AboutDialog
open={aboutOpen}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ describe('the useGetPreflightTokens hook', () => {
});

it('should return the tokenError property when there is an error', async () => {
const mockGetToken = jest.fn(() => Promise.reject('mockError'));
mockUseAppState.mockImplementationOnce(() => ({ getToken: mockGetToken }));
const mockGetTokenFn = jest.fn(() => Promise.reject('mockError'));
mockUseAppState.mockImplementationOnce(() => ({ getToken: mockGetTokenFn }));
const { result, waitForNextUpdate } = renderHook(useGetPreflightTokens);
await waitForNextUpdate();
expect(result.current).toEqual({ tokens: undefined, tokenError: 'mockError' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export default function useGetPreflightTokens() {
const subscriberIdentity = 'participant-' + nanoid();

Promise.all([getToken(publisherIdentity, roomName), getToken(subscriberIdentity, roomName)])
.then(tokens => {
setTokens(tokens);
.then(newTokens => {
setTokens(newTokens);
setIsFetching(false);
})
.catch(error => setTokenError(error));
Expand Down
1 change: 0 additions & 1 deletion src/components/Snackbar/Snackbar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { shallow } from 'enzyme';
import CloseIcon from '@material-ui/icons/Close';
import React from 'react';
import Snackbar from './Snackbar';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const useStyles = makeStyles({
},
});

export default function({ children }: { children: React.ReactElement }) {
export default function UnsupportedBrowserWarning({ children }: { children: React.ReactElement }) {
const classes = useStyles();

if (!Video.isSupported) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { act, renderHook } from '@testing-library/react-hooks';
import EventEmitter from 'events';

import useHandleRoomDisconnectionErrors from './useHandleRoomDisconnectionErrors';
import { Room, TwilioError } from 'twilio-video';
import { Room } from 'twilio-video';

describe('the useHandleRoomDisconnectionErrors hook', () => {
let mockRoom: any = new EventEmitter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Callback } from '../../../types';

export default function useHandleRoomDisconnectionErrors(room: Room, onError: Callback) {
useEffect(() => {
const onDisconnected = (room: Room, error: TwilioError) => {
const onDisconnected = (_: Room, error: TwilioError) => {
if (error) {
onError(error);
}
Expand Down
Loading