Skip to content

Commit

Permalink
feat(reply): Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingze Xiao committed May 13, 2020
1 parent 1d7e145 commit 6c0ef80
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 7 deletions.
7 changes: 7 additions & 0 deletions src/components/Popups/ReplyField/ItemRow.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import '~box-ui-elements/es/styles/variables';

.ba-DefaultItemRow-email {
color: $bdl-gray-62;
font-size: 11px;
line-height: 13px;
}
31 changes: 31 additions & 0 deletions src/components/Popups/ReplyField/ItemRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import DatalistItem from 'box-ui-elements/es/components/datalist-item';
import { UserMini, GroupMini } from '../../../@types';
import './ItemRow.scss';

export type Props = {
id?: string;
item?: UserMini | GroupMini;
name?: string;
};

const DefaultItemRow = ({ item, ...rest }: Props): JSX.Element | null => {
if (!item || !item.name) {
return null;
}

return (
<DatalistItem {...rest}>
<div className="ba-DefaultItemRow-name" data-testid="ba-DefaultItemRow-name">
{item.name}
</div>
{'email' in item && (
<div className="ba-DefaultItemRow-email" data-testid="ba-DefaultItemRow-email">
{item.email}
</div>
)}
</DatalistItem>
);
};

export default DefaultItemRow;
50 changes: 50 additions & 0 deletions src/components/Popups/ReplyField/__tests__/ItemRow-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import DatalistItem from 'box-ui-elements/es/components/datalist-item';
import ItemRow, { Props } from '../ItemRow';

describe('components/Popups/ReplyField/DefaultItemRow', () => {
const defaults: Props = {
id: 'testid',
item: { email: '[email protected]', id: 'testid', name: 'testname', type: 'user' },
name: 'testname',
};

const getWrapper = (props = {}): ShallowWrapper => shallow(<ItemRow {...defaults} {...props} />);

describe('render()', () => {
test('should render DatalistItem with correct props', () => {
const wrapper = getWrapper();

expect(wrapper.find(DatalistItem).props()).toMatchObject({
id: 'testid',
name: 'testname',
});
});

test('should not render anything if no item', () => {
const wrapper = getWrapper({ item: null });

expect(wrapper.find(DatalistItem).exists()).toBeFalsy();
});

test('should not render anything if no item name', () => {
const wrapper = getWrapper({ item: {} });

expect(wrapper.find(DatalistItem).exists()).toBeFalsy();
});

test('should render item name and email', () => {
const wrapper = getWrapper();

expect(wrapper.find('[data-testid="ba-DefaultItemRow-name"]').text()).toBe('testname');
expect(wrapper.find('[data-testid="ba-DefaultItemRow-email"]').text()).toBe('[email protected]');
});

test('should not render email if item has no email', () => {
const wrapper = getWrapper({ item: { id: 'testid', name: 'testname', type: 'group' } });

expect(wrapper.find('[data-testid="ba-DefaultItemRow-email"]').exists()).toBeFalsy();
});
});
});
239 changes: 232 additions & 7 deletions src/components/Popups/ReplyField/__tests__/ReplyField-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { shallow, ShallowWrapper } from 'enzyme';
import { Editor, EditorState } from 'draft-js';
import PopupList from '../PopupList';
import ReplyField, { Props, State } from '../ReplyField';
import { VirtualElement } from '../../Popper';
import { State as PopperState, VirtualElement } from '../../Popper';

