Mailspring/internal_packages/composer/spec/quoted-text-spec.cjsx

151 lines
6.1 KiB
Plaintext
Raw Normal View History

2015-03-06 08:00:56 +08:00
# This tests just quoted text within a contenteditable.
#
# For a test of the basic component itself see
# contenteditable-component-spec.cjsx
#
_ = require "underscore"
2015-03-06 08:00:56 +08:00
React = require "react/addons"
ReactTestUtils = React.addons.TestUtils
Fields = require '../lib/fields'
Composer = require "../lib/composer-view"
feat(editor-region): Add support to register components as editors Summary: - The main purpose of this is to be able to properly register the editor for the markdown plugin (and any other plugins to come) - Refactors ComposerView and Contenteditable -> - Replaces Contenteditable with an InjectedComponent for a new region role: "Composer:Editor" - Creates a new component called ComposerEditor, which is the one that is being registered by default as "Composer:Editor" - I used this class to try to standardize the props that should be passed to any would be editor Component: - Renamed a bunch of the props which (I think) had a bit of confusing names - Added a bunch of docs for these in the source file, although I feel like those docs should live elsewhere, like in the ComponentRegion docs. - In the process, I ended up pulling some stuff out of ComposerView and some stuff out of the Contenteditable, namely: - The scrolling logic to ensure that the composer is visible while typing was moved outside of the Contenteditable -- this feels more like the ComposerEditor's responsibility, especially since the Contenteditable is meant to be used in other contexts as well. - The ComposerExtensions state; it feels less awkward for me if this is inside the ComposerEditor because 1) ComposerView does less things, 2) these are actually just being passed to the Contenteditable, 3) I feel like other plugins shouldn't need to mess around with ComposerExtensions, so we shouldn't pass them to the editor. If you register an editor different from our default one, any other ComposerExtension callbacks will be disabled, which I feel is expected behavior. - I think there is still some more refactoring to be done, and I left some TODOS here and there, but I think this diff is already big enough and its a minimal set of changes to get the markdown editor working in a not so duck tapish way. - New props for InjectedComponent: - `requiredMethods`: allows you to define a collection of methods that should be implemented by any Component that registers for your desired region. - It will throw an error if these are not implemented - It will automatically pass calls made on the InjectedComponent to these methods down to the instance of the actual registered component - Would love some comments on this approach and impl - `fallback`: allows you to define a default component to use if none were registered through the ComponentRegistry - Misc: - Added a new test case for the QuotedHTMLTransformer - Tests: - They were minimally updated so that they don't break, but a big TODO is to properly refactor them. I plan to do that in an upcoming diff. Test Plan: - Unit tests Reviewers: bengotow, evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D2372
2015-12-19 03:03:58 +08:00
ComposerEditor = require '../lib/composer-editor'
{DraftStore, ComponentRegistry} = require 'nylas-exports'
2015-03-06 08:00:56 +08:00
describe "Composer Quoted Text", ->
2015-03-06 08:00:56 +08:00
beforeEach ->
feat(editor-region): Add support to register components as editors Summary: - The main purpose of this is to be able to properly register the editor for the markdown plugin (and any other plugins to come) - Refactors ComposerView and Contenteditable -> - Replaces Contenteditable with an InjectedComponent for a new region role: "Composer:Editor" - Creates a new component called ComposerEditor, which is the one that is being registered by default as "Composer:Editor" - I used this class to try to standardize the props that should be passed to any would be editor Component: - Renamed a bunch of the props which (I think) had a bit of confusing names - Added a bunch of docs for these in the source file, although I feel like those docs should live elsewhere, like in the ComponentRegion docs. - In the process, I ended up pulling some stuff out of ComposerView and some stuff out of the Contenteditable, namely: - The scrolling logic to ensure that the composer is visible while typing was moved outside of the Contenteditable -- this feels more like the ComposerEditor's responsibility, especially since the Contenteditable is meant to be used in other contexts as well. - The ComposerExtensions state; it feels less awkward for me if this is inside the ComposerEditor because 1) ComposerView does less things, 2) these are actually just being passed to the Contenteditable, 3) I feel like other plugins shouldn't need to mess around with ComposerExtensions, so we shouldn't pass them to the editor. If you register an editor different from our default one, any other ComposerExtension callbacks will be disabled, which I feel is expected behavior. - I think there is still some more refactoring to be done, and I left some TODOS here and there, but I think this diff is already big enough and its a minimal set of changes to get the markdown editor working in a not so duck tapish way. - New props for InjectedComponent: - `requiredMethods`: allows you to define a collection of methods that should be implemented by any Component that registers for your desired region. - It will throw an error if these are not implemented - It will automatically pass calls made on the InjectedComponent to these methods down to the instance of the actual registered component - Would love some comments on this approach and impl - `fallback`: allows you to define a default component to use if none were registered through the ComponentRegistry - Misc: - Added a new test case for the QuotedHTMLTransformer - Tests: - They were minimally updated so that they don't break, but a big TODO is to properly refactor them. I plan to do that in an upcoming diff. Test Plan: - Unit tests Reviewers: bengotow, evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D2372
2015-12-19 03:03:58 +08:00
# TODO
# Extract ComposerEditor tests instead of rendering injected component
# here
ComposerEditor.containerRequired = false
ComponentRegistry.register(ComposerEditor, role: "Composer:Editor")
2015-03-06 08:00:56 +08:00
@onChange = jasmine.createSpy('onChange')
@htmlNoQuote = 'Test <strong>HTML</strong><br>'
@htmlWithQuote = 'Test <strong>HTML</strong><br><blockquote class="gmail_quote">QUOTE</blockquote>'
@composer = ReactTestUtils.renderIntoDocument(<Composer draftClientId="unused"/>)
@composer._proxy = trigger: ->
spyOn(@composer, "_addToProxy")
spyOn(@composer, "_setupSession")
spyOn(@composer, "_teardownForDraft")
spyOn(@composer, "_deleteDraftIfEmpty")
spyOn(@composer, "_renderAttachments")
afterEach ->
DraftStore._cleanupAllSessions()
feat(editor-region): Add support to register components as editors Summary: - The main purpose of this is to be able to properly register the editor for the markdown plugin (and any other plugins to come) - Refactors ComposerView and Contenteditable -> - Replaces Contenteditable with an InjectedComponent for a new region role: "Composer:Editor" - Creates a new component called ComposerEditor, which is the one that is being registered by default as "Composer:Editor" - I used this class to try to standardize the props that should be passed to any would be editor Component: - Renamed a bunch of the props which (I think) had a bit of confusing names - Added a bunch of docs for these in the source file, although I feel like those docs should live elsewhere, like in the ComponentRegion docs. - In the process, I ended up pulling some stuff out of ComposerView and some stuff out of the Contenteditable, namely: - The scrolling logic to ensure that the composer is visible while typing was moved outside of the Contenteditable -- this feels more like the ComposerEditor's responsibility, especially since the Contenteditable is meant to be used in other contexts as well. - The ComposerExtensions state; it feels less awkward for me if this is inside the ComposerEditor because 1) ComposerView does less things, 2) these are actually just being passed to the Contenteditable, 3) I feel like other plugins shouldn't need to mess around with ComposerExtensions, so we shouldn't pass them to the editor. If you register an editor different from our default one, any other ComposerExtension callbacks will be disabled, which I feel is expected behavior. - I think there is still some more refactoring to be done, and I left some TODOS here and there, but I think this diff is already big enough and its a minimal set of changes to get the markdown editor working in a not so duck tapish way. - New props for InjectedComponent: - `requiredMethods`: allows you to define a collection of methods that should be implemented by any Component that registers for your desired region. - It will throw an error if these are not implemented - It will automatically pass calls made on the InjectedComponent to these methods down to the instance of the actual registered component - Would love some comments on this approach and impl - `fallback`: allows you to define a default component to use if none were registered through the ComponentRegistry - Misc: - Added a new test case for the QuotedHTMLTransformer - Tests: - They were minimally updated so that they don't break, but a big TODO is to properly refactor them. I plan to do that in an upcoming diff. Test Plan: - Unit tests Reviewers: bengotow, evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D2372
2015-12-19 03:03:58 +08:00
ComposerEditor.containerRequired = undefined
ComponentRegistry.unregister(ComposerEditor)
# Must be called with the test's scope
setHTML = (newHTML) ->
@$contentEditable.innerHTML = newHTML
@contentEditable._onDOMMutated(["mutated"])
describe "quoted-text-control toggle button", ->
describe "when there's no quoted text", ->
beforeEach ->
@composer.setState
body: @htmlNoQuote
showQuotedText: true
@contentEditable = @composer.refs[Fields.Body]
@$contentEditable = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithAttr(@contentEditable, 'contentEditable'))
@$composerBodyWrap = React.findDOMNode(@composer.refs.composerBodyWrap)
it 'should not display any quoted text', ->
expect(@$contentEditable.innerHTML).toBe @htmlNoQuote
2015-03-06 08:00:56 +08:00
it "allows the text to update", ->
textToAdd = "MORE <strong>TEXT</strong>!"
expect(@$contentEditable.innerHTML).toBe @htmlNoQuote
setHTML.call(@, textToAdd + @htmlNoQuote)
ev = @composer._addToProxy.mostRecentCall.args[0].body
expect(ev).toEqual(textToAdd + @htmlNoQuote)
2015-03-06 08:00:56 +08:00
it 'should not render the quoted-text-control toggle', ->
toggles = ReactTestUtils.scryRenderedDOMComponentsWithClass(@composer, 'quoted-text-control')
expect(toggles.length).toBe 0
describe 'when showQuotedText is true', ->
2015-03-06 08:00:56 +08:00
beforeEach ->
@composer.setState
body: @htmlWithQuote
showQuotedText: true
@contentEditable = @composer.refs[Fields.Body]
@$contentEditable = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithAttr(@contentEditable, 'contentEditable'))
@$composerBodyWrap = React.findDOMNode(@composer.refs.composerBodyWrap)
it 'should display the quoted text', ->
expect(@$contentEditable.innerHTML).toBe @htmlWithQuote
it "should call `_addToProxy` with the entire HTML string", ->
textToAdd = "MORE <strong>TEXT</strong>!"
expect(@$contentEditable.innerHTML).toBe @htmlWithQuote
setHTML.call(@, textToAdd + @htmlWithQuote)
ev = @composer._addToProxy.mostRecentCall.args[0].body
expect(ev).toEqual(textToAdd + @htmlWithQuote)
it "should allow the quoted text to be changed", ->
newText = 'Test <strong>NEW 1 HTML</strong><blockquote class="gmail_quote">QUOTE CHANGED!!!</blockquote>'
expect(@$contentEditable.innerHTML).toBe @htmlWithQuote
setHTML.call(@, newText)
ev = @composer._addToProxy.mostRecentCall.args[0].body
expect(ev).toEqual(newText)
describe 'quoted text control toggle button', ->
beforeEach ->
@toggle = ReactTestUtils.findRenderedDOMComponentWithClass(@composer, 'quoted-text-control')
it 'should be rendered', ->
expect(@toggle).toBeDefined()
2015-03-06 08:00:56 +08:00
it 'prompts to hide the quote', ->
expect(React.findDOMNode(@toggle).textContent).toEqual "•••Hide previous"
2015-03-06 08:00:56 +08:00
describe 'when showQuotedText is false', ->
beforeEach ->
@composer.setState
body: @htmlWithQuote
showQuotedText: false
@contentEditable = @composer.refs[Fields.Body]
@$contentEditable = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithAttr(@contentEditable, 'contentEditable'))
@$composerBodyWrap = React.findDOMNode(@composer.refs.composerBodyWrap)
# The quoted text dom parser wraps stuff inertly in body tags
wrapBody = (html) -> "<head></head><body>#{html}</body>"
it 'should not display any quoted text', ->
expect(@$contentEditable.innerHTML).toBe @htmlNoQuote
it "should let you change the text, and then append the quoted text part to the end before firing `_addToProxy`", ->
textToAdd = "MORE <strong>TEXT</strong>!"
expect(@$contentEditable.innerHTML).toBe @htmlNoQuote
setHTML.call(@, textToAdd + @htmlNoQuote)
ev = @composer._addToProxy.mostRecentCall.args[0].body
# Note that we expect the version WITH a quote while setting the
# version withOUT a quote.
expect(ev).toEqual(wrapBody(textToAdd + @htmlWithQuote))
it "should let you add more html that looks like quoted text, and still properly appends the old quoted text", ->
textToAdd = "Yo <blockquote class=\"gmail_quote\">I'm a fake quote</blockquote>"
expect(@$contentEditable.innerHTML).toBe @htmlNoQuote
setHTML.call(@, textToAdd + @htmlNoQuote)
ev = @composer._addToProxy.mostRecentCall.args[0].body
# Note that we expect the version WITH a quote while setting the
# version withOUT a quote.
expect(ev).toEqual(wrapBody(textToAdd + @htmlWithQuote))
describe 'quoted text control toggle button', ->
beforeEach ->
@toggle = ReactTestUtils.findRenderedDOMComponentWithClass(@composer, 'quoted-text-control')
it 'should be rendered', ->
expect(@toggle).toBeDefined()
it 'prompts to hide the quote', ->
expect(React.findDOMNode(@toggle).textContent).toEqual "•••Show previous"