mirror of
https://github.com/darkwire/darkwire.io.git
synced 2025-07-18 18:54:52 +00:00
Update all dependencies
This commit is contained in:
parent
d0d36d690c
commit
0057292553
@ -4,7 +4,7 @@
|
||||
jobs:
|
||||
test-job:
|
||||
docker:
|
||||
- image: "circleci/node:lts"
|
||||
- image: "cimg/node:lts"
|
||||
|
||||
working_directory: ~/repo
|
||||
|
||||
@ -33,7 +33,7 @@ jobs:
|
||||
command: yarn test
|
||||
environment:
|
||||
TZ: UTC
|
||||
REACT_APP_COMMIT_SHA: some_sha
|
||||
VITE_COMMIT_SHA: some_sha
|
||||
|
||||
- store_artifacts: # For coverage report
|
||||
path: client/coverage
|
||||
|
8
build.sh
8
build.sh
@ -10,10 +10,10 @@ fi
|
||||
echo "building client..."
|
||||
cd client
|
||||
yarn --production=false
|
||||
REACT_APP_COMMIT_SHA=$SOURCE_VERSION \
|
||||
REACT_APP_API_HOST=$api_host \
|
||||
REACT_APP_API_PROTOCOL=$API_PROTOCOL \
|
||||
REACT_APP_API_PORT=$API_PORT \
|
||||
VITE_COMMIT_SHA=$SOURCE_VERSION \
|
||||
VITE_API_HOST=$api_host \
|
||||
VITE_API_PROTOCOL=$API_PROTOCOL \
|
||||
VITE_API_PORT=$API_PORT \
|
||||
yarn build
|
||||
cd ../
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
# Api settings
|
||||
TZ=UTC
|
||||
REACT_APP_API_HOST=localhost
|
||||
REACT_APP_API_PROTOCOL=http
|
||||
REACT_APP_API_PORT=3001
|
||||
REACT_APP_COMMIT_SHA=some_sha
|
||||
VITE_API_HOST=localhost
|
||||
VITE_API_PROTOCOL=http
|
||||
VITE_API_PORT=3001
|
||||
VITE_COMMIT_SHA=some_sha
|
||||
|
||||
# To display darkwire version
|
||||
REACT_APP_COMMIT_SHA=some_sha
|
||||
VITE_COMMIT_SHA=some_sha
|
||||
|
||||
# Set max transferable file size in MB
|
||||
REACT_APP_MAX_FILE_SIZE=4
|
||||
VITE_MAX_FILE_SIZE=4
|
||||
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"extends": ["plugin:prettier/recommended"],
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
"prettier/prettier": "error"
|
||||
}
|
||||
}
|
10
client/.eslintrc.cjs
Normal file
10
client/.eslintrc.cjs
Normal file
@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
};
|
32
client/.gitignore
vendored
32
client/.gitignore
vendored
@ -1,9 +1,25 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
coverage
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
.env*
|
||||
!.env.example
|
||||
build/
|
||||
*sublime*
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist/
|
||||
dist-ssr
|
||||
*.local
|
||||
coverage
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
@ -1 +0,0 @@
|
||||
module.exports = {};
|
17
client/index.html
Normal file
17
client/index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-100">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="robots" content="index,nofollow" />
|
||||
<meta name="googlebot" content="index,nofollow" />
|
||||
<meta name="description" content="darkwire.io is the simplest way to chat with encryption online." />
|
||||
<title>Darkwire.io - instant encrypted web chat</title>
|
||||
</head>
|
||||
<body class="h-100">
|
||||
<div id="root" class="h-100"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
@ -6,3 +6,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
"name": "darkwire-client",
|
||||
"version": "2.0.0-beta.12",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Daniel Seripap"
|
||||
@ -12,44 +13,55 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"autosize": "^4.0.2",
|
||||
"bootstrap": "^4.3.1",
|
||||
"clipboard": "^2.0.4",
|
||||
"feather-icons": "^4.21.0",
|
||||
"jquery": "^3.5.0",
|
||||
"js-cookie": "^2.2.0",
|
||||
"lodash": "^4.17.20",
|
||||
"moment": "^2.24.0",
|
||||
"node-sass": "^4.13.1",
|
||||
"popper.js": "^1.15.0",
|
||||
"randomcolor": "^0.5.4",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-feather": "^1.1.6",
|
||||
"react-linkify": "^0.2.2",
|
||||
"react-modal": "^3.8.1",
|
||||
"react-redux": "^7.0.3",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-scripts": "3.0.0",
|
||||
"bootstrap": "^4.6.2",
|
||||
"classnames": "^2.3.2",
|
||||
"clipboard": "^2.0.11",
|
||||
"jquery": "3",
|
||||
"js-cookie": "^3.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"nanoid": "^4.0.0",
|
||||
"randomcolor": "^0.6.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-feather": "^2.0.10",
|
||||
"react-linkify": "^1.0.0-alpha",
|
||||
"react-modal": "^3.16.1",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router": "^6.4.4",
|
||||
"react-router-dom": "^6.4.4",
|
||||
"react-simple-dropdown": "^3.2.3",
|
||||
"redux": "^4.0.1",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"sanitize-html": "^1.20.1",
|
||||
"shortid": "^2.2.14",
|
||||
"socket.io-client": "^2.2.0",
|
||||
"tinycon": "^0.6.8",
|
||||
"webcrypto-shim": "^0.1.4"
|
||||
"redux": "^4.2.0",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"sanitize-html": "^2.7.3",
|
||||
"socket.io-client": "^4.5.4",
|
||||
"tinycon": "^0.6.8"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jest-environment-jsdom-sixteen",
|
||||
"coverage": "react-scripts test --env=jest-environment-jsdom-sixteen --coverage --watchAll=false",
|
||||
"eject": "react-scripts eject",
|
||||
"lint": "eslint src"
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "TZ=UTC vitest",
|
||||
"lint": "eslint src",
|
||||
"coverage": "TZ=UTC vitest --coverage --watch=false"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.46.0",
|
||||
"@typescript-eslint/parser": "^5.46.0",
|
||||
"@vitejs/plugin-react": "^3.0.0",
|
||||
"@vitest/coverage-istanbul": "^0.25.7",
|
||||
"eslint": "^8.29.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"jest-environment-jsdom-sixteen": "^1.0.3",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"prettier": "^2.0.5",
|
||||
"sass": "^1.56.2",
|
||||
"typescript": "^4.9.4",
|
||||
"vitest": "^0.25.7",
|
||||
"vitest-fetch-mock": "^0.2.1"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@ -62,18 +74,5 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@peculiar/webcrypto": "^1.1.1",
|
||||
"@testing-library/jest-dom": "^5.5.0",
|
||||
"@testing-library/react": "^10.0.4",
|
||||
"enzyme": "^3.9.0",
|
||||
"enzyme-adapter-react-16": "^1.12.1",
|
||||
"enzyme-to-json": "^3.3.5",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"jest-environment-jsdom-sixteen": "^1.0.3",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"prettier": "^2.0.5"
|
||||
}
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-100">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
|
||||
<meta name="robots" content="index,nofollow" />
|
||||
<meta name="googlebot" content="index,nofollow" />
|
||||
<meta name="description" content="darkwire.io is the simplest way to chat with encryption online." />
|
||||
<title>darkwire.io - instant encrypted web chat</title>
|
||||
</head>
|
||||
<body class="h-100">
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root" class="h-100"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,7 @@
|
||||
import * as actions from './app';
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
describe('App actions', () => {
|
||||
it('should create an action to scroll to bottom', () => {
|
||||
expect(actions.setScrolledToBottom('test')).toEqual({
|
||||
@ -22,7 +24,7 @@ describe('App actions', () => {
|
||||
});
|
||||
|
||||
it('should create an action to clear activities', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
|
||||
actions.clearActivities()(mockDispatch);
|
||||
|
||||
@ -31,7 +33,7 @@ describe('App actions', () => {
|
||||
});
|
||||
});
|
||||
it('should create all actions', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
|
||||
const actionsResults = [
|
||||
[actions.toggleWindowFocus('test'), 'TOGGLE_WINDOW_FOCUS'],
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { getSocket } from 'utils/socket';
|
||||
import { prepare as prepareMessage, process as processMessage } from 'utils/message';
|
||||
import { getSocket } from '@/utils/socket';
|
||||
import { prepare as prepareMessage, process as processMessage } from '@/utils/message';
|
||||
|
||||
export const sendEncryptedMessage = payload => async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
@ -1,21 +1,23 @@
|
||||
import * as actions from './encrypted_messages';
|
||||
import { getSocket } from 'utils/socket';
|
||||
import { prepare as prepareMessage, process as processMessage } from 'utils/message';
|
||||
import { getSocket } from '@/utils/socket';
|
||||
import { prepare as prepareMessage, process as processMessage } from '@/utils/message';
|
||||
|
||||
jest.mock('utils/message', () => {
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
vi.mock('@/utils/message', () => {
|
||||
return {
|
||||
prepare: jest
|
||||
prepare: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ original: { type: 'messageType', payload: 'test' }, toSend: 'encryptedpayload' }),
|
||||
process: jest.fn().mockResolvedValue({ type: 'messageType', payload: 'test' }),
|
||||
process: vi.fn().mockResolvedValue({ type: 'messageType', payload: 'test' }),
|
||||
};
|
||||
});
|
||||
|
||||
const mockEmit = jest.fn();
|
||||
const mockEmit = vi.fn();
|
||||
|
||||
jest.mock('utils/socket', () => {
|
||||
vi.mock('@/utils/socket', () => {
|
||||
return {
|
||||
getSocket: jest.fn().mockImplementation(() => ({
|
||||
getSocket: vi.fn().mockImplementation(() => ({
|
||||
emit: mockEmit,
|
||||
})),
|
||||
};
|
||||
@ -23,9 +25,9 @@ jest.mock('utils/socket', () => {
|
||||
|
||||
describe('Encrypted messages actions', () => {
|
||||
it('should create an action to send message', async () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
|
||||
await actions.sendEncryptedMessage({ payload: 'payload' })(mockDispatch, jest.fn().mockReturnValue({ state: {} }));
|
||||
await actions.sendEncryptedMessage({ payload: 'payload' })(mockDispatch, vi.fn().mockReturnValue({ state: {} }));
|
||||
|
||||
expect(prepareMessage).toHaveBeenLastCalledWith({ payload: 'payload' }, { state: {} });
|
||||
expect(mockDispatch).toHaveBeenLastCalledWith({ payload: 'test', type: 'SEND_ENCRYPTED_MESSAGE_messageType' });
|
||||
@ -33,11 +35,11 @@ describe('Encrypted messages actions', () => {
|
||||
});
|
||||
|
||||
it('should create an action to receive message', async () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
|
||||
await actions.receiveEncryptedMessage({ payload: 'encrypted' })(
|
||||
mockDispatch,
|
||||
jest.fn().mockReturnValue({ state: {} }),
|
||||
vi.fn().mockReturnValue({ state: {} }),
|
||||
);
|
||||
|
||||
expect(processMessage).toHaveBeenLastCalledWith({ payload: 'encrypted' }, { state: {} });
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getSocket } from 'utils/socket';
|
||||
import { getSocket } from '@/utils/socket';
|
||||
|
||||
const receiveUserEnter = (payload, dispatch) => {
|
||||
dispatch({ type: 'USER_ENTER', payload });
|
||||
@ -70,7 +70,7 @@ const sendToggleLockRoom = (dispatch, getState) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const sendUnencryptedMessage = (type, payload) => async (dispatch, getState) => {
|
||||
export const sendUnencryptedMessage = type => async (dispatch, getState) => {
|
||||
switch (type) {
|
||||
case 'TOGGLE_LOCK_ROOM':
|
||||
return sendToggleLockRoom(dispatch, getState);
|
||||
|
@ -1,33 +1,34 @@
|
||||
import * as actions from './unencrypted_messages';
|
||||
import { getSocket } from 'utils/socket';
|
||||
|
||||
const mockEmit = jest.fn((_type, _null, callback) => {
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
const mockEmit = vi.fn((_type, _null, callback) => {
|
||||
callback({ isLocked: true });
|
||||
});
|
||||
|
||||
jest.mock('utils/socket', () => {
|
||||
vi.mock('@/utils/socket', () => {
|
||||
return {
|
||||
getSocket: jest.fn().mockImplementation(() => ({
|
||||
getSocket: vi.fn().mockImplementation(() => ({
|
||||
emit: mockEmit,
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Reveice unencrypted message actions', () => {
|
||||
describe('Receive unencrypted message actions', () => {
|
||||
it('should create no action', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
actions.receiveUnencryptedMessage('FAKE')(mockDispatch, jest.fn().mockReturnValue({}));
|
||||
const mockDispatch = vi.fn();
|
||||
actions.receiveUnencryptedMessage('FAKE')(mockDispatch, vi.fn().mockReturnValue({}));
|
||||
expect(mockDispatch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create user enter action', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
actions.receiveUnencryptedMessage('USER_ENTER', 'test')(mockDispatch, jest.fn().mockReturnValue({ state: {} }));
|
||||
const mockDispatch = vi.fn();
|
||||
actions.receiveUnencryptedMessage('USER_ENTER', 'test')(mockDispatch, vi.fn().mockReturnValue({ state: {} }));
|
||||
expect(mockDispatch).toHaveBeenLastCalledWith({ type: 'USER_ENTER', payload: 'test' });
|
||||
});
|
||||
|
||||
it('should create user exit action', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
const state = {
|
||||
room: {
|
||||
members: [
|
||||
@ -37,7 +38,7 @@ describe('Reveice unencrypted message actions', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const mockGetState = jest.fn().mockReturnValue(state);
|
||||
const mockGetState = vi.fn().mockReturnValue(state);
|
||||
const payload1 = [
|
||||
{ publicKey: { n: 'alankey' } },
|
||||
{ publicKey: { n: 'dankey' } },
|
||||
@ -62,7 +63,7 @@ describe('Reveice unencrypted message actions', () => {
|
||||
});
|
||||
|
||||
it('should create receive toggle lock room action', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
const state = {
|
||||
room: {
|
||||
members: [
|
||||
@ -71,7 +72,7 @@ describe('Reveice unencrypted message actions', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const mockGetState = jest.fn().mockReturnValue(state);
|
||||
const mockGetState = vi.fn().mockReturnValue(state);
|
||||
const payload = { publicKey: { n: 'alankey' } };
|
||||
|
||||
actions.receiveUnencryptedMessage('TOGGLE_LOCK_ROOM', payload)(mockDispatch, mockGetState);
|
||||
@ -82,14 +83,14 @@ describe('Reveice unencrypted message actions', () => {
|
||||
});
|
||||
|
||||
it('should create receive toggle lock room action', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
const state = {
|
||||
user: {
|
||||
username: 'alan',
|
||||
id: 'idalan',
|
||||
},
|
||||
};
|
||||
const mockGetState = jest.fn().mockReturnValue(state);
|
||||
const mockGetState = vi.fn().mockReturnValue(state);
|
||||
|
||||
actions.sendUnencryptedMessage('TOGGLE_LOCK_ROOM')(mockDispatch, mockGetState);
|
||||
expect(mockDispatch).toHaveBeenLastCalledWith({
|
||||
@ -101,20 +102,20 @@ describe('Reveice unencrypted message actions', () => {
|
||||
|
||||
describe('Send unencrypted message actions', () => {
|
||||
it('should create no action', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
actions.sendUnencryptedMessage('FAKE')(mockDispatch, jest.fn().mockReturnValue({}));
|
||||
const mockDispatch = vi.fn();
|
||||
actions.sendUnencryptedMessage('FAKE')(mockDispatch, vi.fn().mockReturnValue({}));
|
||||
expect(mockDispatch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create toggle lock room action', () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const mockDispatch = vi.fn();
|
||||
const state = {
|
||||
user: {
|
||||
username: 'alan',
|
||||
id: 'idalan',
|
||||
},
|
||||
};
|
||||
const mockGetState = jest.fn().mockReturnValue(state);
|
||||
const mockGetState = vi.fn().mockReturnValue(state);
|
||||
|
||||
actions.sendUnencryptedMessage('TOGGLE_LOCK_ROOM')(mockDispatch, mockGetState);
|
||||
expect(mockDispatch).toHaveBeenLastCalledWith({
|
||||
|
@ -3,21 +3,21 @@ let host;
|
||||
let protocol;
|
||||
let port;
|
||||
|
||||
switch (process.env.NODE_ENV) {
|
||||
switch (import.meta.env.NODE_ENV) {
|
||||
case 'staging':
|
||||
host = process.env.REACT_APP_API_HOST;
|
||||
protocol = process.env.REACT_APP_API_PROTOCOL || 'https';
|
||||
port = process.env.REACT_APP_API_PORT || 443;
|
||||
host = import.meta.env.VITE_API_HOST;
|
||||
protocol = import.meta.env.VITE_API_PROTOCOL || 'https';
|
||||
port = import.meta.env.VITE_API_PORT || 443;
|
||||
break;
|
||||
case 'production':
|
||||
host = process.env.REACT_APP_API_HOST;
|
||||
protocol = process.env.REACT_APP_API_PROTOCOL || 'https';
|
||||
port = process.env.REACT_APP_API_PORT || 443;
|
||||
host = import.meta.env.VITE_API_HOST;
|
||||
protocol = import.meta.env.VITE_API_PROTOCOL || 'https';
|
||||
port = import.meta.env.VITE_API_PORT || 443;
|
||||
break;
|
||||
default:
|
||||
host = process.env.REACT_APP_API_HOST || 'localhost';
|
||||
protocol = process.env.REACT_APP_API_PROTOCOL || 'http';
|
||||
port = process.env.REACT_APP_API_PORT || 3001;
|
||||
host = import.meta.env.VITE_API_HOST || 'localhost';
|
||||
protocol = import.meta.env.VITE_API_PROTOCOL || 'http';
|
||||
port = import.meta.env.VITE_API_PORT || 3001;
|
||||
}
|
||||
|
||||
export default {
|
||||
|
@ -1,15 +1,17 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import About from '.';
|
||||
import fetchMock from 'jest-fetch-mock';
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
|
||||
// Mock Api generator
|
||||
|
||||
jest.mock('../../api/generator', () => {
|
||||
return path => {
|
||||
vi.mock('@/api/generator', () => {
|
||||
return {
|
||||
default: path => {
|
||||
return `http://fakedomain/${path}`;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@ -43,7 +45,7 @@ describe('About component', () => {
|
||||
|
||||
fireEvent.change(getByPlaceholderText('Room ID'), { target: { value: 'newRoomName' } });
|
||||
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
|
||||
fireEvent.click(getByText('Submit'));
|
||||
|
@ -1,12 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`About component should display 1`] = `
|
||||
exports[`About component > should display 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="base"
|
||||
class="_base_4f26aa"
|
||||
>
|
||||
<div
|
||||
class="links"
|
||||
class="_links_4f26aa"
|
||||
>
|
||||
<div>
|
||||
<a
|
@ -1,7 +1,9 @@
|
||||
/* eslint-disable */
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import apiUrlGenerator from '../../api/generator';
|
||||
|
||||
import { COMMIT_SHA } from '@/config/env';
|
||||
import apiUrlGenerator from '@/api/generator';
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
class About extends Component {
|
||||
@ -63,11 +65,8 @@ class About extends Component {
|
||||
<h4>Version</h4>
|
||||
<p>
|
||||
Commit SHA:{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href={`https://github.com/darkwire/darkwire.io/commit/${process.env.REACT_APP_COMMIT_SHA}`}
|
||||
>
|
||||
{process.env.REACT_APP_COMMIT_SHA}
|
||||
<a target="_blank" href={`https://github.com/darkwire/darkwire.io/commit/${COMMIT_SHA}`}>
|
||||
{COMMIT_SHA}
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
@ -1,12 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
import FileTransfer from 'components/FileTransfer';
|
||||
import { CornerDownRight } from 'react-feather';
|
||||
import { getSelectedText, hasTouchSupport } from '../../utils/dom';
|
||||
|
||||
// Disable for now
|
||||
// import autosize from 'autosize'
|
||||
import { getSelectedText, hasTouchSupport } from '@/utils/dom';
|
||||
|
||||
import FileTransfer from '@/components/FileTransfer';
|
||||
|
||||
export class Chat extends Component {
|
||||
constructor(props) {
|
||||
@ -21,14 +20,14 @@ export class Chat extends Component {
|
||||
{
|
||||
command: 'nick',
|
||||
description: 'Changes nickname.',
|
||||
paramaters: ['{username}'],
|
||||
parameters: ['{username}'],
|
||||
usage: '/nick {username}',
|
||||
scope: 'global',
|
||||
action: params => {
|
||||
// eslint-disable-line
|
||||
let newUsername = params.join(' ') || ''; // eslint-disable-line
|
||||
|
||||
// Remove things that arent digits or chars
|
||||
// Remove things that aren't digits or chars
|
||||
newUsername = newUsername.replace(/[^A-Za-z0-9]/g, '-');
|
||||
|
||||
const errors = [];
|
@ -1,19 +1,20 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
|
||||
import { Chat } from './Chat';
|
||||
import { Chat } from '@/components/Chat/Chat';
|
||||
|
||||
import * as dom from 'utils/dom';
|
||||
import * as dom from '@/utils/dom';
|
||||
|
||||
const translations = {
|
||||
typePlaceholder: 'inputplaceholder',
|
||||
};
|
||||
|
||||
// Fake date
|
||||
jest.spyOn(global.Date, 'now').mockImplementation(() => new Date('2020-03-14T11:01:58.135Z').valueOf());
|
||||
vi.spyOn(global.Date, 'now').mockImplementation(() => new Date('2020-03-14T11:01:58.135Z').valueOf());
|
||||
|
||||
// To change touch support
|
||||
jest.mock('../../utils/dom');
|
||||
vi.mock('@/utils/dom');
|
||||
|
||||
describe('Chat component', () => {
|
||||
afterEach(() => {
|
||||
@ -39,7 +40,7 @@ describe('Chat component', () => {
|
||||
});
|
||||
|
||||
it('can send message', () => {
|
||||
const sendEncryptedMessage = jest.fn();
|
||||
const sendEncryptedMessage = vi.fn();
|
||||
|
||||
render(
|
||||
<Chat
|
||||
@ -78,7 +79,7 @@ describe('Chat component', () => {
|
||||
});
|
||||
|
||||
it("shouldn't send message with Shift+enter", () => {
|
||||
const sendEncryptedMessage = jest.fn();
|
||||
const sendEncryptedMessage = vi.fn();
|
||||
|
||||
render(
|
||||
<Chat
|
||||
@ -115,9 +116,9 @@ describe('Chat component', () => {
|
||||
});
|
||||
|
||||
it('should send commands', () => {
|
||||
const sendEncryptedMessage = jest.fn();
|
||||
const showNotice = jest.fn();
|
||||
const clearActivities = jest.fn();
|
||||
const sendEncryptedMessage = vi.fn();
|
||||
const showNotice = vi.fn();
|
||||
const clearActivities = vi.fn();
|
||||
|
||||
render(
|
||||
<Chat
|
||||
@ -210,14 +211,14 @@ describe('Chat component', () => {
|
||||
// Enable touch support
|
||||
dom.hasTouchSupport = true;
|
||||
|
||||
jest.mock('../../utils/dom', () => {
|
||||
vi.mock('@/utils/dom', () => {
|
||||
return {
|
||||
getSelectedText: jest.fn(),
|
||||
getSelectedText: vi.fn(),
|
||||
hasTouchSupport: true,
|
||||
};
|
||||
});
|
||||
|
||||
const sendEncryptedMessage = jest.fn();
|
||||
const sendEncryptedMessage = vi.fn();
|
||||
|
||||
const { getByTitle } = render(
|
||||
<Chat
|
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Chat component should display 1`] = `
|
||||
exports[`Chat component > should display 1`] = `
|
||||
<DocumentFragment>
|
||||
<form
|
||||
class="chat-preflight-container"
|
||||
@ -13,7 +13,7 @@ exports[`Chat component should display 1`] = `
|
||||
class="input-controls"
|
||||
>
|
||||
<div
|
||||
class="styles icon file-transfer btn btn-link"
|
||||
class="_styles_374fdd icon file-transfer btn btn-link"
|
||||
>
|
||||
<input
|
||||
id="fileInput"
|
@ -1,6 +1,6 @@
|
||||
import Chat from './Chat';
|
||||
import { connect } from 'react-redux';
|
||||
import { clearActivities, showNotice, sendEncryptedMessage } from '../../actions';
|
||||
import { clearActivities, showNotice, sendEncryptedMessage } from '@/actions';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
username: state.user.username,
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import Connecting from '.';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Connecting component is displaying', async () => {
|
||||
const { asFragment } = render(<Connecting />);
|
@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Connecting component is displaying 1`] = `
|
||||
<DocumentFragment>
|
@ -1,9 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import uuid from 'uuid';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { File } from 'react-feather';
|
||||
import { sanitize } from 'utils';
|
||||
import { styles } from './styles.module.scss';
|
||||
|
||||
import { MAX_FILE_SIZE } from '@/config/env';
|
||||
import { sanitize } from '@/utils';
|
||||
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
const VALID_FILE_TYPES = [
|
||||
'png',
|
||||
@ -24,8 +27,6 @@ const VALID_FILE_TYPES = [
|
||||
'css',
|
||||
];
|
||||
|
||||
const MAX_FILE_SIZE = process.env.REACT_APP_MAX_FILE_SIZE || 4;
|
||||
|
||||
/**
|
||||
* Encode the given file to binary string
|
||||
* @param {File} file
|
||||
@ -86,7 +87,7 @@ export const FileTransfer = ({ sendEncryptedMessage }) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fileId = uuid.v4();
|
||||
const fileId = nanoid();
|
||||
const fileData = {
|
||||
id: fileId,
|
||||
file,
|
||||
@ -129,7 +130,7 @@ export const FileTransfer = ({ sendEncryptedMessage }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${styles} icon file-transfer btn btn-link`}>
|
||||
<div className={`${classes.styles} icon file-transfer btn btn-link`}>
|
||||
<input placeholder="Choose a file..." type="file" name="fileUploader" id="fileInput" ref={fileInput} />
|
||||
<label htmlFor="fileInput">
|
||||
<File color="#fff" />
|
@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent, createEvent } from '@testing-library/react';
|
||||
import FileTransfer from '.';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
|
||||
// Fake date
|
||||
jest.spyOn(global.Date, 'now').mockImplementation(() => new Date('2020-03-14T11:01:58.135Z').valueOf());
|
||||
vi.spyOn(global.Date, 'now').mockImplementation(() => new Date('2020-03-14T11:01:58.135Z').valueOf());
|
||||
|
||||
describe('FileTransfer tests', () => {
|
||||
const { File } = window;
|
||||
@ -68,7 +69,7 @@ describe('FileTransfer tests', () => {
|
||||
});
|
||||
|
||||
it('Try to send unsupported file', async () => {
|
||||
window.alert = jest.fn();
|
||||
window.alert = vi.fn();
|
||||
|
||||
render(<FileTransfer sendEncryptedMessage={() => {}} />);
|
||||
|
||||
@ -86,7 +87,7 @@ describe('FileTransfer tests', () => {
|
||||
});
|
||||
|
||||
it('Try to send too big file', async () => {
|
||||
window.alert = jest.fn();
|
||||
window.alert = vi.fn();
|
||||
|
||||
render(<FileTransfer sendEncryptedMessage={() => {}} />);
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`FileTransfer tests FileTransfer component is displaying 1`] = `
|
||||
exports[`FileTransfer tests > FileTransfer component is displaying 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="styles icon file-transfer btn btn-link"
|
||||
class="_styles_374fdd icon file-transfer btn btn-link"
|
||||
>
|
||||
<input
|
||||
id="fileInput"
|
@ -1,12 +1,13 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Message from 'components/Message';
|
||||
import Username from 'components/Username';
|
||||
import Notice from 'components/Notice';
|
||||
import Zoom from 'utils/ImageZoom';
|
||||
import { getObjectUrl } from 'utils/file';
|
||||
|
||||
import T from 'components/T';
|
||||
import Zoom from '@/utils/ImageZoom';
|
||||
import { getObjectUrl } from '@/utils/file';
|
||||
|
||||
import Message from '@/components/Message';
|
||||
import Username from '@/components/Username';
|
||||
import Notice from '@/components/Notice';
|
||||
import T from '@/components/T';
|
||||
|
||||
const FileDisplay = ({ activity: { fileType, encodedFile, fileName, username }, scrollToBottom }) => {
|
||||
const zoomableImage = React.useRef(null);
|
@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import Activity from './Activity';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from 'store';
|
||||
|
||||
import Activity from './Activity';
|
||||
import configureStore from '@/store';
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
//jest.mock('components/T'); // Need store
|
||||
|
||||
describe('Activity component', () => {
|
||||
it('should display', () => {
|
||||
const activity = {
|
||||
@ -15,7 +15,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -31,7 +31,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -45,7 +45,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -59,7 +59,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -74,7 +74,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment, rerender } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -84,7 +84,7 @@ describe('Activity component', () => {
|
||||
|
||||
rerender(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -98,7 +98,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -113,7 +113,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -128,7 +128,7 @@ describe('Activity component', () => {
|
||||
};
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -143,11 +143,11 @@ describe('Activity component', () => {
|
||||
encodedFile: 'dGV4dGZpbGU=',
|
||||
fileType: 'text/plain',
|
||||
};
|
||||
global.URL.createObjectURL = jest.fn(data => `url:${data}`);
|
||||
global.URL.createObjectURL = vi.fn(data => `url:${data}`);
|
||||
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -155,9 +155,9 @@ describe('Activity component', () => {
|
||||
});
|
||||
|
||||
it('should display RECEIVE_FILE with image', () => {
|
||||
global.URL.createObjectURL = jest.fn(data => `url:${data}`);
|
||||
global.URL.createObjectURL = vi.fn(data => `url:${data}`);
|
||||
|
||||
const mockScrollToBottom = jest.fn();
|
||||
const mockScrollToBottom = vi.fn();
|
||||
|
||||
const activity = {
|
||||
type: 'RECEIVE_FILE',
|
||||
@ -181,7 +181,7 @@ describe('Activity component', () => {
|
||||
});
|
||||
|
||||
it('should display SEND_FILE', () => {
|
||||
global.URL.createObjectURL = jest.fn(data => `url:${data}`);
|
||||
global.URL.createObjectURL = vi.fn(data => `url:${data}`);
|
||||
const activity = {
|
||||
type: 'SEND_FILE',
|
||||
username: 'alice',
|
||||
@ -192,7 +192,7 @@ describe('Activity component', () => {
|
||||
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<Activity activity={activity} scrollToBottom={jest.fn()} />
|
||||
<Activity activity={activity} scrollToBottom={vi.fn()} />
|
||||
</Provider>,
|
||||
);
|
||||
|
@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ChatInput from 'components/Chat';
|
||||
import Activity from './Activity';
|
||||
import T from 'components/T';
|
||||
import { defer } from 'lodash';
|
||||
|
||||
import ChatInput from '@/components/Chat';
|
||||
import T from '@/components/T';
|
||||
|
||||
import Activity from './Activity';
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
const ActivityList = ({ activities, openModal }) => {
|
@ -1,18 +1,21 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import ActivityList from './ActivityList';
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from 'store';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
import configureStore from '@/store';
|
||||
|
||||
import ActivityList from './ActivityList';
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
|
||||
describe('ActivityList component', () => {
|
||||
it('should display', () => {
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<ActivityList openModal={jest.fn()} activities={[]} />
|
||||
<ActivityList openModal={vi.fn()} activities={[]} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -39,7 +42,7 @@ describe('ActivityList component', () => {
|
||||
];
|
||||
const { asFragment } = render(
|
||||
<Provider store={store}>
|
||||
<ActivityList openModal={jest.fn()} activities={activities} />
|
||||
<ActivityList openModal={vi.fn()} activities={activities} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
@ -47,7 +50,7 @@ describe('ActivityList component', () => {
|
||||
});
|
||||
|
||||
it('should show About modal', async () => {
|
||||
const mockOpenModal = jest.fn();
|
||||
const mockOpenModal = vi.fn();
|
||||
|
||||
const { getByText } = render(
|
||||
<Provider store={store}>
|
||||
@ -56,43 +59,40 @@ describe('ActivityList component', () => {
|
||||
);
|
||||
|
||||
fireEvent.click(getByText('By using Darkwire, you are agreeing to our Acceptable Use Policy and Terms of Service'));
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
|
||||
expect(mockOpenModal.mock.calls[0][0]).toBe('About');
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
});
|
||||
|
||||
it('should focus chat', () => {
|
||||
const { getByTestId } = render(
|
||||
<Provider store={store}>
|
||||
<ActivityList openModal={jest.fn()} activities={[]} />
|
||||
<ActivityList openModal={vi.fn()} activities={[]} />
|
||||
</Provider>,
|
||||
);
|
||||
fireEvent.click(getByTestId('main-div'));
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
});
|
||||
|
||||
it('should scroll to bottom on new message if not scrolled', () => {
|
||||
jest.spyOn(Element.prototype, 'clientHeight', 'get').mockReturnValueOnce(400).mockReturnValueOnce(200);
|
||||
vi.spyOn(Element.prototype, 'clientHeight', 'get').mockReturnValueOnce(400).mockReturnValueOnce(200);
|
||||
|
||||
Element.prototype.getBoundingClientRect = jest
|
||||
.fn()
|
||||
.mockReturnValueOnce({ top: 0 })
|
||||
.mockReturnValueOnce({ top: 261 });
|
||||
Element.prototype.getBoundingClientRect = vi.fn().mockReturnValueOnce({ top: 0 }).mockReturnValueOnce({ top: 261 });
|
||||
|
||||
jest.spyOn(Element.prototype, 'scrollHeight', 'get').mockReturnValue(42);
|
||||
const mockScrollTop = jest.spyOn(Element.prototype, 'scrollTop', 'set');
|
||||
vi.spyOn(Element.prototype, 'scrollHeight', 'get').mockReturnValue(42);
|
||||
const mockScrollTop = vi.spyOn(Element.prototype, 'scrollTop', 'set');
|
||||
|
||||
const { rerender, getByTestId } = render(
|
||||
<Provider store={store}>
|
||||
<ActivityList openModal={jest.fn()} activities={[]} />
|
||||
<ActivityList openModal={vi.fn()} activities={[]} />
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
rerender(
|
||||
<Provider store={store}>
|
||||
<ActivityList
|
||||
openModal={jest.fn()}
|
||||
openModal={vi.fn()}
|
||||
activities={[
|
||||
{
|
||||
type: 'TEXT_MESSAGE',
|
||||
@ -105,7 +105,7 @@ describe('ActivityList component', () => {
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
|
||||
expect(mockScrollTop).toHaveBeenCalledTimes(2);
|
||||
expect(mockScrollTop).toHaveBeenLastCalledWith(42);
|
||||
@ -115,7 +115,7 @@ describe('ActivityList component', () => {
|
||||
rerender(
|
||||
<Provider store={store}>
|
||||
<ActivityList
|
||||
openModal={jest.fn()}
|
||||
openModal={vi.fn()}
|
||||
activities={[
|
||||
{
|
||||
type: 'TEXT_MESSAGE',
|
@ -1,17 +1,20 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Crypto from 'utils/crypto';
|
||||
import { connect as connectSocket } from 'utils/socket';
|
||||
import Nav from 'components/Nav';
|
||||
import shortId from 'shortid';
|
||||
import Connecting from 'components/Connecting';
|
||||
import Modal from 'react-modal';
|
||||
import About from 'components/About';
|
||||
import Settings from 'components/Settings';
|
||||
import Welcome from 'components/Welcome';
|
||||
import RoomLocked from 'components/RoomLocked';
|
||||
import PropTypes from 'prop-types';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { X, AlertCircle } from 'react-feather';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Crypto from '@/utils/crypto';
|
||||
import { connect as connectSocket } from '@/utils/socket';
|
||||
|
||||
import Nav from '@/components/Nav';
|
||||
import Connecting from '@/components/Connecting';
|
||||
import About from '@/components/About';
|
||||
import Settings from '@/components/Settings';
|
||||
import Welcome from '@/components/Welcome';
|
||||
import RoomLocked from '@/components/RoomLocked';
|
||||
|
||||
import ActivityList from './ActivityList';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
@ -22,11 +25,9 @@ Modal.setAppElement('#root');
|
||||
|
||||
class Home extends Component {
|
||||
async componentWillMount() {
|
||||
const roomId = encodeURI(this.props.match.params.roomId);
|
||||
|
||||
const user = await this.createUser();
|
||||
|
||||
const socket = connectSocket(roomId);
|
||||
const socket = connectSocket(this.props.socketId);
|
||||
|
||||
this.socket = socket;
|
||||
|
||||
@ -150,7 +151,7 @@ class Home extends Component {
|
||||
|
||||
createUser() {
|
||||
return new Promise(async resolve => {
|
||||
const username = shortId.generate();
|
||||
const username = nanoid();
|
||||
|
||||
const encryptDecryptKeys = await crypto.createEncryptDecryptKeys();
|
||||
const exportedEncryptDecryptPrivateKey = await crypto.exportKey(encryptDecryptKeys.privateKey);
|
||||
@ -237,7 +238,7 @@ Home.propTypes = {
|
||||
username: PropTypes.string.isRequired,
|
||||
publicKey: PropTypes.object.isRequired,
|
||||
members: PropTypes.array.isRequired,
|
||||
match: PropTypes.object.isRequired,
|
||||
socketId: PropTypes.object.isRequired,
|
||||
roomId: PropTypes.string.isRequired,
|
||||
roomLocked: PropTypes.bool.isRequired,
|
||||
modalComponent: PropTypes.string,
|
@ -1,27 +1,34 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import Home from './Home';
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from 'store';
|
||||
import { render } from '@testing-library/react';
|
||||
import { test, expect, vi } from 'vitest';
|
||||
|
||||
import Home from './Home';
|
||||
import configureStore from '@/store';
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
jest.mock('react-modal'); // Cant load modal without root app element
|
||||
jest.mock('utils/socket', () => {
|
||||
vi.mock('react-modal'); // Cant load modal without root app element
|
||||
|
||||
vi.mock('@/RoomLink');
|
||||
vi.mock('@/components/Nav');
|
||||
|
||||
vi.mock('@/utils/socket', () => {
|
||||
// Avoid exception
|
||||
return {
|
||||
connect: jest.fn().mockImplementation(() => {
|
||||
connect: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
on: jest.fn(),
|
||||
emit: jest.fn(),
|
||||
on: vi.fn(),
|
||||
emit: vi.fn(),
|
||||
};
|
||||
}),
|
||||
};
|
||||
}); //
|
||||
|
||||
jest.mock('utils/crypto', () => {
|
||||
vi.mock('../../utils/crypto', () => {
|
||||
// Need window.crytpo.subtle
|
||||
return jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
default: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
createEncryptDecryptKeys: () => {
|
||||
return {
|
||||
@ -33,7 +40,8 @@ jest.mock('utils/crypto', () => {
|
||||
return 'exportedkey';
|
||||
},
|
||||
};
|
||||
});
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
test('Home component is displaying', async () => {
|
@ -1,8 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { notify, beep } from 'utils/notifications';
|
||||
import Tinycon from 'tinycon';
|
||||
import { toggleNotificationAllowed, toggleNotificationEnabled } from 'actions';
|
||||
|
||||
import { notify, beep } from '@/utils/notifications';
|
||||
import { toggleNotificationAllowed, toggleNotificationEnabled } from '@/actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
@ -1,8 +1,8 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Activity component should display 1`] = `<DocumentFragment />`;
|
||||
exports[`Activity component > should display 1`] = `<DocumentFragment />`;
|
||||
|
||||
exports[`Activity component should display CHANGE_USERNAME 1`] = `
|
||||
exports[`Activity component > should display CHANGE_USERNAME 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -30,7 +30,7 @@ exports[`Activity component should display CHANGE_USERNAME 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display NOTICE 1`] = `
|
||||
exports[`Activity component > should display NOTICE 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -44,7 +44,7 @@ exports[`Activity component should display NOTICE 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display RECEIVE_FILE 1`] = `
|
||||
exports[`Activity component > should display RECEIVE_FILE 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<span>
|
||||
@ -71,7 +71,7 @@ exports[`Activity component should display RECEIVE_FILE 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display RECEIVE_FILE with image 1`] = `
|
||||
exports[`Activity component > should display RECEIVE_FILE with image 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<span>
|
||||
@ -103,7 +103,7 @@ exports[`Activity component should display RECEIVE_FILE with image 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display SEND_FILE 1`] = `
|
||||
exports[`Activity component > should display SEND_FILE 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -128,7 +128,7 @@ exports[`Activity component should display SEND_FILE 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display TEXT_MESSAGE 1`] = `
|
||||
exports[`Activity component > should display TEXT_MESSAGE 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -148,18 +148,14 @@ exports[`Activity component should display TEXT_MESSAGE 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="chat"
|
||||
>
|
||||
<span
|
||||
class="Linkify"
|
||||
>
|
||||
Hi!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display TOGGLE_LOCK_ROOM 1`] = `
|
||||
exports[`Activity component > should display TOGGLE_LOCK_ROOM 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -181,7 +177,7 @@ exports[`Activity component should display TOGGLE_LOCK_ROOM 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display TOGGLE_LOCK_ROOM 2`] = `
|
||||
exports[`Activity component > should display TOGGLE_LOCK_ROOM 2`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -203,7 +199,7 @@ exports[`Activity component should display TOGGLE_LOCK_ROOM 2`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display USER_ACTION 1`] = `
|
||||
exports[`Activity component > should display USER_ACTION 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -224,7 +220,7 @@ exports[`Activity component should display USER_ACTION 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display USER_ENTER 1`] = `
|
||||
exports[`Activity component > should display USER_ENTER 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
||||
@ -246,7 +242,7 @@ exports[`Activity component should display USER_ENTER 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Activity component should display USER_EXIT 1`] = `
|
||||
exports[`Activity component > should display USER_EXIT 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div
|
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`ActivityList component should display 1`] = `
|
||||
exports[`ActivityList component > should display 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="main-chat"
|
||||
@ -14,7 +14,7 @@ exports[`ActivityList component should display 1`] = `
|
||||
>
|
||||
<li>
|
||||
<p
|
||||
class="tos"
|
||||
class="_tos_0b54d3"
|
||||
>
|
||||
<button
|
||||
class="btn btn-link"
|
||||
@ -40,7 +40,7 @@ exports[`ActivityList component should display 1`] = `
|
||||
class="input-controls"
|
||||
>
|
||||
<div
|
||||
class="styles icon file-transfer btn btn-link"
|
||||
class="_styles_374fdd icon file-transfer btn btn-link"
|
||||
>
|
||||
<input
|
||||
id="fileInput"
|
||||
@ -78,7 +78,7 @@ exports[`ActivityList component should display 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`ActivityList component should display with activities 1`] = `
|
||||
exports[`ActivityList component > should display with activities 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="main-chat"
|
||||
@ -92,7 +92,7 @@ exports[`ActivityList component should display with activities 1`] = `
|
||||
>
|
||||
<li>
|
||||
<p
|
||||
class="tos"
|
||||
class="_tos_0b54d3"
|
||||
>
|
||||
<button
|
||||
class="btn btn-link"
|
||||
@ -122,12 +122,8 @@ exports[`ActivityList component should display with activities 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="chat"
|
||||
>
|
||||
<span
|
||||
class="Linkify"
|
||||
>
|
||||
Hi!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@ -196,7 +192,7 @@ exports[`ActivityList component should display with activities 1`] = `
|
||||
class="input-controls"
|
||||
>
|
||||
<div
|
||||
class="styles icon file-transfer btn btn-link"
|
||||
class="_styles_374fdd icon file-transfer btn btn-link"
|
||||
>
|
||||
<input
|
||||
id="fileInput"
|
@ -1,365 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Home component is displaying 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="styles h-100"
|
||||
>
|
||||
<div
|
||||
class="nav-container"
|
||||
>
|
||||
<div
|
||||
class="alert-banner"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="15"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="15"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
y1="8"
|
||||
y2="12"
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
y1="16"
|
||||
y2="16"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
Disconnected
|
||||
</span>
|
||||
</div>
|
||||
<nav
|
||||
class="navbar navbar-expand-md navbar-dark"
|
||||
>
|
||||
<div
|
||||
class="meta"
|
||||
>
|
||||
<img
|
||||
alt="Darkwire"
|
||||
class="logo"
|
||||
src="logo.png"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-plain btn-link clipboard-trigger room-id ellipsis"
|
||||
data-clipboard-text="http://localhost/testId"
|
||||
data-placement="bottom"
|
||||
data-toggle="tooltip"
|
||||
>
|
||||
/testId
|
||||
</button>
|
||||
<span
|
||||
class="lock-room-container"
|
||||
>
|
||||
<button
|
||||
class="lock-room btn btn-link btn-plain"
|
||||
data-placement="bottom"
|
||||
data-toggle="tooltip"
|
||||
title="You must be the owner to lock or unlock the room"
|
||||
>
|
||||
<svg
|
||||
class="muted"
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
height="11"
|
||||
rx="2"
|
||||
ry="2"
|
||||
width="18"
|
||||
x="3"
|
||||
y="11"
|
||||
/>
|
||||
<path
|
||||
d="M7 11V7a5 5 0 0 1 9.9-1"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
<div
|
||||
class="dropdown members-dropdown"
|
||||
>
|
||||
<a
|
||||
class="dropdown__trigger "
|
||||
>
|
||||
<button
|
||||
class="btn btn-link btn-plain members-action"
|
||||
title="Users"
|
||||
>
|
||||
<svg
|
||||
class="users-icon"
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"
|
||||
/>
|
||||
<circle
|
||||
cx="9"
|
||||
cy="7"
|
||||
r="4"
|
||||
/>
|
||||
<path
|
||||
d="M23 21v-2a4 4 0 0 0-3-3.87"
|
||||
/>
|
||||
<path
|
||||
d="M16 3.13a4 4 0 0 1 0 7.75"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<span>
|
||||
0
|
||||
</span>
|
||||
</a>
|
||||
<div
|
||||
class="dropdown__content "
|
||||
>
|
||||
<ul
|
||||
class="plain"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
class="navbar-toggler"
|
||||
data-target="#navbarSupportedContent"
|
||||
data-toggle="collapse"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="navbar-toggler-icon"
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="collapse navbar-collapse"
|
||||
id="navbarSupportedContent"
|
||||
>
|
||||
<ul
|
||||
class="navbar-nav ml-auto"
|
||||
>
|
||||
<li
|
||||
class="nav-item"
|
||||
>
|
||||
<button
|
||||
class="btn btn-plain nav-link"
|
||||
target="blank"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
y1="8"
|
||||
y2="16"
|
||||
/>
|
||||
<line
|
||||
x1="8"
|
||||
x2="16"
|
||||
y1="12"
|
||||
y2="12"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span />
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class=" nav-item"
|
||||
>
|
||||
<button
|
||||
class="btn btn-plain nav-link"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="3"
|
||||
/>
|
||||
<path
|
||||
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span />
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="nav-item"
|
||||
>
|
||||
<button
|
||||
class="btn btn-plain nav-link"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
y1="16"
|
||||
y2="12"
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
y1="8"
|
||||
y2="8"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span />
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
class="main-chat"
|
||||
>
|
||||
<div
|
||||
class="message-stream h-100"
|
||||
data-testid="main-div"
|
||||
>
|
||||
<ul
|
||||
class="plain"
|
||||
>
|
||||
<li>
|
||||
<p
|
||||
class="tos"
|
||||
>
|
||||
<button
|
||||
class="btn btn-link"
|
||||
>
|
||||
By using Darkwire, you are agreeing to our Acceptable Use Policy and Terms of Service
|
||||
</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="chat-container"
|
||||
>
|
||||
<form
|
||||
class="chat-preflight-container"
|
||||
>
|
||||
<textarea
|
||||
class="chat"
|
||||
placeholder="Type here"
|
||||
rows="1"
|
||||
/>
|
||||
<div
|
||||
class="input-controls"
|
||||
>
|
||||
<div
|
||||
class="styles icon file-transfer btn btn-link"
|
||||
>
|
||||
<input
|
||||
id="fileInput"
|
||||
name="fileUploader"
|
||||
placeholder="Choose a file..."
|
||||
type="file"
|
||||
/>
|
||||
<label
|
||||
for="fileInput"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="#fff"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"
|
||||
/>
|
||||
<polyline
|
||||
points="13 2 13 9 20 9"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
128
client/src/components/Home/__snapshots__/Home.test.jsx.snap
Normal file
128
client/src/components/Home/__snapshots__/Home.test.jsx.snap
Normal file
@ -0,0 +1,128 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Home component is displaying 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_styles_0b54d3 h-100"
|
||||
>
|
||||
<div
|
||||
class="nav-container"
|
||||
>
|
||||
<div
|
||||
class="alert-banner"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="15"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="15"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
y1="8"
|
||||
y2="12"
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12.01"
|
||||
y1="16"
|
||||
y2="16"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
Disconnected
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="main-chat"
|
||||
>
|
||||
<div
|
||||
class="message-stream h-100"
|
||||
data-testid="main-div"
|
||||
>
|
||||
<ul
|
||||
class="plain"
|
||||
>
|
||||
<li>
|
||||
<p
|
||||
class="_tos_0b54d3"
|
||||
>
|
||||
<button
|
||||
class="btn btn-link"
|
||||
>
|
||||
By using Darkwire, you are agreeing to our Acceptable Use Policy and Terms of Service
|
||||
</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="chat-container"
|
||||
>
|
||||
<form
|
||||
class="chat-preflight-container"
|
||||
>
|
||||
<textarea
|
||||
class="chat"
|
||||
placeholder="Type here"
|
||||
rows="1"
|
||||
/>
|
||||
<div
|
||||
class="input-controls"
|
||||
>
|
||||
<div
|
||||
class="_styles_374fdd icon file-transfer btn btn-link"
|
||||
>
|
||||
<input
|
||||
id="fileInput"
|
||||
name="fileUploader"
|
||||
placeholder="Choose a file..."
|
||||
type="file"
|
||||
/>
|
||||
<label
|
||||
for="fileInput"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="#fff"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"
|
||||
/>
|
||||
<polyline
|
||||
points="13 2 13 9 20 9"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -1,9 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Connected Home component should display 1`] = `
|
||||
exports[`Connected Home component > should display 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="styles h-100"
|
||||
class="_styles_0b54d3 h-100"
|
||||
>
|
||||
<div
|
||||
class="nav-container"
|
||||
@ -38,7 +38,7 @@ exports[`Connected Home component should display 1`] = `
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
x2="12.01"
|
||||
y1="16"
|
||||
y2="16"
|
||||
/>
|
||||
@ -58,11 +58,11 @@ exports[`Connected Home component should display 1`] = `
|
||||
<img
|
||||
alt="Darkwire"
|
||||
class="logo"
|
||||
src="logo.png"
|
||||
src="/src/img/logo.png"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-plain btn-link clipboard-trigger room-id ellipsis"
|
||||
data-clipboard-text="http://localhost/"
|
||||
data-clipboard-text="http://localhost:3000/"
|
||||
data-placement="bottom"
|
||||
data-toggle="tooltip"
|
||||
title="Copied"
|
||||
@ -279,7 +279,7 @@ exports[`Connected Home component should display 1`] = `
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
x2="12.01"
|
||||
y1="8"
|
||||
y2="8"
|
||||
/>
|
@ -1,5 +1,6 @@
|
||||
import Home from './Home';
|
||||
import { connect } from 'react-redux';
|
||||
import { useLoaderData } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
receiveEncryptedMessage,
|
||||
createUser,
|
||||
@ -14,7 +15,9 @@ import {
|
||||
sendUnencryptedMessage,
|
||||
sendEncryptedMessage,
|
||||
setLanguage,
|
||||
} from 'actions';
|
||||
} from '@/actions';
|
||||
|
||||
import Home from './Home';
|
||||
import WithNewMessageNotification from './WithNewMessageNotification';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
@ -57,4 +60,11 @@ const mapDispatchToProps = {
|
||||
setLanguage,
|
||||
};
|
||||
|
||||
export default WithNewMessageNotification(connect(mapStateToProps, mapDispatchToProps)(Home));
|
||||
export const ConnectedHome = WithNewMessageNotification(connect(mapStateToProps, mapDispatchToProps)(Home));
|
||||
|
||||
const HomeWithParams = ({ ...props }) => {
|
||||
const socketId = useLoaderData();
|
||||
return <ConnectedHome socketId={socketId} {...props} />;
|
||||
};
|
||||
|
||||
export default HomeWithParams;
|
@ -1,55 +1,65 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import ConnectedHome from '.';
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from 'store';
|
||||
import { toggleWindowFocus, toggleNotificationEnabled, toggleSoundEnabled } from 'actions/app';
|
||||
import { receiveEncryptedMessage } from 'actions/encrypted_messages';
|
||||
import { notify, beep } from 'utils/notifications';
|
||||
import Tinycon from 'tinycon';
|
||||
import Modal from 'react-modal';
|
||||
import { expect, vi, describe, beforeEach, afterEach, it } from 'vitest';
|
||||
|
||||
import configureStore from '@/store';
|
||||
import { toggleWindowFocus, toggleNotificationEnabled, toggleSoundEnabled } from '@/actions/app';
|
||||
import { receiveEncryptedMessage } from '@/actions/encrypted_messages';
|
||||
import { notify, beep } from '@/utils/notifications';
|
||||
|
||||
import { ConnectedHome } from './';
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
|
||||
// We don't test activity list here
|
||||
jest.mock('./ActivityList', () => {
|
||||
return jest.fn().mockReturnValue(null);
|
||||
});
|
||||
vi.mock('react-modal'); // Cant load modal without root app element
|
||||
|
||||
jest.mock('react-modal'); // Cant load modal without root app element
|
||||
|
||||
jest.mock('utils/socket', () => {
|
||||
vi.mock('nanoid', () => {
|
||||
// Avoid exception
|
||||
return {
|
||||
connect: jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
on: jest.fn(),
|
||||
emit: jest.fn(),
|
||||
};
|
||||
}),
|
||||
getSocket: jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
on: jest.fn(),
|
||||
emit: jest.fn(),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('shortid', () => {
|
||||
// Avoid exception
|
||||
return {
|
||||
generate: jest.fn().mockImplementation(() => {
|
||||
nanoid: vi.fn().mockImplementation(() => {
|
||||
return 'shortidgenerated';
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('utils/crypto', () => {
|
||||
vi.mock('tinycon', () => {
|
||||
return {
|
||||
default: { setBubble: vi.fn() },
|
||||
};
|
||||
});
|
||||
|
||||
// We don't test activity list here
|
||||
vi.mock('./ActivityList', () => {
|
||||
return { default: vi.fn().mockReturnValue(null) };
|
||||
});
|
||||
|
||||
vi.mock('@/utils/socket', () => {
|
||||
// Avoid exception
|
||||
return {
|
||||
connect: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
on: vi.fn(),
|
||||
emit: vi.fn(),
|
||||
};
|
||||
}),
|
||||
getSocket: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
on: vi.fn(),
|
||||
emit: vi.fn(),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@/utils/crypto', () => {
|
||||
// Need window.crytpo.subtle
|
||||
return jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
default: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
createEncryptDecryptKeys: () => {
|
||||
return {
|
||||
@ -61,28 +71,23 @@ jest.mock('utils/crypto', () => {
|
||||
return { n: 'exportedKey' };
|
||||
},
|
||||
};
|
||||
});
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('utils/message', () => {
|
||||
vi.mock('@/utils/message', () => {
|
||||
return {
|
||||
process: jest.fn(async (payload, state) => ({
|
||||
process: vi.fn(async (payload, state) => ({
|
||||
...payload,
|
||||
payload: { payload: 'text', username: 'sender', text: 'new message' },
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('utils/notifications', () => {
|
||||
vi.mock('@/utils/notifications', () => {
|
||||
return {
|
||||
notify: jest.fn(),
|
||||
beep: { play: jest.fn() },
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('tinycon', () => {
|
||||
return {
|
||||
setBubble: jest.fn(),
|
||||
notify: vi.fn(),
|
||||
beep: { play: vi.fn() },
|
||||
};
|
||||
});
|
||||
|
||||
@ -143,7 +148,7 @@ describe('Connected Home component', () => {
|
||||
});
|
||||
|
||||
it('should send notifications', async () => {
|
||||
Modal.prototype.getSnapshotBeforeUpdate = jest.fn().mockReturnValue(null);
|
||||
Modal.prototype.getSnapshotBeforeUpdate = vi.fn().mockReturnValue(null);
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<ConnectedHome match={{ params: { roomId: 'roomTest' } }} userId="testUserId" roomId={'testId'} />
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import Message from '.';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Message component is displaying', async () => {
|
||||
const { asFragment } = render(<Message sender={'linus'} timestamp={1588794269074} message={'we come in peace'} />);
|
@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Message component is displaying 1`] = `
|
||||
<DocumentFragment>
|
||||
@ -20,12 +20,8 @@ exports[`Message component is displaying 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="chat"
|
||||
>
|
||||
<span
|
||||
class="Linkify"
|
||||
>
|
||||
we come in peace
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
@ -1,9 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Username from 'components/Username';
|
||||
import moment from 'moment';
|
||||
import Linkify from 'react-linkify';
|
||||
|
||||
import Username from '@/components/Username';
|
||||
|
||||
class Message extends Component {
|
||||
render() {
|
||||
const msg = decodeURI(this.props.message);
|
@ -1,19 +1,21 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent, waitFor } from '@testing-library/react';
|
||||
import Nav from '.';
|
||||
import mock$ from 'jquery';
|
||||
import { test, expect, vi } from 'vitest';
|
||||
|
||||
const mockTooltip = jest.fn().mockImplementation(param => {
|
||||
import Nav from '.';
|
||||
|
||||
const mockTooltip = vi.fn().mockImplementation(param => {
|
||||
// console.log('tooltip', param);
|
||||
});
|
||||
|
||||
const mockCollapse = jest.fn().mockImplementation(param => {
|
||||
const mockCollapse = vi.fn().mockImplementation(param => {
|
||||
// console.log('collapse', param);
|
||||
});
|
||||
|
||||
jest.mock('jquery', () => {
|
||||
return jest.fn().mockImplementation(param => {
|
||||
// console.log('$', param);
|
||||
vi.mock('jquery', () => {
|
||||
return {
|
||||
default: vi.fn().mockImplementation(param => {
|
||||
if (typeof param === 'function') {
|
||||
param();
|
||||
}
|
||||
@ -21,18 +23,19 @@ jest.mock('jquery', () => {
|
||||
tooltip: mockTooltip,
|
||||
collapse: mockCollapse,
|
||||
};
|
||||
});
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('shortid', () => {
|
||||
vi.mock('nanoid', () => {
|
||||
return {
|
||||
generate() {
|
||||
nanoid: () => {
|
||||
return 'fakeid';
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
|
||||
const mockTranslations = {
|
||||
newRoomButton: 'new room',
|
||||
@ -101,9 +104,9 @@ test('Nav component is displaying with another configuration and can rerender',
|
||||
});
|
||||
|
||||
test('Can copy room url', async () => {
|
||||
document.execCommand = jest.fn(() => true);
|
||||
document.execCommand = vi.fn(() => true);
|
||||
|
||||
const toggleLockRoom = jest.fn();
|
||||
const toggleLockRoom = vi.fn();
|
||||
|
||||
const { getByText } = render(
|
||||
<Nav
|
||||
@ -128,14 +131,14 @@ test('Can copy room url', async () => {
|
||||
expect(mockTooltip).toHaveBeenLastCalledWith('show');
|
||||
|
||||
// Wait tooltip closing
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
|
||||
expect(mock$).toHaveBeenCalledTimes(18);
|
||||
expect(mockTooltip).toHaveBeenLastCalledWith('hide');
|
||||
});
|
||||
|
||||
test('Can lock/unlock room is room owner only', async () => {
|
||||
const toggleLockRoom = jest.fn();
|
||||
const toggleLockRoom = vi.fn();
|
||||
|
||||
const { rerender, getByTitle } = render(
|
||||
<Nav
|
||||
@ -231,7 +234,7 @@ test('Can show user list', async () => {
|
||||
});
|
||||
|
||||
test('Can open settings', async () => {
|
||||
const openModal = jest.fn();
|
||||
const openModal = vi.fn();
|
||||
|
||||
// Test with one user owner and me
|
||||
const { getByText } = render(
|
||||
@ -255,7 +258,7 @@ test('Can open settings', async () => {
|
||||
});
|
||||
|
||||
test('Can open About', async () => {
|
||||
const openModal = jest.fn();
|
||||
const openModal = vi.fn();
|
||||
|
||||
// Test with one user owner and me
|
||||
const { getByText } = render(
|
||||
@ -279,7 +282,7 @@ test('Can open About', async () => {
|
||||
});
|
||||
|
||||
test('Can open About', async () => {
|
||||
window.open = jest.fn();
|
||||
window.open = vi.fn();
|
||||
|
||||
// Test with one user owner and me
|
||||
const { getByText } = render(
|
@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Nav component is displaying 1`] = `
|
||||
<DocumentFragment>
|
||||
@ -11,11 +11,11 @@ exports[`Nav component is displaying 1`] = `
|
||||
<img
|
||||
alt="Darkwire"
|
||||
class="logo"
|
||||
src="logo.png"
|
||||
src="/src/img/logo.png"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-plain btn-link clipboard-trigger room-id ellipsis"
|
||||
data-clipboard-text="http://localhost/testRoom"
|
||||
data-clipboard-text="http://localhost:3000/testRoom"
|
||||
data-placement="bottom"
|
||||
data-toggle="tooltip"
|
||||
>
|
||||
@ -227,7 +227,7 @@ exports[`Nav component is displaying 1`] = `
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
x2="12.01"
|
||||
y1="8"
|
||||
y2="8"
|
||||
/>
|
||||
@ -253,11 +253,11 @@ exports[`Nav component is displaying with another configuration and can rerender
|
||||
<img
|
||||
alt="Darkwire"
|
||||
class="logo"
|
||||
src="logo.png"
|
||||
src="/src/img/logo.png"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-plain btn-link clipboard-trigger room-id ellipsis"
|
||||
data-clipboard-text="http://localhost/testRoom_2"
|
||||
data-clipboard-text="http://localhost:3000/testRoom_2"
|
||||
data-placement="bottom"
|
||||
data-toggle="tooltip"
|
||||
>
|
||||
@ -515,7 +515,7 @@ exports[`Nav component is displaying with another configuration and can rerender
|
||||
/>
|
||||
<line
|
||||
x1="12"
|
||||
x2="12"
|
||||
x2="12.01"
|
||||
y1="8"
|
||||
y2="8"
|
||||
/>
|
@ -1,13 +1,14 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import shortId from 'shortid';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { Info, Settings, PlusCircle, User, Users, Lock, Unlock, Star } from 'react-feather';
|
||||
import logoImg from 'img/logo.png';
|
||||
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
|
||||
import Username from 'components/Username';
|
||||
import Clipboard from 'clipboard';
|
||||
import $ from 'jquery';
|
||||
|
||||
import logoImg from '@/img/logo.png';
|
||||
import Username from '@/components/Username';
|
||||
|
||||
class Nav extends Component {
|
||||
componentDidMount() {
|
||||
const clip = new Clipboard('.clipboard-trigger');
|
||||
@ -38,7 +39,7 @@ class Nav extends Component {
|
||||
|
||||
newRoom() {
|
||||
$('.navbar-collapse').collapse('hide');
|
||||
window.open(`/${shortId.generate()}`);
|
||||
window.open(`/${nanoid()}`);
|
||||
}
|
||||
|
||||
handleSettingsClick() {
|
||||
@ -138,10 +139,7 @@ class Nav extends Component {
|
||||
<PlusCircle /> <span>{this.props.translations.newRoomButton}</span>
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
className="
|
||||
nav-item"
|
||||
>
|
||||
<li className="nav-item">
|
||||
<button onClick={this.handleSettingsClick.bind(this)} className="btn btn-plain nav-link">
|
||||
<Settings /> <span>{this.props.translations.settingsButton}</span>
|
||||
</button>
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import Notice from '.';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Notice component is displaying', async () => {
|
||||
const { asFragment } = render(
|
@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Notice component is displaying 1`] = `
|
||||
<DocumentFragment>
|
@ -2,24 +2,24 @@ import React from 'react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import RoomLink from '.';
|
||||
import mock$ from 'jquery';
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
|
||||
const mockTooltip = jest.fn().mockImplementation(param => {
|
||||
// console.log('tooltip', param);
|
||||
});
|
||||
const mockTooltip = vi.fn().mockImplementation(param => {});
|
||||
|
||||
jest.mock('jquery', () => {
|
||||
return jest.fn().mockImplementation(param => {
|
||||
// console.log('$', param);
|
||||
vi.mock('jquery', () => {
|
||||
return {
|
||||
default: vi.fn().mockImplementation(param => {
|
||||
if (typeof param === 'function') {
|
||||
param();
|
||||
}
|
||||
return {
|
||||
tooltip: mockTooltip,
|
||||
};
|
||||
});
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
|
||||
const mockTranslations = {
|
||||
copyButtonTooltip: 'copyButton',
|
||||
@ -47,11 +47,11 @@ describe('RoomLink', () => {
|
||||
|
||||
it('should copy link', async () => {
|
||||
// Mock execCommand for paste
|
||||
document.execCommand = jest.fn(() => true);
|
||||
document.execCommand = vi.fn(() => true);
|
||||
|
||||
const { getByTitle } = render(<RoomLink roomId="roomId" translations={mockTranslations} />);
|
||||
|
||||
fireEvent.click(getByTitle(mockTranslations.copyButtonTooltip));
|
||||
await fireEvent.click(getByTitle(mockTranslations.copyButtonTooltip));
|
||||
|
||||
expect(document.execCommand).toHaveBeenLastCalledWith('copy');
|
||||
expect(mock$).toHaveBeenCalledTimes(4);
|
||||
@ -59,7 +59,7 @@ describe('RoomLink', () => {
|
||||
expect(mockTooltip).toHaveBeenLastCalledWith('show');
|
||||
|
||||
// Wait for tooltip to close
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
|
||||
expect(mock$).toHaveBeenCalledTimes(6);
|
||||
expect(mock$).toHaveBeenLastCalledWith('.copy-room');
|
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`RoomLink should display 1`] = `
|
||||
exports[`RoomLink > should display 1`] = `
|
||||
<DocumentFragment>
|
||||
<form>
|
||||
<div
|
||||
@ -14,14 +14,14 @@ exports[`RoomLink should display 1`] = `
|
||||
id="room-url"
|
||||
readonly=""
|
||||
type="text"
|
||||
value="http://localhost/roomId"
|
||||
value="http://localhost:3000/roomId"
|
||||
/>
|
||||
<div
|
||||
class="input-group-append"
|
||||
>
|
||||
<button
|
||||
class="copy-room btn btn-secondary"
|
||||
data-clipboard-text="http://localhost/roomId"
|
||||
data-clipboard-text="http://localhost:3000/roomId"
|
||||
data-placement="bottom"
|
||||
data-toggle="tooltip"
|
||||
title="copyButton"
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import RoomLocked from '.';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('RoomLocked component should display', () => {
|
||||
const { asFragment } = render(<RoomLocked modalContent={'test'} />);
|
@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`RoomLocked component should display 1`] = `
|
||||
<DocumentFragment>
|
@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from 'store';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
import configureStore from '@/store';
|
||||
|
||||
import Settings from '.';
|
||||
|
||||
@ -11,9 +13,24 @@ const mockTranslations = {
|
||||
sound: 'soundCheck',
|
||||
};
|
||||
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
|
||||
jest.mock('components/RoomLink');
|
||||
vi.mock('@/components/RoomLink');
|
||||
|
||||
const mockTooltip = vi.fn().mockImplementation(param => {});
|
||||
|
||||
vi.mock('jquery', () => {
|
||||
return {
|
||||
default: vi.fn().mockImplementation(param => {
|
||||
if (typeof param === 'function') {
|
||||
param();
|
||||
}
|
||||
return {
|
||||
tooltip: mockTooltip,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Settings component', () => {
|
||||
it('should display', async () => {
|
||||
@ -24,7 +41,7 @@ describe('Settings component', () => {
|
||||
toggleSoundEnabled={() => {}}
|
||||
notificationIsEnabled={true}
|
||||
toggleNotificationEnabled={() => {}}
|
||||
toggleNotificationAllowed={jest.fn()}
|
||||
toggleNotificationAllowed={vi.fn()}
|
||||
roomId="roomId"
|
||||
setLanguage={() => {}}
|
||||
translations={{}}
|
||||
@ -42,7 +59,7 @@ describe('Settings component', () => {
|
||||
notificationIsEnabled={true}
|
||||
notificationIsAllowed={false}
|
||||
toggleNotificationEnabled={() => {}}
|
||||
toggleNotificationAllowed={jest.fn()}
|
||||
toggleNotificationAllowed={vi.fn()}
|
||||
roomId="roomId"
|
||||
setLanguage={() => {}}
|
||||
translations={{}}
|
||||
@ -54,7 +71,7 @@ describe('Settings component', () => {
|
||||
});
|
||||
|
||||
it('should toggle sound', async () => {
|
||||
const toggleSound = jest.fn();
|
||||
const toggleSound = vi.fn();
|
||||
const { getByText } = render(
|
||||
<Provider store={store}>
|
||||
<Settings
|
||||
@ -63,7 +80,7 @@ describe('Settings component', () => {
|
||||
notificationIsEnabled={true}
|
||||
notificationIsAllowed={true}
|
||||
toggleNotificationEnabled={() => {}}
|
||||
toggleNotificationAllowed={jest.fn()}
|
||||
toggleNotificationAllowed={vi.fn()}
|
||||
roomId="roomId"
|
||||
setLanguage={() => {}}
|
||||
translations={{}}
|
||||
@ -79,10 +96,10 @@ describe('Settings component', () => {
|
||||
|
||||
it('should toggle notifications', async () => {
|
||||
global.Notification = {
|
||||
requestPermission: jest.fn().mockResolvedValue('granted'),
|
||||
requestPermission: vi.fn().mockResolvedValue('granted'),
|
||||
};
|
||||
|
||||
const toggleNotifications = jest.fn();
|
||||
const toggleNotifications = vi.fn();
|
||||
const { getByText } = render(
|
||||
<Provider store={store}>
|
||||
<Settings
|
||||
@ -91,7 +108,7 @@ describe('Settings component', () => {
|
||||
notificationIsEnabled={true}
|
||||
notificationIsAllowed={true}
|
||||
toggleNotificationEnabled={toggleNotifications}
|
||||
toggleNotificationAllowed={jest.fn()}
|
||||
toggleNotificationAllowed={vi.fn()}
|
||||
roomId="roomId"
|
||||
setLanguage={() => {}}
|
||||
translations={{}}
|
||||
@ -101,7 +118,7 @@ describe('Settings component', () => {
|
||||
|
||||
fireEvent.click(getByText('Desktop Notification'));
|
||||
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
|
||||
delete global.Notification;
|
||||
|
||||
@ -110,11 +127,11 @@ describe('Settings component', () => {
|
||||
|
||||
it('should not toggle notifications', async () => {
|
||||
global.Notification = {
|
||||
requestPermission: jest.fn().mockResolvedValue('denied'),
|
||||
requestPermission: vi.fn().mockResolvedValue('denied'),
|
||||
};
|
||||
|
||||
const toggleNotifications = jest.fn();
|
||||
const toggleAllowed = jest.fn();
|
||||
const toggleNotifications = vi.fn();
|
||||
const toggleAllowed = vi.fn();
|
||||
const { getByText } = render(
|
||||
<Provider store={store}>
|
||||
<Settings
|
||||
@ -133,7 +150,7 @@ describe('Settings component', () => {
|
||||
|
||||
fireEvent.click(getByText('Desktop Notification'));
|
||||
|
||||
jest.runAllTimers();
|
||||
vi.runAllTimers();
|
||||
|
||||
delete global.Notification;
|
||||
|
||||
@ -142,7 +159,7 @@ describe('Settings component', () => {
|
||||
});
|
||||
|
||||
it('should change lang', async () => {
|
||||
const changeLang = jest.fn();
|
||||
const changeLang = vi.fn();
|
||||
|
||||
const { getByDisplayValue } = render(
|
||||
<Provider store={store}>
|
||||
@ -151,7 +168,7 @@ describe('Settings component', () => {
|
||||
toggleSoundEnabled={() => {}}
|
||||
notificationIsEnabled={true}
|
||||
toggleNotificationEnabled={() => {}}
|
||||
toggleNotificationAllowed={jest.fn()}
|
||||
toggleNotificationAllowed={vi.fn()}
|
||||
roomId="roomId"
|
||||
setLanguage={changeLang}
|
||||
translations={{}}
|
@ -1,9 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Settings component should display 1`] = `
|
||||
exports[`Settings component > should display 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="styles"
|
||||
class="_styles_23b490"
|
||||
>
|
||||
<section>
|
||||
<h4>
|
||||
@ -127,6 +127,11 @@ exports[`Settings component should display 1`] = `
|
||||
>
|
||||
Türkçe
|
||||
</option>
|
||||
<option
|
||||
value="ko"
|
||||
>
|
||||
한국어
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</section>
|
||||
@ -192,10 +197,10 @@ exports[`Settings component should display 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Settings component should display 2`] = `
|
||||
exports[`Settings component > should display 2`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="styles"
|
||||
class="_styles_23b490"
|
||||
>
|
||||
<section>
|
||||
<h4>
|
||||
@ -313,6 +318,11 @@ exports[`Settings component should display 2`] = `
|
||||
>
|
||||
Türkçe
|
||||
</option>
|
||||
<option
|
||||
value="ko"
|
||||
>
|
||||
한국어
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</section>
|
@ -1,9 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import RoomLink from 'components/RoomLink';
|
||||
import { styles } from './styles.module.scss';
|
||||
import Cookie from 'js-cookie';
|
||||
import T from 'components/T';
|
||||
|
||||
import RoomLink from '@/components/RoomLink';
|
||||
import T from '@/components/T';
|
||||
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
class Settings extends Component {
|
||||
handleSoundToggle() {
|
||||
@ -30,7 +32,7 @@ class Settings extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles}>
|
||||
<div className={classes.styles}>
|
||||
<section>
|
||||
<h4>
|
||||
<T path="newMessageNotification" />
|
@ -1,8 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getTranslations } from 'i18n';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getTranslations } from '@/i18n';
|
||||
|
||||
const regex = /{(.*?)}/g;
|
||||
|
||||
class T extends Component {
|
@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { test, expect, vi } from 'vitest';
|
||||
|
||||
import T from './T';
|
||||
|
||||
// To avoid missing provider
|
||||
jest.mock('components/T');
|
||||
vi.mock('components/T');
|
||||
|
||||
test('T component is displaying', async () => {
|
||||
const { asFragment, rerender } = render(<T path="welcomeHeader" language="en" />);
|
@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`T component is displaying 1`] = `
|
||||
<DocumentFragment>
|
@ -1,5 +1,5 @@
|
||||
import { connect } from 'react-redux';
|
||||
import T from 'components/T/T';
|
||||
import T from './T';
|
||||
|
||||
export default connect((state, ownProps) => ({
|
||||
language: state.app.language,
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
import Username from '.';
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Username component is displaying 1`] = `
|
||||
<DocumentFragment>
|
@ -1,8 +1,11 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { test, expect, vi } from 'vitest';
|
||||
|
||||
import Welcome from '.';
|
||||
|
||||
vi.mock('@/components/RoomLink');
|
||||
|
||||
test('Welcome component is displaying', async () => {
|
||||
const { asFragment } = render(<Welcome roomId="roomtest" close={() => {}} translations={{}} />);
|
||||
|
@ -1,106 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Welcome component is displaying 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div>
|
||||
v2.0 is a complete rewrite and includes several new features. Here are some highlights:
|
||||
<ul
|
||||
class="native"
|
||||
>
|
||||
<li>
|
||||
Support on all modern browsers (Chrome, Firefox, Safari, Safari iOS, Android)
|
||||
</li>
|
||||
<li>
|
||||
Slash commands (/nick, /me, /clear)
|
||||
</li>
|
||||
<li>
|
||||
Room owners can lock the room, preventing anyone else from joining
|
||||
</li>
|
||||
<li>
|
||||
Front-end rewritten in React.js and Redux
|
||||
</li>
|
||||
<li>
|
||||
Send files up to 4 MB
|
||||
</li>
|
||||
</ul>
|
||||
<div>
|
||||
You can learn more
|
||||
<a
|
||||
href="https://github.com/darkwire/darkwire.io"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
here
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<p
|
||||
class="mb-2"
|
||||
>
|
||||
Others can join this room using the following URL:
|
||||
</p>
|
||||
<form>
|
||||
<div
|
||||
class="form-group"
|
||||
>
|
||||
<div
|
||||
class="input-group"
|
||||
>
|
||||
<input
|
||||
class="form-control"
|
||||
id="room-url"
|
||||
readonly=""
|
||||
type="text"
|
||||
value="http://localhost/roomtest"
|
||||
/>
|
||||
<div
|
||||
class="input-group-append"
|
||||
>
|
||||
<button
|
||||
class="copy-room btn btn-secondary"
|
||||
data-clipboard-text="http://localhost/roomtest"
|
||||
data-placement="bottom"
|
||||
data-toggle="tooltip"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
height="13"
|
||||
rx="2"
|
||||
ry="2"
|
||||
width="13"
|
||||
x="9"
|
||||
y="9"
|
||||
/>
|
||||
<path
|
||||
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div
|
||||
class="react-modal-footer"
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary btn-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -0,0 +1,54 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Welcome component is displaying 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div>
|
||||
v2.0 is a complete rewrite and includes several new features. Here are some highlights:
|
||||
<ul
|
||||
class="native"
|
||||
>
|
||||
<li>
|
||||
Support on all modern browsers (Chrome, Firefox, Safari, Safari iOS, Android)
|
||||
</li>
|
||||
<li>
|
||||
Slash commands (/nick, /me, /clear)
|
||||
</li>
|
||||
<li>
|
||||
Room owners can lock the room, preventing anyone else from joining
|
||||
</li>
|
||||
<li>
|
||||
Front-end rewritten in React.js and Redux
|
||||
</li>
|
||||
<li>
|
||||
Send files up to 4 MB
|
||||
</li>
|
||||
</ul>
|
||||
<div>
|
||||
You can learn more
|
||||
<a
|
||||
href="https://github.com/darkwire/darkwire.io"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
here
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<p
|
||||
class="mb-2"
|
||||
>
|
||||
Others can join this room using the following URL:
|
||||
</p>
|
||||
<div
|
||||
class="react-modal-footer"
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary btn-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import RoomLink from 'components/RoomLink';
|
||||
import RoomLink from '@/components/RoomLink';
|
||||
|
||||
class Welcome extends Component {
|
||||
constructor(props) {
|
@ -1,2 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
export default process.env.NODE_ENV;
|
||||
export const MAX_FILE_SIZE = import.meta.VITE_MAX_FILE_SIZE || 4;
|
||||
export const COMMIT_SHA = import.meta.env.VITE_COMMIT_SHA;
|
||||
|
||||
export default import.meta.env.NODE_ENV;
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { getTranslations } from './index.js';
|
||||
import { getTranslations } from './';
|
||||
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Get translation', () => {
|
||||
expect(getTranslations('en').welcomeHeader).toBe('Welcome to Darkwire v2.0');
|
||||
|
@ -34,11 +34,11 @@ const languagesMap = {
|
||||
export function getTranslations(language = '') {
|
||||
const [lang, variant] = language.split('-');
|
||||
|
||||
if (languagesMap.hasOwnProperty(`${lang}${variant}`)) {
|
||||
if (Object.prototype.hasOwnProperty.call(languagesMap, `${lang}${variant}`)) {
|
||||
return languagesMap[`${lang}${variant}`];
|
||||
}
|
||||
|
||||
if (languagesMap.hasOwnProperty(lang)) {
|
||||
if (Object.prototype.hasOwnProperty.call(languagesMap, `${lang}`)) {
|
||||
return languagesMap[lang];
|
||||
}
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import Root from './root';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
|
||||
ReactDOM.render(<Root />, document.getElementById('root'));
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||
serviceWorker.unregister();
|
@ -1,5 +0,0 @@
|
||||
describe('Timezones', () => {
|
||||
it('should always be UTC', () => {
|
||||
expect(new Date().getTimezoneOffset()).toBe(0);
|
||||
});
|
||||
});
|
52
client/src/main.tsx
Normal file
52
client/src/main.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { createBrowserRouter, RouterProvider, Navigate } from 'react-router-dom';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'react-simple-dropdown/styles/Dropdown.css';
|
||||
import './stylesheets/app.sass';
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||
|
||||
import configureStore from '@/store/';
|
||||
import Home from '@/components/Home/';
|
||||
import { hasTouchSupport } from '@/utils/dom';
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: '/',
|
||||
element: <Navigate to={`/${nanoid()}`} replace />,
|
||||
},
|
||||
{
|
||||
path: '/:roomId',
|
||||
element: <Home />,
|
||||
loader({ params }) {
|
||||
return encodeURI(params.roomId ? params.roomId : '');
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const Main = () => {
|
||||
React.useEffect(() => {
|
||||
if (hasTouchSupport) {
|
||||
document.body.classList.add('touch');
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<RouterProvider router={router} />
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const root = createRoot(document.getElementById('root') as HTMLElement);
|
||||
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<Main />
|
||||
</React.StrictMode>,
|
||||
);
|
@ -76,10 +76,7 @@ const activities = (state = initialState, action) => {
|
||||
],
|
||||
};
|
||||
case 'RECEIVE_ENCRYPTED_MESSAGE_ADD_USER':
|
||||
const newUserId = action.payload.payload.id;
|
||||
|
||||
const haveUser = action.payload.state.room.members.find(m => m.id === newUserId);
|
||||
if (haveUser) {
|
||||
if (action.payload.state.room.members.find(m => m.id === action.payload.payload.id)) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -88,7 +85,7 @@ const activities = (state = initialState, action) => {
|
||||
items: [
|
||||
...state.items,
|
||||
{
|
||||
userId: newUserId,
|
||||
userId: action.payload.payload.id,
|
||||
type: 'USER_ENTER',
|
||||
username: action.payload.payload.username,
|
||||
},
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import reducer from './activities';
|
||||
|
||||
describe('Activities reducer', () => {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Cookie from 'js-cookie';
|
||||
import { getTranslations } from 'i18n';
|
||||
|
||||
import { getTranslations } from '@/i18n';
|
||||
|
||||
const language = Cookie.get('language') || navigator.language || 'en';
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
import reducer from './app';
|
||||
import { getTranslations } from 'i18n';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
jest.mock('i18n', () => {
|
||||
import reducer from './app';
|
||||
import { getTranslations } from '@/i18n';
|
||||
|
||||
vi.mock('@/i18n', () => {
|
||||
return {
|
||||
getTranslations: jest.fn().mockReturnValue({ path: 'test' }),
|
||||
getTranslations: vi.fn().mockReturnValue({ path: 'test' }),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* istanbul ignore file */
|
||||
import { combineReducers } from 'redux';
|
||||
|
||||
import app from './app';
|
||||
import activities from './activities';
|
||||
import user from './user';
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
import _ from 'lodash';
|
||||
|
||||
const initialState = {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import reducer from './room';
|
||||
|
||||
describe('Room reducer', () => {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
import reducer from './user';
|
||||
|
||||
jest.mock('i18n', () => {
|
||||
vi.mock('@/i18n', () => {
|
||||
return {
|
||||
getTranslations: jest.fn().mockReturnValue({ path: 'test' }),
|
||||
getTranslations: vi.fn().mockReturnValue({ path: 'test' }),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -5,7 +5,7 @@ import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from 'store';
|
||||
import configureStore from './store';
|
||||
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
||||
import shortId from 'shortid';
|
||||
import Home from 'components/Home';
|
@ -20,9 +20,9 @@ const isLocalhost = Boolean(
|
||||
);
|
||||
|
||||
export function register(config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
if (import.meta.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||
const publicUrl = new URL(import.meta.env.PUBLIC_URL, window.location.href);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
@ -31,7 +31,7 @@ export function register(config) {
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
const swUrl = `${import.meta.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
|
@ -1,8 +1,14 @@
|
||||
import { configure } from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
// this adds jest-dom's custom assertions
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { enableFetchMocks } from 'jest-fetch-mock';
|
||||
import { expect, afterEach, vi } from 'vitest';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import matchers from '@testing-library/jest-dom/extend-expect';
|
||||
import createFetchMock from 'vitest-fetch-mock';
|
||||
|
||||
configure({ adapter: new Adapter() });
|
||||
enableFetchMocks();
|
||||
const fetchMock = createFetchMock(vi);
|
||||
fetchMock.enableMocks();
|
||||
|
||||
expect.extend(matchers);
|
||||
|
||||
// runs a cleanup after each test case (e.g. clearing jsdom)
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
import { createStore, applyMiddleware, compose } from 'redux';
|
||||
import reducers from 'reducers';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import reducers from '@/reducers';
|
||||
|
||||
const composeEnhancers =
|
||||
process.env.NODE_ENV === 'production' ? compose : window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
import.meta.env.NODE_ENV === 'production' ? compose : window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
|
||||
const enabledMiddlewares = [thunk];
|
||||
|
||||
@ -12,14 +13,5 @@ const middlewares = applyMiddleware(...enabledMiddlewares);
|
||||
|
||||
export default function configureStore(preloadedState) {
|
||||
const store = createStore(reducers, preloadedState, composeEnhancers(middlewares));
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept('../reducers', () => {
|
||||
// eslint-disable-next-line global-require
|
||||
const nextRootReducer = require('../reducers/index');
|
||||
store.replaceReducer(nextRootReducer);
|
||||
});
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import Enzyme from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
@ -1,4 +1,3 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
export const getSelectedText = () => {
|
||||
let text = '';
|
||||
if (typeof window.getSelection !== 'undefined') {
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
export const getObjectUrl = (encodedFile, fileType) => {
|
||||
const b64 = unescape(encodedFile);
|
||||
const sliceSize = 1024;
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
export function sanitize(str) {
|
||||
return str.replace(/[^A-Za-z0-9._]/g, '-').replace(/[<>]/gi, '');
|
||||
}
|
||||
|
@ -2,22 +2,19 @@ import Crypto from './crypto';
|
||||
|
||||
const crypto = new Crypto();
|
||||
|
||||
export const process = (payload, state) =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
export const process = async (payload, state) => {
|
||||
const privateKeyJson = state.user.privateKey;
|
||||
const privateKey = await crypto.importEncryptDecryptKey(privateKeyJson, 'jwk', ['decrypt', 'unwrapKey']);
|
||||
|
||||
let sessionKey;
|
||||
let signingKey;
|
||||
|
||||
const iv = await crypto.convertStringToArrayBufferView(payload.iv);
|
||||
const signature = await crypto.convertStringToArrayBufferView(payload.signature);
|
||||
const payloadBuffer = await crypto.convertStringToArrayBufferView(payload.payload);
|
||||
|
||||
await new Promise(resolvePayload => {
|
||||
// We try to decrypt all sessions and signin keys to get the one encrypted for self
|
||||
const [sessionKey, signingKey] = await new Promise(resolvePayload => {
|
||||
payload.keys.forEach(async key => {
|
||||
try {
|
||||
sessionKey = await crypto.unwrapKey(
|
||||
const sessionKey = await crypto.unwrapKey(
|
||||
'jwk',
|
||||
key.sessionKey,
|
||||
privateKey,
|
||||
@ -30,7 +27,7 @@ export const process = (payload, state) =>
|
||||
['decrypt'],
|
||||
);
|
||||
|
||||
signingKey = await crypto.unwrapKey(
|
||||
const signingKey = await crypto.unwrapKey(
|
||||
'jwk',
|
||||
key.signingKey,
|
||||
privateKey,
|
||||
@ -42,7 +39,7 @@ export const process = (payload, state) =>
|
||||
true,
|
||||
['verify'],
|
||||
);
|
||||
resolvePayload();
|
||||
resolvePayload([sessionKey, signingKey]);
|
||||
} catch (e) {} // eslint-disable-line
|
||||
});
|
||||
});
|
||||
@ -50,19 +47,17 @@ export const process = (payload, state) =>
|
||||
const verified = await crypto.verifyPayload(signature, payloadBuffer, signingKey);
|
||||
|
||||
if (!verified) {
|
||||
reject();
|
||||
return;
|
||||
throw new Error("Can't verify message");
|
||||
}
|
||||
|
||||
const decryptedPayload = await crypto.decryptMessage(payloadBuffer, sessionKey, iv);
|
||||
|
||||
const payloadJson = JSON.parse(crypto.convertArrayBufferViewToString(new Uint8Array(decryptedPayload)));
|
||||
|
||||
resolve(payloadJson);
|
||||
});
|
||||
return payloadJson;
|
||||
};
|
||||
|
||||
export const prepare = (payload, state) =>
|
||||
new Promise(async resolve => {
|
||||
export const prepare = async (payload, state) => {
|
||||
const myUsername = state.user.username;
|
||||
const myId = state.user.id;
|
||||
|
||||
@ -101,7 +96,7 @@ export const prepare = (payload, state) =>
|
||||
const ivString = await crypto.convertArrayBufferViewToString(new Uint8Array(iv));
|
||||
const signatureString = await crypto.convertArrayBufferViewToString(new Uint8Array(signature));
|
||||
|
||||
resolve({
|
||||
return {
|
||||
toSend: {
|
||||
payload: payloadString,
|
||||
signature: signatureString,
|
||||
@ -109,5 +104,5 @@ export const prepare = (payload, state) =>
|
||||
keys: encryptedKeys,
|
||||
},
|
||||
original: jsonToSend,
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import beepFile from 'audio/beep.mp3';
|
||||
import beepFile from '@/audio/beep.mp3';
|
||||
|
||||
const showNotification = (title, message, avatarUrl) => {
|
||||
const showNotification = (title, message) => {
|
||||
const notifBody = {
|
||||
body: message,
|
||||
tag: 'darkwire',
|
||||
@ -44,6 +44,21 @@ export const notify = (title, content = '') => {
|
||||
}
|
||||
};
|
||||
|
||||
export const beep = (window.Audio && new window.Audio(beepFile)) || { play: () => {} };
|
||||
let theBeep;
|
||||
|
||||
export const beep = {
|
||||
async play() {
|
||||
if (window.Audio) {
|
||||
if (theBeep === undefined) {
|
||||
theBeep = new window.Audio(beepFile);
|
||||
}
|
||||
try {
|
||||
await theBeep.play();
|
||||
} catch (e) {
|
||||
console.log("Can't play sound.");
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default { notify, beep };
|
||||
|
@ -1,5 +1,5 @@
|
||||
import socketIO from 'socket.io-client';
|
||||
import generateUrl from '../api/generator';
|
||||
import generateUrl from '@/api/generator';
|
||||
|
||||
let socket;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user