first version
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import Avatar, { avatarFailback } from '../../src/components/Avatar';
|
||||
|
||||
describe('Avatar', () => {
|
||||
it('shoule render without error', async () => {
|
||||
render(<Avatar src="./1.jpg" />);
|
||||
const $img = await screen.findByRole('img');
|
||||
expect($img).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call props handler function when fire event', async () => {
|
||||
const handleClick = jest.fn();
|
||||
const handleMouseEnter = jest.fn();
|
||||
const handleMouseLeave = jest.fn();
|
||||
render(
|
||||
<Avatar
|
||||
src="./1.jpg"
|
||||
onClick={handleClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
/>,
|
||||
);
|
||||
const $img = await screen.findByRole('img');
|
||||
fireEvent.click($img);
|
||||
expect(handleClick).toBeCalled();
|
||||
fireEvent.mouseEnter($img);
|
||||
expect(handleMouseEnter).toBeCalled();
|
||||
fireEvent.mouseLeave($img);
|
||||
expect(handleMouseLeave).toBeCalled();
|
||||
});
|
||||
|
||||
it('shoule use failback avatar when fetch error', async () => {
|
||||
const src = 'origin.jpg';
|
||||
render(<Avatar src={src} />);
|
||||
const $img = (await screen.findByRole('img')) as HTMLImageElement;
|
||||
expect($img.src).toEqual(expect.stringContaining(src));
|
||||
fireEvent.error($img);
|
||||
expect($img.src).toEqual(expect.stringContaining(avatarFailback));
|
||||
fireEvent.error($img);
|
||||
fireEvent.error($img);
|
||||
});
|
||||
|
||||
it('shoule not add CDN query params', async () => {
|
||||
const src = 'data:base64/png;xxx';
|
||||
render(<Avatar src={src} />);
|
||||
const $img = (await screen.findByRole('img')) as HTMLImageElement;
|
||||
expect($img.src).not.toEqual(expect.stringContaining('x-oss-process='));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import Button from '../../src/components/Button';
|
||||
|
||||
describe('Button', () => {
|
||||
it('shoule render without error', async () => {
|
||||
render(<Button>text</Button>);
|
||||
const $button = screen.getByRole('button');
|
||||
expect($button).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shoule support set custom class name and type', async () => {
|
||||
render(
|
||||
<Button className="custom" type="danger">
|
||||
text
|
||||
</Button>,
|
||||
);
|
||||
const $button = screen.getByRole('button');
|
||||
expect($button.classList).toContain('custom');
|
||||
expect($button.classList).toContain('danger');
|
||||
});
|
||||
|
||||
it('shoule call props handler function when fire event', async () => {
|
||||
const handleClick = jest.fn();
|
||||
render(<Button onClick={handleClick}>text</Button>);
|
||||
const $button = screen.getByRole('button');
|
||||
fireEvent.click($button);
|
||||
expect(handleClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import getData, { LocalStorageKey } from '../src/localStorage';
|
||||
import config from '../../config/client';
|
||||
import themes from '../src/themes';
|
||||
|
||||
describe('client/localStorage.ts', () => {
|
||||
it('should return localStorage value, or default value if not exists', () => {
|
||||
expect(getData().sound).toBe(config.sound);
|
||||
localStorage.setItem(LocalStorageKey.Sound, 'huaji');
|
||||
expect(getData().sound).toBe('huaji');
|
||||
});
|
||||
|
||||
it('should return default theme config when them not exists', () => {
|
||||
localStorage.setItem(LocalStorageKey.Theme, 'xxx');
|
||||
expect(getData().primaryColor).toBe(themes.cool.primaryColor);
|
||||
});
|
||||
|
||||
it('should return boolean type value when value is true / false', () => {
|
||||
localStorage.setItem(LocalStorageKey.SoundSwitch, 'true');
|
||||
expect(getData().soundSwitch).toBe(true);
|
||||
localStorage.setItem(LocalStorageKey.SoundSwitch, 'false');
|
||||
expect(getData().soundSwitch).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,589 @@
|
||||
import getFriendId from '@fiora/utils/getFriendId';
|
||||
import reducer, { State, initialState } from '../../src/state/reducer';
|
||||
import { Action, ActionTypes } from '../../src/state/action';
|
||||
|
||||
describe('redux reducer', () => {
|
||||
it('should user initial state', () => {
|
||||
const action = { type: 'mock' as ActionTypes, payload: {} } as Action;
|
||||
expect(reducer(undefined, action)).toBe(initialState);
|
||||
});
|
||||
|
||||
it('should return origin state with unknown action', () => {
|
||||
const state = {} as State;
|
||||
const action = { type: 'mock' as ActionTypes, payload: {} } as Action;
|
||||
expect(reducer(state, action)).toBe(state);
|
||||
});
|
||||
|
||||
it('should set connect status to true', () => {
|
||||
const state = {
|
||||
connect: false,
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.Connect,
|
||||
payload: {},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.connect).toBe(true);
|
||||
});
|
||||
|
||||
it('should set connect status to false', () => {
|
||||
const state = {
|
||||
connect: true,
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.Disconnect,
|
||||
payload: {},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.connect).toBe(false);
|
||||
});
|
||||
|
||||
it('should set guest user and default group', () => {
|
||||
const state = {} as State;
|
||||
const group = {
|
||||
_id: '1',
|
||||
name: 'Default Group',
|
||||
};
|
||||
const action = {
|
||||
type: ActionTypes.SetGuest,
|
||||
payload: group,
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.user).not.toBe(null);
|
||||
expect(newState.linkmans[group._id]).toBe(group);
|
||||
expect(newState.focus).toBe(group._id);
|
||||
});
|
||||
|
||||
it('should set user and linkmans', () => {
|
||||
const state = {
|
||||
linkmans: {},
|
||||
} as State;
|
||||
const group = {
|
||||
_id: 'group',
|
||||
name: 'group',
|
||||
};
|
||||
const friend = {
|
||||
from: '111',
|
||||
to: {
|
||||
_id: '222',
|
||||
username: 'friend',
|
||||
},
|
||||
};
|
||||
const action = {
|
||||
type: ActionTypes.SetUser,
|
||||
payload: {
|
||||
_id: 'id',
|
||||
username: 'user',
|
||||
friends: [friend],
|
||||
groups: [group],
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.user).not.toBe(null);
|
||||
expect(Object.keys(newState.linkmans).length).toBe(2);
|
||||
expect(newState.linkmans[group._id].type).toBe('group');
|
||||
|
||||
const friendId = getFriendId(friend.from, friend.to._id);
|
||||
expect(newState.linkmans[friendId].type).toBe('friend');
|
||||
expect(newState.linkmans[friendId].name).toBe(friend.to.username);
|
||||
expect(newState.focus).toBe(group._id);
|
||||
});
|
||||
|
||||
it('should update user with payload data', () => {
|
||||
const state = {
|
||||
user: {
|
||||
_id: 'id',
|
||||
username: 'name',
|
||||
},
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.UpdateUserInfo,
|
||||
payload: {
|
||||
username: 'new',
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.user?.username).toBe('new');
|
||||
});
|
||||
|
||||
it('should set user to null', () => {
|
||||
const state = {
|
||||
user: {
|
||||
_id: 'id',
|
||||
},
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.Logout,
|
||||
payload: {},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.user).toEqual(null);
|
||||
});
|
||||
|
||||
it('should update user avatar', () => {
|
||||
const state = {
|
||||
user: {
|
||||
_id: 'id',
|
||||
avatar: 'avatar',
|
||||
},
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.SetAvatar,
|
||||
payload: 'new',
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.user?.avatar).toBe('new');
|
||||
});
|
||||
|
||||
it('should update focus and reduce exist messages when more than 50', () => {
|
||||
const linkman = {
|
||||
_id: '1',
|
||||
messages: {},
|
||||
};
|
||||
const state = {
|
||||
linkmans: {
|
||||
[linkman._id]: linkman,
|
||||
},
|
||||
focus: '',
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.SetFocus,
|
||||
payload: linkman._id,
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.focus).toBe(linkman._id);
|
||||
expect(
|
||||
Object.keys(newState.linkmans[newState.focus].messages),
|
||||
).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should reduce exist messages when more than 50', () => {
|
||||
const messages: { [id: string]: any } = {};
|
||||
for (let i = 0; i < 51; i++) {
|
||||
messages[i] = {
|
||||
_id: i,
|
||||
};
|
||||
}
|
||||
const linkman = {
|
||||
_id: '1',
|
||||
messages,
|
||||
unread: 10,
|
||||
};
|
||||
const state = {
|
||||
linkmans: {
|
||||
[linkman._id]: linkman,
|
||||
},
|
||||
focus: '',
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.SetFocus,
|
||||
payload: linkman._id,
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(
|
||||
Object.keys(newState.linkmans[newState.focus].messages),
|
||||
).toHaveLength(50);
|
||||
});
|
||||
|
||||
it('should be no change when foucs not exits user id', () => {
|
||||
const linkman = {
|
||||
id: '1',
|
||||
};
|
||||
// @ts-ignore
|
||||
const state = {
|
||||
linkmans: {
|
||||
[linkman.id]: linkman,
|
||||
},
|
||||
focus: linkman.id,
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.SetFocus,
|
||||
payload: '2',
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState).toBe(state);
|
||||
});
|
||||
|
||||
it('should add new group linkman into linkmans', () => {
|
||||
const state = {
|
||||
linkmans: {},
|
||||
} as State;
|
||||
const linkman = {
|
||||
_id: 'id',
|
||||
name: 'name',
|
||||
type: 'group',
|
||||
};
|
||||
const action = {
|
||||
type: ActionTypes.AddLinkman,
|
||||
payload: {
|
||||
linkman,
|
||||
focus: true,
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(Object.keys(newState.linkmans)).toHaveLength(1);
|
||||
expect(newState.focus).toBe(linkman._id);
|
||||
});
|
||||
|
||||
it('should add new friend linkman into linkmans', () => {
|
||||
const state = {
|
||||
linkmans: {},
|
||||
} as State;
|
||||
const linkman = {
|
||||
name: 'name',
|
||||
type: 'friend',
|
||||
from: '111',
|
||||
to: {
|
||||
_id: '222',
|
||||
},
|
||||
};
|
||||
const action = {
|
||||
type: ActionTypes.AddLinkman,
|
||||
payload: {
|
||||
linkman,
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(Object.keys(newState.linkmans)).toHaveLength(1);
|
||||
expect(newState.linkmans['111222']).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should add new temporary linkman into linkmans', () => {
|
||||
const state = {
|
||||
linkmans: {},
|
||||
} as State;
|
||||
const linkman = {
|
||||
_id: 'id',
|
||||
name: 'name',
|
||||
type: 'temporary',
|
||||
};
|
||||
const action = {
|
||||
type: ActionTypes.AddLinkman,
|
||||
payload: {
|
||||
linkman,
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(Object.keys(newState.linkmans)).toHaveLength(1);
|
||||
expect(newState.linkmans[linkman._id].unread).toBe(1);
|
||||
});
|
||||
|
||||
it('should return origin state when add unknown linkman', () => {
|
||||
const state = {
|
||||
linkmans: {},
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.AddLinkman,
|
||||
payload: {
|
||||
linkman: {
|
||||
type: 'xxx',
|
||||
},
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState).toBe(state);
|
||||
});
|
||||
|
||||
it('should remove linkman form linkmans', () => {
|
||||
const linkman1 = {
|
||||
_id: '1',
|
||||
};
|
||||
const linkman2 = {
|
||||
_id: '2',
|
||||
};
|
||||
const state = {
|
||||
linkmans: {
|
||||
[linkman1._id]: linkman1,
|
||||
[linkman2._id]: linkman2,
|
||||
},
|
||||
} as State;
|
||||
const action1 = {
|
||||
type: ActionTypes.RemoveLinkman,
|
||||
payload: linkman1._id,
|
||||
};
|
||||
const newState = reducer(state, action1);
|
||||
expect(Object.keys(newState.linkmans)).toHaveLength(1);
|
||||
expect(newState.focus).toBe(linkman2._id);
|
||||
|
||||
const action2 = {
|
||||
type: ActionTypes.RemoveLinkman,
|
||||
payload: linkman2._id,
|
||||
};
|
||||
expect(reducer(newState, action2).focus).toBe('');
|
||||
});
|
||||
|
||||
it('should add messages to linkmans', () => {
|
||||
const state = {
|
||||
linkmans: {
|
||||
1: {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {},
|
||||
},
|
||||
2: {
|
||||
_id: '2',
|
||||
name: 'name',
|
||||
messages: {},
|
||||
},
|
||||
},
|
||||
} as unknown as State;
|
||||
const action = {
|
||||
type: ActionTypes.SetLinkmansLastMessages,
|
||||
payload: {
|
||||
'1': {
|
||||
messages: [
|
||||
{
|
||||
_id: 'm1',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
},
|
||||
{
|
||||
_id: 'm2',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
},
|
||||
],
|
||||
unread: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(Object.keys(newState.linkmans['1'].messages).length).toBe(2);
|
||||
expect(Object.keys(newState.linkmans['2'].messages).length).toBe(0);
|
||||
});
|
||||
|
||||
it('should add messages to linkman', () => {
|
||||
const state = {
|
||||
linkmans: {
|
||||
1: {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {},
|
||||
},
|
||||
},
|
||||
} as unknown as State;
|
||||
const action = {
|
||||
type: ActionTypes.AddLinkmanHistoryMessages,
|
||||
payload: {
|
||||
linkmanId: '1',
|
||||
messages: [
|
||||
{
|
||||
_id: 'm1',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
},
|
||||
{
|
||||
_id: 'm2',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(Object.keys(newState.linkmans['1'].messages).length).toBe(2);
|
||||
});
|
||||
|
||||
it('should add message to linkman', () => {
|
||||
const linkman = {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {},
|
||||
unread: 0,
|
||||
};
|
||||
const state = {
|
||||
linkmans: {
|
||||
[linkman._id]: linkman,
|
||||
},
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.AddLinkmanMessage,
|
||||
payload: {
|
||||
linkmanId: '1',
|
||||
message: {
|
||||
_id: 'm1',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
},
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(Object.keys(newState.linkmans['1'].messages)).toHaveLength(1);
|
||||
expect(newState.linkmans['1'].unread).toBe(1);
|
||||
});
|
||||
|
||||
it('should not increase unread count when linkman is foucs', () => {
|
||||
const linkman = {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {},
|
||||
unread: 0,
|
||||
};
|
||||
const state = {
|
||||
linkmans: {
|
||||
[linkman._id]: linkman,
|
||||
},
|
||||
focus: linkman._id,
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.AddLinkmanMessage,
|
||||
payload: {
|
||||
linkmanId: '1',
|
||||
message: {
|
||||
_id: 'm1',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
},
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(Object.keys(newState.linkmans['1'].messages)).toHaveLength(1);
|
||||
expect(newState.linkmans['1'].unread).toBe(0);
|
||||
});
|
||||
|
||||
it('should remove message from linkman', () => {
|
||||
const state = {
|
||||
linkmans: {
|
||||
1: {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {
|
||||
m1: {
|
||||
_id: 'm1',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
from: {},
|
||||
},
|
||||
},
|
||||
unread: 0,
|
||||
},
|
||||
},
|
||||
} as unknown as State;
|
||||
const action = {
|
||||
type: ActionTypes.DeleteMessage,
|
||||
payload: {
|
||||
linkmanId: '1',
|
||||
messageId: 'm1',
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.linkmans['1'].messages.m1.deleted).toBe(true);
|
||||
});
|
||||
|
||||
it('should return origin state when delete not exists linkman message', () => {
|
||||
const state = {
|
||||
linkmans: {},
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.DeleteMessage,
|
||||
payload: {
|
||||
linkmanId: '1',
|
||||
messageId: 'm1',
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState).toBe(state);
|
||||
});
|
||||
|
||||
it('should update linkman property', () => {
|
||||
const state = {
|
||||
linkmans: {
|
||||
1: {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {},
|
||||
unread: 0,
|
||||
},
|
||||
},
|
||||
} as unknown as State;
|
||||
const action = {
|
||||
type: ActionTypes.SetLinkmanProperty,
|
||||
payload: {
|
||||
linkmanId: '1',
|
||||
key: 'name',
|
||||
value: 'new_name',
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.linkmans['1'].name).toBe('new_name');
|
||||
});
|
||||
|
||||
it('should update message from linkman', () => {
|
||||
const state = {
|
||||
linkmans: {
|
||||
1: {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {
|
||||
m1: {
|
||||
_id: 'm1',
|
||||
type: 'text',
|
||||
content: 'content',
|
||||
},
|
||||
},
|
||||
unread: 0,
|
||||
},
|
||||
},
|
||||
} as unknown as State;
|
||||
const action = {
|
||||
type: ActionTypes.UpdateMessage,
|
||||
payload: {
|
||||
linkmanId: '1',
|
||||
messageId: 'm1',
|
||||
value: {
|
||||
_id: 'm1',
|
||||
type: 'text',
|
||||
content: 'new_content',
|
||||
},
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.linkmans['1'].messages.m1.content).toBe('new_content');
|
||||
});
|
||||
|
||||
it('should add instead of update message when it not exists', () => {
|
||||
const linkman = {
|
||||
_id: '1',
|
||||
name: 'name',
|
||||
messages: {},
|
||||
unread: 0,
|
||||
};
|
||||
const state = {
|
||||
linkmans: {
|
||||
[linkman._id]: linkman,
|
||||
},
|
||||
} as State;
|
||||
const action = {
|
||||
type: ActionTypes.UpdateMessage,
|
||||
payload: {
|
||||
linkmanId: linkman._id,
|
||||
messageId: 'm1',
|
||||
value: {
|
||||
type: 'text',
|
||||
content: 'new_content',
|
||||
},
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.linkmans[linkman._id].messages.m1.content).toBe(
|
||||
'new_content',
|
||||
);
|
||||
});
|
||||
|
||||
it('should update status of key', () => {
|
||||
const state = {
|
||||
status: {
|
||||
aero: false,
|
||||
},
|
||||
} as unknown as State;
|
||||
const action = {
|
||||
type: ActionTypes.SetStatus,
|
||||
payload: {
|
||||
key: 'aero',
|
||||
value: true,
|
||||
},
|
||||
};
|
||||
const newState = reducer(state, action);
|
||||
expect(newState.status.aero).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user