_ = require 'underscore-plus'
CSON = require 'season'
React = require 'react/addons'
ReactTestUtils = React.addons.TestUtils
ComposerParticipants = require '../lib/composer-participants.cjsx'
ComposerParticipant = require '../lib/composer-participant.cjsx'
{InboxTestUtils,
Namespace,
NamespaceStore,
Contact,
ContactStore,
} = require 'inbox-exports'
me = new Namespace
name: 'Test User'
email: 'test@example.com'
provider: 'inbox'
NamespaceStore._current = me
participant1 = new Contact
email: 'zip@inboxapp.com'
participant2 = new Contact
email: 'zip@example.com'
name: 'zip'
participant3 = new Contact
email: 'zip@inboxapp.com'
name: 'Duplicate email'
participant4 = new Contact
email: 'zip@elsewhere.com',
name: 'zip again'
default_participants = [participant1, participant2]
all_participants = [participant1, participant2, participant3, participant4]
describe 'Autocomplete', ->
keymap_path = 'internal_packages/composer/keymaps/composer.cson'
keymap_file = CSON.readFileSync keymap_path
# We have to add these manually for testing
beforeEach ->
@onAdd = jasmine.createSpy 'add'
@onRemove = jasmine.createSpy 'remove'
@participants = ReactTestUtils.renderIntoDocument(
)
@renderedParticipants = ReactTestUtils.scryRenderedComponentsWithType @participants, ComposerParticipant
it 'renders into the document', ->
expect(ReactTestUtils.isCompositeComponentWithType @participants, ComposerParticipants).toBe true
it 'shows the participants by default', ->
expect(@renderedParticipants.length).toBe(2)
it 'should render the participants specified', ->
expect(@renderedParticipants[0].props.participant).toEqual participant1
expect(@renderedParticipants[1].props.participant).toEqual participant2
it 'fires onRemove with a participant when the "x" is clicked', ->
button = @renderedParticipants[0].getDOMNode().querySelector('i')
expect(button).toBeDefined()
ReactTestUtils.Simulate.click(button)
expect(@onRemove).toHaveBeenCalledWith(participant1)
it 'should have one element with a "hasName" class', ->
hasname = ReactTestUtils.scryRenderedDOMComponentsWithClass(@participants, 'hasName')
expect(hasname.length).toBe(1)
describe 'the input', ->
beforeEach ->
atom.keymaps.add keymap_path, keymap_file
@input = @participants.refs.autocomplete.getDOMNode()
it 'should remove the last participant when "backspace" is pressed', ->
@input.focus()
ReactTestUtils.Simulate.focus(@input)
InboxTestUtils.keyPress 'backspace', @input
expect(@onRemove).toHaveBeenCalledWith(participant2)
it 'should not call @onRemove with no participants', ->
onRemove = jasmine.createSpy 'remove'
participants = ReactTestUtils.renderIntoDocument(
)
input = participants.refs.autocomplete.getDOMNode()
InboxTestUtils.keyPress 'backspace', input
expect(onRemove).not.toHaveBeenCalled()
it 'should not bring up an autocomplete box for no input', ->
spyOn(ContactStore, 'searchContacts')
ReactTestUtils.Simulate.focus(@input)
expect(ContactStore.searchContacts).not.toHaveBeenCalled()
completions = ReactTestUtils.findRenderedDOMComponentWithClass(@participants, 'completions')
expect(completions.getDOMNode().style.display).toBe 'none'
it 'should do nothing on "tab"', ->
spyOn(@participants, "_addParticipant").andCallThrough()
InboxTestUtils.keyPress('tab', @input)
expect(@participants._addParticipant).not.toHaveBeenCalled()
it 'should do nothing on "blur"', ->
spyOn(@participants, "_addParticipant").andCallThrough()
@input.focus()
ReactTestUtils.Simulate.focus(@input)
@input.blur()
ReactTestUtils.Simulate.blur(@input)
expect(@participants._addParticipant).not.toHaveBeenCalled()
it 'should remove the last participant when "backspace" is pressed', ->
@input.focus()
ReactTestUtils.Simulate.focus(@input)
InboxTestUtils.keyPress 'backspace', @input
expect(@onRemove).toHaveBeenCalledWith(participant2)
it 'should do nothing when escape is pushed', ->
spyOn(@participants, "_addParticipant").andCallThrough()
@input.focus()
ReactTestUtils.Simulate.focus(@input)
InboxTestUtils.keyPress('escape', @input)
expect(@participants._addParticipant).not.toHaveBeenCalled()
describe 'when typing an email with no suggestions', ->
beforeEach ->
spyOn(@participants, "_addParticipant").andCallThrough()
@input.focus()
ReactTestUtils.Simulate.focus(@input)
@input.value = participant4.email
ReactTestUtils.Simulate.change(@input)
it 'has the right class', ->
nodes = ReactTestUtils.scryRenderedDOMComponentsWithClass(@participants, "autocomplete-no-suggestions")
expect(nodes.length).toBe 1
it 'should complete on "tab"', ->
InboxTestUtils.keyPress('tab', @input)
addedEmail = @participants._addParticipant.calls[0].args[0].email
expect(addedEmail).toEqual participant4.email
expect(@participants.state.currentEmail).toBe ''
it 'should complete on "enter"', ->
InboxTestUtils.keyPress('enter', @input)
addedEmail = @participants._addParticipant.calls[0].args[0].email
expect(addedEmail).toEqual participant4.email
expect(@participants.state.currentEmail).toBe ''
it 'should complete on "comma"', ->
InboxTestUtils.keyPress(',', @input)
addedEmail = @participants._addParticipant.calls[0].args[0].email
expect(addedEmail).toEqual participant4.email
expect(@participants.state.currentEmail).toBe ''
it 'should complete on "space"', ->
InboxTestUtils.keyPress('space', @input)
addedEmail = @participants._addParticipant.calls[0].args[0].email
expect(addedEmail).toEqual participant4.email
expect(@participants.state.currentEmail).toBe ''
it 'should complete on "blur"', ->
@input.blur()
ReactTestUtils.Simulate.blur(@input)
addedEmail = @participants._addParticipant.calls[0].args[0].email
expect(addedEmail).toEqual participant4.email
expect(@participants.state.currentEmail).toBe ''
it 'should clear the suggestion without adding when escape is pushed', ->
InboxTestUtils.keyPress('escape', @input)
expect(@participants._addParticipant).not.toHaveBeenCalled()
expect(@participants.state.currentEmail).toBe ''
describe 'when typing a name with no suggestions', ->
beforeEach ->
spyOn(@participants, "_addParticipant").andCallThrough()
@input.focus()
ReactTestUtils.Simulate.focus(@input)
@input.value = "Foobar"
ReactTestUtils.Simulate.change(@input)
it 'should NOT complete on "space"', ->
InboxTestUtils.keyPress('space', @input)
expect(@participants._addParticipant).not.toHaveBeenCalled()
it 'should do nothing on "blur"', ->
@input.focus()
ReactTestUtils.Simulate.focus(@input)
@input.blur()
ReactTestUtils.Simulate.blur(@input)
expect(@participants._addParticipant).not.toHaveBeenCalled()
describe 'in autocomplete mode', ->
beforeEach ->
spyOn(ContactStore, 'searchContacts').andReturn(all_participants)
spyOn(@participants, "_addParticipant").andCallThrough()
@input.focus()
ReactTestUtils.Simulate.focus(@input)
@input.value = 'z'
ReactTestUtils.Simulate.change(@input)
@completions = ReactTestUtils.findRenderedDOMComponentWithClass(@participants, 'completions')
it 'should clear the suggestion without adding when escape is pushed', ->
InboxTestUtils.keyPress('escape', @input)
expect(@participants._addParticipant).not.toHaveBeenCalled()
expect(@participants.state.currentEmail).toBe ''
it 'should query the contact store for input', ->
expect(ContactStore.searchContacts).toHaveBeenCalledWith('z')
it 'should show the completions field', ->
expect(@completions.getDOMNode().style.display).toBe 'initial'
expect(ReactTestUtils.scryRenderedComponentsWithType(@completions, ComposerParticipant).length).toBe all_participants.length
it 'should hide the completions field on blur', ->
@input.blur()
ReactTestUtils.Simulate.blur(@input)
expect(@completions.getDOMNode().style.display).toBe 'none'
expect(ReactTestUtils.scryRenderedComponentsWithType(@completions, ComposerParticipant).length).toBe all_participants.length
expect(@participants.state.selectedIndex).toBe 0
it 'should not fire when clicking an existing email in its field', ->
ReactTestUtils.Simulate.mouseUp(@completions.getDOMNode().querySelectorAll('li')[0])
expect(@onAdd).not.toHaveBeenCalled()
it 'should fire for a new email address which has been clicked', ->
ReactTestUtils.Simulate.mouseUp(@completions.getDOMNode().querySelectorAll('li')[3])
expect(@onAdd).toHaveBeenCalledWith(participant4)
it 'should start with an index of 0', ->
expect(@participants.state.selectedIndex).toEqual 1
it 'should increment the index when "down" is pressed', ->
InboxTestUtils.keyPress 'down', @input
expect(@participants.state.selectedIndex).toEqual 2
it 'should decrement the index and wrap when "up" is pressed', ->
InboxTestUtils.keyPress 'up', @input
expect(@participants.state.selectedIndex).toEqual all_participants.length
it 'should wrap when the end is reached', ->
InboxTestUtils.keyPress 'down', @input
InboxTestUtils.keyPress 'down', @input
InboxTestUtils.keyPress 'down', @input
InboxTestUtils.keyPress 'down', @input
expect(@participants.state.selectedIndex).toEqual 1
it 'should be able to select the last one', ->
InboxTestUtils.keyPress 'down', @input
InboxTestUtils.keyPress 'down', @input
InboxTestUtils.keyPress 'down', @input
expect(@participants.state.selectedIndex).toEqual 4
it 'should select an item underneath the selectedIndex with "enter"', ->
InboxTestUtils.keyPress 'up', @input
InboxTestUtils.keyPress 'enter', @input
expect(@onAdd).toHaveBeenCalledWith participant4
it 'should select an item underneath the selectedIndex with "comma"', ->
InboxTestUtils.keyPress 'up', @input
InboxTestUtils.keyPress ',', @input
expect(@onAdd).toHaveBeenCalledWith participant4
it 'should select an item underneath the selectedIndex with "tab"', ->
InboxTestUtils.keyPress 'up', @input
InboxTestUtils.keyPress 'tab', @input
expect(@onAdd).toHaveBeenCalledWith participant4
it 'should select an index using the mouse', ->
ReactTestUtils.Simulate.mouseOver(@completions.getDOMNode().querySelectorAll('li')[3])
expect(@participants.state.selectedIndex).toEqual 4
it 'should add a "seen" class to seen participants', ->
InboxTestUtils.keyPress 'down', @input
hovered = ReactTestUtils.scryRenderedDOMComponentsWithClass(@participants, "hover")
expect(hovered.length).toEqual 1
participant = ReactTestUtils.scryRenderedComponentsWithType(hovered[0], ComposerParticipant)
expect(participant?[0].props?.participant).toEqual participant2
it 'should work if two are in the same document', ->
onAdd = jasmine.createSpy 'add'
nevercalled = jasmine.createSpy 'nevercalled'
participants = ReactTestUtils.renderIntoDocument(
)
first = ReactTestUtils.scryRenderedComponentsWithType(participants, ComposerParticipants)[0]
spyOn(ContactStore, 'searchContacts').andReturn(all_participants)
atom.keymaps.add keymap_path, keymap_file
input = first.refs.autocomplete.getDOMNode()
input.focus()
ReactTestUtils.Simulate.focus(input)
input.value = 'z'
ReactTestUtils.Simulate.change(input)
InboxTestUtils.keyPress 'up', input
InboxTestUtils.keyPress 'enter', input
expect(onAdd).toHaveBeenCalledWith participant4
expect(nevercalled).not.toHaveBeenCalled()