Skip to content

Commit ffea3e1

Browse files
authored
Video 10586 synk pr (#733)
1 parent 6e481aa commit ffea3e1

File tree

31 files changed

+38503
-35814
lines changed

31 files changed

+38503
-35814
lines changed

jest.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ module.exports = {
22
roots: ['<rootDir>/src', '<rootDir>/server'],
33
transform: {
44
'^.+\\.tsx?$': 'ts-jest',
5+
"^.+\\.(css)$": "<rootDir>/jest.transform.js"
56
},
7+
transformIgnorePatterns: ["/node_modules/(?!swiper|swiper/react|ssr-window|dom7)"],
8+
testEnvironment: 'jsdom',
69
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
710
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
811
snapshotSerializers: ['enzyme-to-json/serializer'],
@@ -13,5 +16,8 @@ module.exports = {
1316
coveragePathIgnorePatterns: ['node_modules', 'src/icons'],
1417
moduleNameMapper: {
1518
'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': '<rootDir>/src/__mocks__/fileMock.ts',
19+
"swiper/react": "<rootDir>/node_modules/swiper/react/swiper-react.js",
20+
"swiper/css": "<rootDir>/node_modules/swiper/swiper.min.css",
21+
"swiper/css/pagination": "<rootDir>/node_modules/swiper/modules/autoplay/pagination.min.css"
1622
},
1723
};

jest.transform.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const path = require("path")
2+
3+
// Requried to fix Swiper CSS imports during jest executions, it transforms imports into filenames
4+
module.exports = {
5+
process: (_src, filename) => `module.exports = ${JSON.stringify(path.basename(filename))};`
6+
}

package-lock.json

Lines changed: 38341 additions & 35694 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
"@material-ui/icons": "^4.11.2",
99
"@material-ui/lab": "^4.0.0-alpha.60",
1010
"@twilio-labs/plugin-rtc": "^0.8.2",
11-
"@twilio/conversations": "^1.2.3",
11+
"@twilio/conversations": "^2.1.0",
1212
"@twilio/video-processors": "^1.0.1",
1313
"@twilio/video-room-monitor": "^1.0.0",
1414
"@types/d3-timer": "^1.0.9",
1515
"@types/dotenv": "^8.2.0",
1616
"@types/express": "^4.17.11",
1717
"@types/fscreen": "^1.0.1",
18-
"@types/jest": "^25.1.0",
18+
"@types/jest": "^27.5.2",
1919
"@types/linkify-it": "^3.0.0",
2020
"@types/lodash.throttle": "^4.1.6",
2121
"@types/node": "^12.12.26",
@@ -27,7 +27,7 @@
2727
"cross-env": "^7.0.2",
2828
"d3-timer": "^1.0.10",
2929
"express": "^4.17.1",
30-
"firebase": "^7.24.0",
30+
"firebase": "^9.9.0",
3131
"firebase-admin": "^9.5.0",
3232
"fscreen": "^1.0.2",
3333
"husky": "^3.1.0",
@@ -39,7 +39,7 @@
3939
"react": "^16.12.0",
4040
"react-dom": "^16.12.0",
4141
"react-router-dom": "^5.1.2",
42-
"react-scripts": "4.0.3",
42+
"react-scripts": "5.0.0",
4343
"rimraf": "3.0.2",
4444
"strip-color": "^0.1.0",
4545
"swiper": "^8.1.5",
@@ -73,7 +73,7 @@
7373
"puppeteer": "^5.3.1",
7474
"react-test-renderer": "^16.12.0",
7575
"start-server-and-test": "^1.10.8",
76-
"ts-jest": "^26.5.1"
76+
"ts-jest": "^27.0.1"
7777
},
7878
"lint-staged": {
7979
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
@@ -83,15 +83,15 @@
8383
},
8484
"scripts": {
8585
"postinstall": "rimraf public/virtualbackground && copyfiles -f node_modules/@twilio/video-processors/dist/build/* public/virtualbackground",
86-
"start": "concurrently npm:server npm:dev",
86+
"start": "npx cross-env REACT_APP_VERSION=$(node -e \"console.log(require('./package.json').version)\") concurrently npm:server npm:dev",
8787
"dev": "react-scripts start",
8888
"build": "node ./scripts/build.js",
89-
"test": "cross-env TZ=utc jest",
89+
"test": "cross-env TZ=utc jest --config jest.config.js",
9090
"eject": "react-scripts eject",
9191
"lint": "eslint src server",
9292
"server": "ts-node -T -P server/tsconfig.json server/index.ts",
9393
"typescript:server": "tsc --noEmit -p server/",
94-
"test:ci": "cross-env TZ=utc jest --ci --runInBand --reporters=default --reporters=jest-junit --coverage --silent",
94+
"test:ci": "cross-env TZ=utc jest --config jest.config.js --ci --runInBand --reporters=default --reporters=jest-junit --coverage --silent",
9595
"cypress:open": "cypress open",
9696
"cypress:run": "cypress run --browser chrome",
9797
"cypress:ci": "cross-env CYPRESS_baseUrl=http://localhost:8081 start-server-and-test server http://localhost:8081 cypress:run",

scripts/build.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ You may serve it with a static server:
1717
1818
Find out more about deployment here:
1919
20-
bit.ly/CRA-deploy
20+
https://cra.link/deployment
2121
2222
`;
2323

@@ -40,6 +40,7 @@ class Filter extends Transform {
4040

4141
// Colors normally don't work when using spawn(), so here we re-enable colors.
4242
process.env.FORCE_COLOR = require('supports-color').stdout.level;
43+
process.env.REACT_APP_VERSION = require(__dirname + "/../package.json").version
4344

4445
const buildProcess = spawn('node', [require.resolve('react-scripts/scripts/build')]);
4546

src/App.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { shallow } from 'enzyme';
77
import useHeight from './hooks/useHeight/useHeight';
88
import useRoomState from './hooks/useRoomState/useRoomState';
99

10-
jest.mock('swiper/react/swiper-react.js', () => ({
10+
jest.mock('swiper/react', () => ({
1111
Swiper: jest.fn(),
1212
SwiperSlide: jest.fn(),
1313
}));

src/__mocks__/@twilio/conversations.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/components/AboutDialog/AboutDialog.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { render } from '@testing-library/react';
44
import { useAppState } from '../../state';
55

66
jest.mock('twilio-video', () => ({ version: '1.2', isSupported: true }));
7-
jest.mock('../../../package.json', () => ({ version: '1.3' }));
87
jest.mock('../../state');
98

109
const mockUseAppState = useAppState as jest.Mock<any>;
@@ -22,6 +21,7 @@ describe('the AboutDialog component', () => {
2221
});
2322

2423
it('should display the package.json version', () => {
24+
process.env.REACT_APP_VERSION = '1.3';
2525
const { getByText } = render(<AboutDialog open={true} onClose={() => {}} />);
2626
expect(getByText('App Version: 1.3')).toBeTruthy();
2727
});

src/components/AboutDialog/AboutDialog.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import DialogContentText from '@material-ui/core/DialogContentText';
77
import DialogTitle from '@material-ui/core/DialogTitle';
88
import Divider from '@material-ui/core/Divider';
99

10-
import { version as appVersion } from '../../../package.json';
1110
import Video from 'twilio-video';
1211
import { useAppState } from '../../state';
1312

@@ -25,7 +24,7 @@ function AboutDialog({ open, onClose }: PropsWithChildren<AboutDialogProps>) {
2524
<DialogContent>
2625
<DialogContentText>Browser supported: {String(Video.isSupported)}</DialogContentText>
2726
<DialogContentText>SDK Version: {Video.version}</DialogContentText>
28-
<DialogContentText>App Version: {appVersion}</DialogContentText>
27+
<DialogContentText>App Version: {process.env.REACT_APP_VERSION}</DialogContentText>
2928
<DialogContentText>Deployed Tag: {process.env.REACT_APP_GIT_TAG || 'N/A'}</DialogContentText>
3029
<DialogContentText>Deployed Commit Hash: {process.env.REACT_APP_GIT_COMMIT || 'N/A'}</DialogContentText>
3130
{roomType && <DialogContentText>Room Type: {roomType}</DialogContentText>}

src/components/ChatProvider/index.test.tsx

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
import React from 'react';
22
import { act, renderHook } from '@testing-library/react-hooks';
33
import { ChatProvider } from './index';
4-
import { Client } from '@twilio/conversations';
5-
import { mockConversation, mockClient } from '../../__mocks__/@twilio/conversations';
64
import useChatContext from '../../hooks/useChatContext/useChatContext';
75
import useVideoContext from '../../hooks/useVideoContext/useVideoContext';
6+
import { setImmediate } from 'timers';
7+
import EventEmitter from 'events';
88

9-
jest.mock('@twilio/conversations');
9+
const mockConversation: any = new EventEmitter();
10+
mockConversation.getMessages = jest.fn(() => Promise.resolve({ items: ['mockMessage'] }));
11+
12+
const mockConversationsClient: any = new EventEmitter();
13+
mockConversationsClient.getConversationByUniqueName = jest.fn(() => Promise.resolve(mockConversation));
14+
15+
jest.mock('@twilio/conversations', () => {
16+
return { Client: jest.fn(() => mockConversationsClient) };
17+
});
1018
jest.mock('../../hooks/useVideoContext/useVideoContext');
19+
1120
const mockUseVideoContext = useVideoContext as jest.Mock<any>;
1221
const mockOnError = jest.fn();
1322

14-
const mockClientCreate = Client.create as jest.Mock<any>;
15-
1623
const mockRoom = { sid: 'mockRoomSid' };
17-
1824
const wrapper: React.FC = ({ children }) => <ChatProvider>{children}</ChatProvider>;
1925

2026
describe('the ChatProvider component', () => {
@@ -25,12 +31,13 @@ describe('the ChatProvider component', () => {
2531

2632
it('should return a Conversation after connect has been called and after a room exists', async () => {
2733
// Setup mock as if user is not connected to a room
28-
mockUseVideoContext.mockImplementation(() => ({}));
34+
mockUseVideoContext.mockImplementation(() => ({ onError: mockOnError }));
2935
const { result, rerender, waitForNextUpdate } = renderHook(useChatContext, { wrapper });
3036

31-
result.current.connect('mockToken');
32-
await waitForNextUpdate();
33-
expect(mockClientCreate).toHaveBeenCalledWith('mockToken');
37+
await act(() => {
38+
result.current.connect('mockToken');
39+
mockConversationsClient.emit('stateChanged', 'initialized');
40+
});
3441

3542
// conversation should be null as there is no room
3643
expect(result.current.conversation).toBe(null);
@@ -41,21 +48,27 @@ describe('the ChatProvider component', () => {
4148
rerender();
4249
await waitForNextUpdate();
4350

44-
expect(mockClient.getConversationByUniqueName).toHaveBeenCalledWith('mockRoomSid');
51+
expect(mockConversationsClient.getConversationByUniqueName).toHaveBeenCalledWith('mockRoomSid');
4552
expect(result.current.conversation).toBe(mockConversation);
4653
});
4754

4855
it('should load all messages after obtaining a conversation', async () => {
4956
const { result, waitForNextUpdate } = renderHook(useChatContext, { wrapper });
50-
result.current.connect('mockToken');
57+
act(() => {
58+
result.current.connect('mockToken');
59+
mockConversationsClient.emit('stateChanged', 'initialized');
60+
});
5161
await waitForNextUpdate();
5262

5363
expect(result.current.messages).toEqual(['mockMessage']);
5464
});
5565

5666
it('should add new messages to the "messages" array', async () => {
5767
const { result, waitForNextUpdate } = renderHook(useChatContext, { wrapper });
58-
result.current.connect('mockToken');
68+
act(() => {
69+
result.current.connect('mockToken');
70+
mockConversationsClient.emit('stateChanged', 'initialized');
71+
});
5972
await waitForNextUpdate();
6073

6174
act(() => {
@@ -70,7 +83,10 @@ describe('the ChatProvider component', () => {
7083

7184
expect(result.current.hasUnreadMessages).toBe(false);
7285

73-
result.current.connect('mockToken');
86+
act(() => {
87+
result.current.connect('mockToken');
88+
mockConversationsClient.emit('stateChanged', 'initialized');
89+
});
7490
await waitForNextUpdate();
7591

7692
expect(result.current.hasUnreadMessages).toBe(true);
@@ -84,7 +100,10 @@ describe('the ChatProvider component', () => {
84100
result.current.setIsChatWindowOpen(true);
85101
});
86102

87-
result.current.connect('mockToken');
103+
act(() => {
104+
result.current.connect('mockToken');
105+
mockConversationsClient.emit('stateChanged', 'initialized');
106+
});
88107
await waitForNextUpdate();
89108

90109
expect(result.current.hasUnreadMessages).toBe(false);
@@ -94,7 +113,10 @@ describe('the ChatProvider component', () => {
94113
// Setup mock so that no messages are loaded after a conversation is obtained.
95114
mockConversation.getMessages.mockImplementationOnce(() => Promise.resolve({ items: [] }));
96115
const { result, waitForNextUpdate } = renderHook(useChatContext, { wrapper });
97-
result.current.connect('mockToken');
116+
act(() => {
117+
result.current.connect('mockToken');
118+
mockConversationsClient.emit('stateChanged', 'initialized');
119+
});
98120
await waitForNextUpdate();
99121

100122
expect(result.current.hasUnreadMessages).toBe(false);
@@ -110,7 +132,10 @@ describe('the ChatProvider component', () => {
110132
// Setup mock so that no messages are loaded after a conversation is obtained.
111133
mockConversation.getMessages.mockImplementationOnce(() => Promise.resolve({ items: [] }));
112134
const { result, waitForNextUpdate } = renderHook(useChatContext, { wrapper });
113-
result.current.connect('mockToken');
135+
act(() => {
136+
result.current.connect('mockToken');
137+
mockConversationsClient.emit('stateChanged', 'initialized');
138+
});
114139
await waitForNextUpdate();
115140

116141
expect(result.current.hasUnreadMessages).toBe(false);
@@ -126,39 +151,45 @@ describe('the ChatProvider component', () => {
126151

127152
it('should set hasUnreadMessages to false when the chat window is opened', async () => {
128153
const { result, waitForNextUpdate } = renderHook(useChatContext, { wrapper });
129-
result.current.connect('mockToken');
154+
act(() => {
155+
result.current.connect('mockToken');
156+
mockConversationsClient.emit('stateChanged', 'initialized');
157+
});
130158
await waitForNextUpdate();
131159

132160
expect(result.current.hasUnreadMessages).toBe(true);
133161

134162
act(() => {
135163
result.current.setIsChatWindowOpen(true);
136164
});
137-
138165
expect(result.current.hasUnreadMessages).toBe(false);
139166
});
140167

141-
it('should call onError when there is an error connecting with the conversations client', done => {
142-
mockClientCreate.mockImplementationOnce(() => Promise.reject('mockError'));
168+
it('should call onError when there is an error connecting with the conversations client', () => {
143169
const { result } = renderHook(useChatContext, { wrapper });
170+
144171
result.current.connect('mockToken');
172+
mockConversationsClient.emit('stateChanged', 'failed');
173+
174+
expect(mockOnError).toHaveBeenCalledWith(
175+
new Error("There was a problem connecting to Twilio's conversation service.")
176+
);
177+
});
178+
179+
it('should call onError when there is an error getting the conversation', done => {
180+
mockConversationsClient.getConversationByUniqueName.mockImplementationOnce(() => Promise.reject('mockError'));
181+
const { result } = renderHook(useChatContext, { wrapper });
182+
183+
act(() => {
184+
result.current.connect('mockToken');
185+
mockConversationsClient.emit('stateChanged', 'initialized');
186+
});
145187

146188
setImmediate(() => {
147189
expect(mockOnError).toHaveBeenCalledWith(
148-
new Error("There was a problem connecting to Twilio's conversation service.")
190+
new Error('There was a problem getting the Conversation associated with this room.')
149191
);
150192
done();
151193
});
152194
});
153-
154-
it('should call onError when there is an error obtaining the conversation', async () => {
155-
mockClient.getConversationByUniqueName.mockImplementationOnce(() => Promise.reject('mockError'));
156-
const { result, waitForNextUpdate } = renderHook(useChatContext, { wrapper });
157-
result.current.connect('mockToken');
158-
await waitForNextUpdate();
159-
160-
expect(mockOnError).toHaveBeenCalledWith(
161-
new Error('There was a problem getting the Conversation associated with this room.')
162-
);
163-
});
164195
});

0 commit comments

Comments
 (0)