fix(tests): Clean up after ReactTestUtils, wipe ComponentRegistry between specs

Summary:
Why does message-list have default participants? No other packages do

Component registry warns if mixin component name not found

Clear the component registry between tests and wipe React elements inserted into DOM

Everything should have a displayName, even you ComposerView

Stub all ComponentRegistry dependencies, always

Test Plan: Run all the tests at the same time

Reviewers: evan

Reviewed By: evan

Differential Revision: https://review.inboxapp.com/D1201
This commit is contained in:
Ben Gotow 2015-02-18 14:09:46 -08:00
parent b97f607a6e
commit 651f105740
9 changed files with 79 additions and 42 deletions

View file

@ -18,6 +18,7 @@ ParticipantsTextField = require './participants-text-field.cjsx'
# simulate the effect of the parent re-rendering us
module.exports =
ComposerView = React.createClass
displayName: 'ComposerView'
getInitialState: ->
state = @getComponentRegistryState()

View file

@ -29,7 +29,7 @@ textFieldStub = (className) ->
focus: ->
draftStoreProxyStub = (localId) ->
listen: -> # noop
listen: -> ->
draft: -> new Message()
changes:
add: ->

View file

@ -2,8 +2,6 @@ _ = require 'underscore-plus'
React = require 'react'
MessageItem = require "./message-item.cjsx"
ThreadParticipants = require "./thread-participants.cjsx"
{Actions, ThreadStore, MessageStore, ComponentRegistry} = require("inbox-exports")
module.exports =
@ -80,13 +78,9 @@ MessageList = React.createClass
<div className="message-list-headers">
<h2>{@state.current_thread.subject}</h2>
{if Participants?
<Participants clickable={true}
context={'primary'}
participants={@_threadParticipants()}/>
else
<ThreadParticipants thread_participants={@_threadParticipants()} />
}
<Participants clickable={true}
context={'primary'}
participants={@_threadParticipants()}/>
{for MessageListHeader in MessageListHeaders
<MessageListHeader thread={@state.current_thread} />

View file

@ -1,15 +0,0 @@
_ = require 'underscore-plus'
React = require "react"
module.exports =
ThreadParticipants = React.createClass
displayName: 'ThreadParticipants'
render: ->
<div className="participants thread-participants">
{@_formattedParticipants()}
</div>
_formattedParticipants: ->
contacts = @props.thread_participants ? []
_.map(contacts, (c) -> c.displayName()).join(", ")

View file

@ -16,6 +16,18 @@ TestUtils = React.addons.TestUtils
InboxTestUtils,
ComponentRegistry} = require "inbox-exports"
ComposerItem = React.createClass
render: -> <div></div>
focus: ->
AttachmentItem = React.createClass
render: -> <div></div>
focus: ->
ParticipantsItem = React.createClass
render: -> <div></div>
focus: ->
MessageItem = proxyquire("../lib/message-item.cjsx", {
"./email-frame": React.createClass({render: -> <div></div>})
})
@ -24,15 +36,7 @@ MessageList = proxyquire("../lib/message-list.cjsx", {
"./message-item.cjsx": MessageItem
})
ComposerItem = React.createClass
render: -> <div></div>
focus: ->
ComponentRegistry.register
name: 'Composer'
view: ComposerItem
MessageParticipants = require "../lib/message-participants.cjsx"
ThreadParticipants = require "../lib/thread-participants.cjsx"
me = new Namespace(
"name": "User One",
@ -175,14 +179,22 @@ test_thread = (new Thread).fromJSON({
})
describe "MessageList", ->
_resetMessageStore = ->
beforeEach ->
ComponentRegistry.register
name: 'Composer'
view: ComposerItem
ComponentRegistry.register
name: 'Participants'
view: ParticipantsItem
ComponentRegistry.register
name: 'AttachmentComponent'
view: AttachmentItem
MessageStore._items = []
MessageStore._threadId = null
spyOn(MessageStore, "itemLocalIds").andCallFake ->
{"666": "666"}
beforeEach ->
_resetMessageStore()
@message_list = TestUtils.renderIntoDocument(<MessageList />)
@message_list_node = @message_list.getDOMNode()
@ -218,7 +230,7 @@ describe "MessageList", ->
it "displays the thread participants on the page", ->
items = TestUtils.scryRenderedComponentsWithType(@message_list,
ThreadParticipants)
ParticipantsItem)
expect(items.length).toBe 1
it "focuses new composers when a draft is added", ->

View file

