mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-11-09 07:56:20 +08:00
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:
parent
b97f607a6e
commit
651f105740
9 changed files with 79 additions and 42 deletions
|
|
@ -18,6 +18,7 @@ ParticipantsTextField = require './participants-text-field.cjsx'
|
||||||
# simulate the effect of the parent re-rendering us
|
# simulate the effect of the parent re-rendering us
|
||||||
module.exports =
|
module.exports =
|
||||||
ComposerView = React.createClass
|
ComposerView = React.createClass
|
||||||
|
displayName: 'ComposerView'
|
||||||
|
|
||||||
getInitialState: ->
|
getInitialState: ->
|
||||||
state = @getComponentRegistryState()
|
state = @getComponentRegistryState()
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ textFieldStub = (className) ->
|
||||||
focus: ->
|
focus: ->
|
||||||
|
|
||||||
draftStoreProxyStub = (localId) ->
|
draftStoreProxyStub = (localId) ->
|
||||||
listen: -> # noop
|
listen: -> ->
|
||||||
draft: -> new Message()
|
draft: -> new Message()
|
||||||
changes:
|
changes:
|
||||||
add: ->
|
add: ->
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ _ = require 'underscore-plus'
|
||||||
React = require 'react'
|
React = require 'react'
|
||||||
MessageItem = require "./message-item.cjsx"
|
MessageItem = require "./message-item.cjsx"
|
||||||
|
|
||||||
ThreadParticipants = require "./thread-participants.cjsx"
|
|
||||||
|
|
||||||
{Actions, ThreadStore, MessageStore, ComponentRegistry} = require("inbox-exports")
|
{Actions, ThreadStore, MessageStore, ComponentRegistry} = require("inbox-exports")
|
||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
|
|
@ -80,13 +78,9 @@ MessageList = React.createClass
|
||||||
<div className="message-list-headers">
|
<div className="message-list-headers">
|
||||||
<h2>{@state.current_thread.subject}</h2>
|
<h2>{@state.current_thread.subject}</h2>
|
||||||
|
|
||||||
{if Participants?
|
|
||||||
<Participants clickable={true}
|
<Participants clickable={true}
|
||||||
context={'primary'}
|
context={'primary'}
|
||||||
participants={@_threadParticipants()}/>
|
participants={@_threadParticipants()}/>
|
||||||
else
|
|
||||||
<ThreadParticipants thread_participants={@_threadParticipants()} />
|
|
||||||
}
|
|
||||||
|
|
||||||
{for MessageListHeader in MessageListHeaders
|
{for MessageListHeader in MessageListHeaders
|
||||||
<MessageListHeader thread={@state.current_thread} />
|
<MessageListHeader thread={@state.current_thread} />
|
||||||
|
|
|
||||||
|
|
@ -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(", ")
|
|
||||||
|
|
@ -16,6 +16,18 @@ TestUtils = React.addons.TestUtils
|
||||||
InboxTestUtils,
|
InboxTestUtils,
|
||||||
ComponentRegistry} = require "inbox-exports"
|
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", {
|
MessageItem = proxyquire("../lib/message-item.cjsx", {
|
||||||
"./email-frame": React.createClass({render: -> <div></div>})
|
"./email-frame": React.createClass({render: -> <div></div>})
|
||||||
})
|
})
|
||||||
|
|
@ -24,15 +36,7 @@ MessageList = proxyquire("../lib/message-list.cjsx", {
|
||||||
"./message-item.cjsx": MessageItem
|
"./message-item.cjsx": MessageItem
|
||||||
})
|
})
|
||||||
|
|
||||||
ComposerItem = React.createClass
|
|
||||||
render: -> <div></div>
|
|
||||||
focus: ->
|
|
||||||
ComponentRegistry.register
|
|
||||||
name: 'Composer'
|
|
||||||
view: ComposerItem
|
|
||||||
|
|
||||||
MessageParticipants = require "../lib/message-participants.cjsx"
|
MessageParticipants = require "../lib/message-participants.cjsx"
|
||||||
ThreadParticipants = require "../lib/thread-participants.cjsx"
|
|
||||||
|
|
||||||
me = new Namespace(
|
me = new Namespace(
|
||||||
"name": "User One",
|
"name": "User One",
|
||||||
|
|
@ -175,14 +179,22 @@ test_thread = (new Thread).fromJSON({
|
||||||
})
|
})
|
||||||
|
|
||||||
describe "MessageList", ->
|
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._items = []
|
||||||
MessageStore._threadId = null
|
MessageStore._threadId = null
|
||||||
spyOn(MessageStore, "itemLocalIds").andCallFake ->
|
spyOn(MessageStore, "itemLocalIds").andCallFake ->
|
||||||
{"666": "666"}
|
{"666": "666"}
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
_resetMessageStore()
|
|
||||||
@message_list = TestUtils.renderIntoDocument(<MessageList />)
|
@message_list = TestUtils.renderIntoDocument(<MessageList />)
|
||||||
@message_list_node = @message_list.getDOMNode()
|
@message_list_node = @message_list.getDOMNode()
|
||||||
|
|
||||||
|
|
@ -218,7 +230,7 @@ describe "MessageList", ->
|
||||||
|
|
||||||
it "displays the thread participants on the page", ->
|
it "displays the thread participants on the page", ->
|
||||||
items = TestUtils.scryRenderedComponentsWithType(@message_list,
|
items = TestUtils.scryRenderedComponentsWithType(@message_list,
|
||||||
ThreadParticipants)
|
ParticipantsItem)
|
||||||
expect(items.length).toBe 1
|
expect(items.length).toBe 1
|
||||||
|
|
||||||
it "focuses new composers when a draft is added", ->
|
it "focuses new composers when a draft is added", ->
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ ReactTestUtils = _.extend ReactTestUtils, require("jasmine-react-helpers")
|
||||||
ThreadStore,
|
ThreadStore,
|
||||||
DatabaseStore,
|
DatabaseStore,
|
||||||
InboxTestUtils,
|
InboxTestUtils,
|
||||||
NamespaceStore} = require "inbox-exports"
|
NamespaceStore,
|
||||||
|
ComponentRegistry} = require "inbox-exports"
|
||||||
|
|
||||||
ThreadListColumn = require("../lib/thread-list-column")
|
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")
|
ThreadListTabular = require("../lib/thread-list-tabular.cjsx")
|
||||||
ThreadListTabularItem = require("../lib/thread-list-tabular-item.cjsx")
|
ThreadListTabularItem = require("../lib/thread-list-tabular-item.cjsx")
|
||||||
|
|
||||||
|
ParticipantsItem = React.createClass
|
||||||
|
render: -> <div></div>
|
||||||
|
|
||||||
me = new Namespace(
|
me = new Namespace(
|
||||||
"name": "User One",
|
"name": "User One",
|
||||||
"email": "user1@inboxapp.com"
|
"email": "user1@inboxapp.com"
|
||||||
|
|
@ -218,6 +222,10 @@ describe "ThreadListTabular", ->
|
||||||
|
|
||||||
ThreadStore._resetInstanceVars()
|
ThreadStore._resetInstanceVars()
|
||||||
|
|
||||||
|
ComponentRegistry.register
|
||||||
|
name: 'Participants'
|
||||||
|
view: ParticipantsItem
|
||||||
|
|
||||||
@thread_list = ReactTestUtils.renderIntoDocument(
|
@thread_list = ReactTestUtils.renderIntoDocument(
|
||||||
<ThreadListTabular />
|
<ThreadListTabular />
|
||||||
)
|
)
|
||||||
|
|
@ -300,6 +308,10 @@ describe "ThreadListNarrow", ->
|
||||||
new Promise (resolve, reject) -> resolve(test_threads())
|
new Promise (resolve, reject) -> resolve(test_threads())
|
||||||
ThreadStore._resetInstanceVars()
|
ThreadStore._resetInstanceVars()
|
||||||
|
|
||||||
|
ComponentRegistry.register
|
||||||
|
name: 'Participants'
|
||||||
|
view: ParticipantsItem
|
||||||
|
|
||||||
@thread_list = ReactTestUtils.renderIntoDocument(
|
@thread_list = ReactTestUtils.renderIntoDocument(
|
||||||
<ThreadListNarrow />
|
<ThreadListNarrow />
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ Attributes = require '../../src/flux/attributes'
|
||||||
{isTempId} = require '../../src/flux/models/utils'
|
{isTempId} = require '../../src/flux/models/utils'
|
||||||
_ = require 'underscore-plus'
|
_ = require 'underscore-plus'
|
||||||
|
|
||||||
fdescribe "Model", ->
|
describe "Model", ->
|
||||||
describe "constructor", ->
|
describe "constructor", ->
|
||||||
it "should accept a hash of attributes and assign them to the new Model", ->
|
it "should accept a hash of attributes and assign them to the new Model", ->
|
||||||
attrs =
|
attrs =
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ clipboard = require 'clipboard'
|
||||||
|
|
||||||
NamespaceStore = require "../src/flux/stores/namespace-store"
|
NamespaceStore = require "../src/flux/stores/namespace-store"
|
||||||
Contact = require '../src/flux/models/contact'
|
Contact = require '../src/flux/models/contact'
|
||||||
|
{ComponentRegistry} = require "inbox-exports"
|
||||||
|
|
||||||
atom.themes.loadBaseStylesheets()
|
atom.themes.loadBaseStylesheets()
|
||||||
atom.themes.requireStylesheet '../static/jasmine'
|
atom.themes.requireStylesheet '../static/jasmine'
|
||||||
|
|
@ -65,8 +66,35 @@ if specDirectory
|
||||||
|
|
||||||
isCoreSpec = specDirectory == fs.realpathSync(__dirname)
|
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 ->
|
beforeEach ->
|
||||||
Grim.clearDeprecations() if isCoreSpec
|
Grim.clearDeprecations() if isCoreSpec
|
||||||
|
ComponentRegistry._clear()
|
||||||
|
|
||||||
$.fx.off = true
|
$.fx.off = true
|
||||||
documentTitle = null
|
documentTitle = null
|
||||||
atom.workspace = new Workspace()
|
atom.workspace = new Workspace()
|
||||||
|
|
@ -146,6 +174,8 @@ afterEach ->
|
||||||
|
|
||||||
$('#jasmine-content').empty() unless window.debugContent
|
$('#jasmine-content').empty() unless window.debugContent
|
||||||
|
|
||||||
|
ReactTestUtils.unmountAll()
|
||||||
|
|
||||||
jasmine.unspy(atom, 'saveSync')
|
jasmine.unspy(atom, 'saveSync')
|
||||||
ensureNoPathSubscriptions()
|
ensureNoPathSubscriptions()
|
||||||
waits(0) # yield to ui thread to make screen update more frequently
|
waits(0) # yield to ui thread to make screen update more frequently
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,20 @@ getViewsByName = (components) ->
|
||||||
[registered, requested] = component.split " as "
|
[registered, requested] = component.split " as "
|
||||||
requested ?= registered
|
requested ?= registered
|
||||||
state[requested] = ComponentRegistry.findViewByName 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
|
state
|
||||||
|
|
||||||
Mixin =
|
Mixin =
|
||||||
getInitialState: ->
|
getInitialState: ->
|
||||||
getViewsByName(@components)
|
getViewsByName.apply(@, [@components])
|
||||||
|
|
||||||
componentWillMount: ->
|
componentWillMount: ->
|
||||||
@_componentUnlistener = ComponentRegistry.listen (event) =>
|
@_componentUnlistener = ComponentRegistry.listen =>
|
||||||
@setState getViewsByName(@components)
|
@setState getViewsByName(@components)
|
||||||
|
|
||||||
componentDidUnmount: ->
|
componentWillUnmount: ->
|
||||||
@_componentUnlistener()
|
@_componentUnlistener()
|
||||||
|
|
||||||
# Internal representation of components
|
# Internal representation of components
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue