-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Mingze Xiao
committed
May 13, 2020
1 parent
1d7e145
commit 6c0ef80
Showing
4 changed files
with
320 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
50
src/components/Popups/ReplyField/__tests__/ItemRow-test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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', | ||
|
@@ -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(), | ||
|
@@ -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(); | ||
|
@@ -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>; | ||
|
||
|
@@ -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(); | ||
|
@@ -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); | ||
}); | ||
}); | ||
}); |