@ -11,7 +11,8 @@ ReactTestUtils = _.extend ReactTestUtils, require("jasmine-react-helpers")
ThreadStore,
DatabaseStore,
InboxTestUtils,
NamespaceStore} = require "inbox-exports"
NamespaceStore,
ComponentRegistry} = require "inbox-exports"
ThreadListColumn = require("../lib/thread-list-column")
@ -21,6 +22,9 @@ ThreadListNarrowItem = require("../lib/thread-list-narrow-item.cjsx")
ThreadListTabular = require("../lib/thread-list-tabular.cjsx")
ThreadListTabularItem = require("../lib/thread-list-tabular-item.cjsx")
ParticipantsItem = React.createClass
render: -> <div></div>
me = new Namespace(
"name": "User One",
"email": "user1@inboxapp.com"
@ -218,6 +222,10 @@ describe "ThreadListTabular", ->
ThreadStore._resetInstanceVars()
ComponentRegistry.register
name: 'Participants'
view: ParticipantsItem
@thread_list = ReactTestUtils.renderIntoDocument(
<ThreadListTabular />
)
@ -300,6 +308,10 @@ describe "ThreadListNarrow", ->
new Promise (resolve, reject) -> resolve(test_threads())
ThreadStore._resetInstanceVars()
ComponentRegistry.register
name: 'Participants'
view: ParticipantsItem
@thread_list = ReactTestUtils.renderIntoDocument(
<ThreadListNarrow />
)

View file

@ -3,7 +3,7 @@ Attributes = require '../../src/flux/attributes'
{isTempId} = require '../../src/flux/models/utils'
_ = require 'underscore-plus'
fdescribe "Model", ->
describe "Model", ->
describe "constructor", ->
it "should accept a hash of attributes and assign them to the new Model", ->
attrs =

View file

@ -21,6 +21,7 @@ clipboard = require 'clipboard'
NamespaceStore = require "../src/flux/stores/namespace-store"
Contact = require '../src/flux/models/contact'
{ComponentRegistry} = require "inbox-exports"
atom.themes.loadBaseStylesheets()
atom.themes.requireStylesheet '../static/jasmine'
@ -65,8 +66,35 @@ if specDirectory
isCoreSpec = specDirectory == fs.realpathSync(__dirname)
# Override React.addons.TestUtils.renderIntoDocument so that
# we can remove all the created elements after the test completes.
React = require "react/addons"
ReactTestUtils = React.addons.TestUtils
ReactTestUtils.scryRenderedDOMComponentsWithAttr = (root, attrName, attrValue) ->
ReactTestUtils.findAllInRenderedTree root, (inst) ->
inst.props[attrName] and (!attrValue or inst.props[attrName] is attrValue)
ReactTestUtils.findRenderedDOMComponentWithAttr = (root, attrName, attrValue) ->
all = ReactTestUtils.scryRenderedDOMComponentsWithAttr(root, attrName, attrValue)
if all.length is not 1
throw new Error("Did not find exactly one match for data attribute: #{attrName} with value: #{attrValue}")
all[0]
ReactElementContainers = []
ReactTestUtils.renderIntoDocument = (element) ->
container = document.createElement('div')
ReactElementContainers.push(container)
React.render(element, container)
ReactTestUtils.unmountAll = ->
for container in ReactElementContainers
React.unmountComponentAtNode(container)
ReactElementContainers = []
beforeEach ->
Grim.clearDeprecations() if isCoreSpec
ComponentRegistry._clear()
$.fx.off = true
documentTitle = null
atom.workspace = new Workspace()
@ -146,6 +174,8 @@ afterEach ->
$('#jasmine-content').empty() unless window.debugContent
ReactTestUtils.unmountAll()
jasmine.unspy(atom, 'saveSync')
ensureNoPathSubscriptions()
waits(0) # yield to ui thread to make screen update more frequently

View file

@ -16,17 +16,20 @@ getViewsByName = (components) ->
[registered, requested] = component.split " as "
requested ?= registered
state[requested] = ComponentRegistry.findViewByName registered
if not state[requested]?
console.log("""Warning: No component found for #{requested} in
#{@constructor.displayName}. Loaded: #{Object.keys(registry)}""")
state
Mixin =
getInitialState: ->
getViewsByName(@components)
getViewsByName.apply(@, [@components])
componentWillMount: ->
@_componentUnlistener = ComponentRegistry.listen (event) =>
@_componentUnlistener = ComponentRegistry.listen =>
@setState getViewsByName(@components)
componentDidUnmount: ->
componentWillUnmount: ->
@_componentUnlistener()
# Internal representation of components