const mockMention = {
blockID: '12345',
Expand All @@ -13,14 +13,23 @@ const mockMention = {
start: 0,
};

const mockEditorState = ({
getCurrentContent: () => ({ getPlainText: () => 'test' }),
getSelection: () => ({ getFocusOffset: () => 0 }),
} as unknown) as EditorState;

jest.mock('box-ui-elements/es/components/form-elements/draft-js-mention-selector', () => ({
getActiveMentionForEditorState: () => mockMention,
addMention: () => mockEditorState,
}));

describe('components/Popups/ReplyField', () => {
const defaults: Props = {
className: 'ba-Popup-field',
collaborators: [],
collaborators: [
{ id: 'testid1', name: 'test1' },
{ id: 'testid2', name: 'test2' },
],
cursorPosition: 0,
isDisabled: false,
onChange: jest.fn(),
Expand All @@ -32,11 +41,6 @@ describe('components/Popups/ReplyField', () => {
const getWrapper = (props = {}): ShallowWrapper<Props, State, ReplyField> =>
shallow(<ReplyField {...defaults} {...props} />);

const mockEditorState = ({
getCurrentContent: () => ({ getPlainText: () => 'test' }),
getSelection: () => ({ getFocusOffset: () => 0 }),
} as unknown) as EditorState;

describe('render()', () => {
test('should render the editor with right props', () => {
const wrapper = getWrapper();
Expand Down Expand Up @@ -76,6 +80,79 @@ describe('components/Popups/ReplyField', () => {
});
});

describe('getCollaborators()', () => {
test('should return empty list if no activeMention', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();

expect(instance.getCollaborators(null)).toHaveLength(0);
});

test('should return full collaborators list if mentionString length is less than 2', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();

const mockMentionShort = {
blockID: 'testid',
end: 1,
mentionString: '',
mentionTrigger: '@',
start: 0,
};

expect(instance.getCollaborators(mockMentionShort)).toMatchObject(defaults.collaborators);
});

test('should filter invalid items in collaborators', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();

expect(instance.getCollaborators(mockMention)).toHaveLength(0);
});

test('should filter items based on item name', () => {
const mockCollabs = [
{ id: 'testid1', name: 'test1', item: { id: 'testid1', name: 'test1', type: 'user' } },
{ id: 'testid2', name: 'test2', item: { id: 'testid2', name: 'test2', type: 'user' } },
];
const mockMention2 = {
blockID: 'testid',
end: 6,
mentionString: 'test2',
mentionTrigger: '@',
start: 0,
};

const wrapper = getWrapper({ collaborators: mockCollabs });
const instance = wrapper.instance();

expect(instance.getCollaborators(mockMention2)).toMatchObject([mockCollabs[1]]);
});

test('should filter items based on item name', () => {
const mockCollabs = [
{ id: 'testid1', name: 'test1', item: { id: 'testid1', name: 'test1', type: 'group' } },
{
id: 'testid2',
name: 'test2',
item: { id: 'testid2', name: 'test2', type: 'group', email: '[email protected]' },
},
];
const mockMention2 = {
blockID: 'testid',
end: 8,
mentionString: 'box.com',
mentionTrigger: '@',
start: 0,
};

const wrapper = getWrapper({ collaborators: mockCollabs });
const instance = wrapper.instance();

expect(instance.getCollaborators(mockMention2)).toMatchObject([mockCollabs[1]]);
});
});

describe('getVirtualElement()', () => {
let getSelectionSpy: jest.SpyInstance<Selection | null>;

Expand Down Expand Up @@ -136,6 +213,54 @@ describe('components/Popups/ReplyField', () => {
});
});

describe('updatePopupReference()', () => {
test('should call getVirtualElement and set state', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();

const getVirtualElementSpy = jest
.spyOn(instance, 'getVirtualElement')
.mockReturnValueOnce(('virtualElement' as unknown) as VirtualElement);
instance.updatePopupReference();

expect(getVirtualElementSpy).toBeCalledWith(mockMention);
expect(wrapper.state('popupReference')).toBe('virtualElement');
});
});

describe('handleFirstUpdate()', () => {
test('should call updatePopupReference if coords are nagitive', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();

const mockPopperState = {
rects: {
reference: {
x: -100,
y: -200,
},
},
} as Partial<PopperState>;
const updatePopupReferenceSpy = jest.spyOn(instance, 'updatePopupReference');

instance.handleFirstUpdate(mockPopperState);

expect(updatePopupReferenceSpy).toBeCalled();
});
});

describe('handleSelect()', () => {
test('should call handle Change with updated editorState', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();

const handleChangeSpy = jest.spyOn(instance, 'handleChange');
instance.handleSelect(0);

expect(handleChangeSpy).toBeCalledWith(mockEditorState);
});
});

describe('focusEditor()', () => {
test('should call editor ref focus', () => {
const wrapper = getWrapper();
Expand All @@ -162,4 +287,104 @@ describe('components/Popups/ReplyField', () => {
expect(defaults.setCursorPosition).toBeCalledWith(0);
});
});

describe('stopDefaultEvent()', () => {
test('should prevent default and stop propagation', () => {
const mockEvent = ({
preventDefault: jest.fn(),
stopPropagation: jest.fn(),
} as unknown) as React.SyntheticEvent;

const wrapper = getWrapper();
wrapper.instance().stopDefaultEvent(mockEvent);

expect(mockEvent.preventDefault).toBeCalled();
expect(mockEvent.stopPropagation).toBeCalled();
});
});

describe('setPopupListActiveItem()', () => {
const wrapper = getWrapper();
wrapper.instance().setPopupListActiveItem(1);

expect(wrapper.state('activeItemIndex')).toBe(1);
});

describe('handleKeyDown()', () => {
let mockKeyboardEvent: React.KeyboardEvent<HTMLDivElement>;
let wrapper: ShallowWrapper<Props, State, ReplyField>;

beforeEach(() => {
mockKeyboardEvent = ({
key: 'ArrowDown',
preventDefault: jest.fn(),
stopPropagation: jest.fn(),
} as unknown) as React.KeyboardEvent<HTMLDivElement>;
wrapper = getWrapper();
wrapper.setState({ activeItemIndex: 0, popupReference: ('popupReference' as unknown) as VirtualElement });
});
// const wrapper = getWrapper();
// const instance = wrapper.instance();

// const getCollaboratorsSpy = jest.spyOn(instance, 'getCollaborators');
// const stopDefaultEventSpy = jest.spyOn(instance, 'stopDefaultEvent');
// const setActiveItemSpy = jest.spyOn(instance, 'setPopupListActiveItem');

test('should return not-handled if popup is not showing', () => {
wrapper.setState({ popupReference: null });
const instance = wrapper.instance();

expect(instance.handleKeyDown(mockKeyboardEvent)).toEqual('not-handled');
});

test('should return not-handled if key is not down, up, or enter', () => {
const instance = wrapper.instance();
mockKeyboardEvent.key = '';

expect(instance.handleKeyDown(mockKeyboardEvent)).toEqual('not-handled');
});

test('should return not-handled if collaborators length is 0', () => {
const instance = wrapper.instance();
jest.spyOn(instance, 'getCollaborators').mockReturnValueOnce([]);

expect(instance.handleKeyDown(mockKeyboardEvent)).toEqual('not-handled');
});

test('should return handled if key is enter and reset active item', () => {
const instance = wrapper.instance();
const setActiveItemSpy = jest.spyOn(instance, 'setPopupListActiveItem');
mockKeyboardEvent.key = 'Enter';

expect(instance.handleKeyDown(mockKeyboardEvent)).toEqual('handled');
expect(setActiveItemSpy).toBeCalledWith(0);
});

test('should increase index if key is down', () => {
const instance = wrapper.instance();
const setActiveItemSpy = jest.spyOn(instance, 'setPopupListActiveItem');
jest.spyOn(instance, 'getCollaborators').mockReturnValueOnce([
{ id: 'testid1', name: 'test1' },
{ id: 'testid2', name: 'test2' },
]);

instance.handleKeyDown(mockKeyboardEvent);
expect(setActiveItemSpy).toBeCalledWith(1);
});

test('should increase index if key is down', () => {
wrapper.setState({ activeItemIndex: 1 });
const instance = wrapper.instance();

const setActiveItemSpy = jest.spyOn(instance, 'setPopupListActiveItem');
jest.spyOn(instance, 'getCollaborators').mockReturnValueOnce([
{ id: 'testid1', name: 'test1' },
{ id: 'testid2', name: 'test2' },
]);
mockKeyboardEvent.key = 'ArrowUp';

instance.handleKeyDown(mockKeyboardEvent);
expect(setActiveItemSpy).toBeCalledWith(0);
});
});
});

0 comments on commit 6c0ef80

Please sign in to comment.