mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-20 15:26:06 +08:00
refactor(spec): remove spectron from main app
This commit is contained in:
parent
ced66902d5
commit
f007962500
|
@ -65,14 +65,12 @@
|
|||
"service-hub": "^0.2.0",
|
||||
"source-map-support": "^0.3.2",
|
||||
"space-pen": "3.8.2",
|
||||
"spectron": "0.34.1",
|
||||
"spellchecker": "^3.1.2",
|
||||
"sqlite3": "https://github.com/mapbox/node-sqlite3/archive/v3.1.1.tar.gz",
|
||||
"temp": "^0.8",
|
||||
"theorist": "^1.0",
|
||||
"underscore": "^1.8",
|
||||
"underscore.string": "^3.0",
|
||||
"webdriverio": "3.2.6"
|
||||
"underscore.string": "^3.0"
|
||||
},
|
||||
"packageDependencies": {},
|
||||
"private": true,
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
_ = require 'underscore'
|
||||
React = require 'react/addons'
|
||||
TimeOverride = require '../../time-override'
|
||||
NylasTestUtils = require '../../nylas-test-utils'
|
||||
|
||||
{Contenteditable} = require 'nylas-component-kit'
|
||||
|
||||
###
|
||||
Public: Easily test contenteditable interactions
|
||||
|
||||
Create a new instance of this on each test. It will render a new
|
||||
Contenteditable into the document wrapped around a class that can keep
|
||||
track of its state.
|
||||
|
||||
For example
|
||||
|
||||
```coffee
|
||||
beforeEach ->
|
||||
@ce = new ContenteditableTestHarness
|
||||
|
||||
it "can create an ordered list", ->
|
||||
@ce.keys ['1', '.', ' ']
|
||||
@ce.expectHTML "<ol><li></li></ol>"
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.querySelectorAll("li")[0]
|
||||
|
||||
afterEach ->
|
||||
@ce.cleanup()
|
||||
|
||||
```
|
||||
|
||||
**Be sure to call `cleanup` after each test**
|
||||
|
||||
###
|
||||
class ContenteditableTestHarness
|
||||
constructor: ({@props, @initialValue}={}) ->
|
||||
@props ?= {}
|
||||
@initialValue ?= ""
|
||||
|
||||
@wrap = NylasTestUtils.renderIntoDocument(
|
||||
<Wrap ceProps={@props} initialValue={@initialValue} />
|
||||
)
|
||||
|
||||
cleanup: ->
|
||||
NylasTestUtils.removeFromDocument(@wrap)
|
||||
|
||||
# We send keys to spectron one at a time. We also need ot use a "real"
|
||||
# setTimeout since Spectron is completely outside of the mocked setTimeouts
|
||||
# that we setup. We still `advanceClock` to clear any components or Promises
|
||||
# that need to run inbetween keystrokes.
|
||||
keys: (keyStrokes=[]) -> new Promise (resolve, reject) =>
|
||||
TimeOverride.disableSpies()
|
||||
@getDOM().focus()
|
||||
timeout = 0
|
||||
KEY_DELAY = 1000
|
||||
keyStrokes.forEach (key) ->
|
||||
window.setTimeout ->
|
||||
NylasEnv.spectron.client.keys([key])
|
||||
advanceClock(KEY_DELAY)
|
||||
, timeout
|
||||
timeout += KEY_DELAY
|
||||
window.setTimeout ->
|
||||
resolve()
|
||||
, timeout + KEY_DELAY
|
||||
|
||||
expectHTML: (expectedHTML) ->
|
||||
expect(@wrap.state.value).toBe expectedHTML
|
||||
|
||||
expectSelection: (callback) ->
|
||||
expectSel = callback(@getDOM())
|
||||
|
||||
anchorNode = expectSel.anchorNode ? expectSel.node ? "No anchorNode found"
|
||||
focusNode = expectSel.focusNode ? expectSel.node ? "No focusNode found"
|
||||
anchorOffset = expectSel.anchorOffset ? expectSel.offset ? 0
|
||||
focusOffset = expectSel.focusOffset ? expectSel.offset ? 0
|
||||
|
||||
selection = document.getSelection()
|
||||
|
||||
expect(selection.anchorNode).toBe anchorNode
|
||||
expect(selection.focusNode).toBe focusNode
|
||||
expect(selection.anchorOffset).toBe anchorOffset
|
||||
expect(selection.focusOffset).toBe focusOffset
|
||||
|
||||
getDOM: ->
|
||||
React.findDOMNode(@wrap.refs["ceWrap"].refs["contenteditable"])
|
||||
|
||||
class Wrap extends React.Component
|
||||
@displayName: "wrap"
|
||||
|
||||
constructor: (@props) ->
|
||||
@state = value: @props.initialValue
|
||||
|
||||
render: ->
|
||||
userOnChange = @props.ceProps.onChange ? ->
|
||||
props = _.clone(@props.ceProps)
|
||||
props.onChange = (event) =>
|
||||
userOnChange(event)
|
||||
@onChange(event)
|
||||
props.value = @state.value
|
||||
props.ref = "ceWrap"
|
||||
|
||||
<Contenteditable {...props} />
|
||||
|
||||
onChange: (event) ->
|
||||
@setState value: event.target.value
|
||||
|
||||
componentDidMount: ->
|
||||
@refs.ceWrap.focus()
|
||||
|
||||
module.exports = ContenteditableTestHarness
|
|
@ -1,122 +0,0 @@
|
|||
ContenteditableTestHarness = require './contenteditable-test-harness'
|
||||
|
||||
return unless NylasEnv.inIntegrationSpecMode()
|
||||
|
||||
xdescribe "ListManager", ->
|
||||
beforeEach ->
|
||||
# console.log "--> Before each"
|
||||
@ce = new ContenteditableTestHarness
|
||||
# div = document.querySelector("div[contenteditable]")
|
||||
# console.log div
|
||||
# console.log div?.innerHTML
|
||||
# console.log "Done before each"
|
||||
|
||||
afterEach ->
|
||||
# console.log "<-- After each"
|
||||
@ce.cleanup()
|
||||
|
||||
it "Creates ordered lists", -> waitsForPromise =>
|
||||
@ce.keys(['1', '.', 'Space']).then =>
|
||||
# console.log "Keys typed"
|
||||
@ce.expectHTML "<ol><li></li></ol>"
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.querySelectorAll("li")[0]
|
||||
|
||||
it "Undoes ordered list creation with backspace", -> waitsForPromise =>
|
||||
@ce.keys(['1', '.', 'Space', 'Back space']).then =>
|
||||
@ce.expectHTML "1. "
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.childNodes[0]
|
||||
offset: 3
|
||||
|
||||
it "Creates unordered lists with star", -> waitsForPromise =>
|
||||
@ce.keys(['*', 'Space']).then =>
|
||||
@ce.expectHTML "<ul><li></li></ul>"
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.querySelectorAll("li")[0]
|
||||
|
||||
it "Undoes unordered list creation with backspace", ->
|
||||
aitsForPromise =>
|
||||
@ce.keys(['*', 'Space', 'Back space']).then =>
|
||||
@ce.expectHTML "* "
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.childNodes[0]
|
||||
offset: 2
|
||||
|
||||
it "Creates unordered lists with dash", -> waitsForPromise =>
|
||||
@ce.keys(['-', 'Space']).then =>
|
||||
@ce.expectHTML "<ul><li></li></ul>"
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.querySelectorAll("li")[0]
|
||||
|
||||
it "Undoes unordered list creation with backspace", ->
|
||||
waitsForPromise =>
|
||||
@ce.keys(['-', 'Space', 'Back space']).then =>
|
||||
@ce.expectHTML "- "
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.childNodes[0]
|
||||
offset: 2
|
||||
|
||||
it "create a single item then delete it with backspace", ->
|
||||
waitsForPromise =>
|
||||
@ce.keys(['-', 'Space', 'a', 'Left arrow', 'Back space']).then =>
|
||||
@ce.expectHTML "a"
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.childNodes[0]
|
||||
offset: 0
|
||||
|
||||
it "create a single item then delete it with tab", ->
|
||||
waitsForPromise =>
|
||||
@ce.keys(['-', 'Space', 'a', 'Shift', 'Tab']).then =>
|
||||
@ce.expectHTML "a"
|
||||
@ce.expectSelection (dom) -> dom.childNodes[0]
|
||||
node: dom.childNodes[0]
|
||||
offset: 1
|
||||
|
||||
describe "when creating two items in a list", ->
|
||||
beforeEach ->
|
||||
@twoItemKeys = ['-', 'Space', 'a', 'Return', 'b']
|
||||
|
||||
it "creates two items with enter at end", -> waitsForPromise =>
|
||||
@ce.keys(@twoItemKeys).then =>
|
||||
@ce.expectHTML "<ul><li>a</li><li>b</li></ul>"
|
||||
@ce.expectSelection (dom) ->
|
||||
node: dom.querySelectorAll('li')[1].childNodes[0]
|
||||
offset: 1
|
||||
|
||||
xit "backspace from the start of the 1st item outdents", ->
|
||||
@ce.keys @twoItemKeys.concat ['left', 'up', 'backspace']
|
||||
|
||||
xit "backspace from the start of the 2nd item outdents", ->
|
||||
@ce.keys @twoItemKeys.concat ['left', 'backspace']
|
||||
|
||||
xit "shift-tab from the start of the 1st item outdents", ->
|
||||
@ce.keys @twoItemKeys.concat ['left', 'up', 'shift-tab']
|
||||
|
||||
xit "shift-tab from the start of the 2nd item outdents", ->
|
||||
@ce.keys @twoItemKeys.concat ['left', 'shift-tab']
|
||||
|
||||
xit "shift-tab from the end of the 1st item outdents", ->
|
||||
@ce.keys @twoItemKeys.concat ['up', 'shift-tab']
|
||||
|
||||
xit "shift-tab from the end of the 2nd item outdents", ->
|
||||
@ce.keys @twoItemKeys.concat ['shift-tab']
|
||||
|
||||
xit "backspace from the end of the 1st item doesn't outdent", ->
|
||||
@ce.keys @twoItemKeys.concat ['up', 'backspace']
|
||||
|
||||
xit "backspace from the end of the 2nd item doesn't outdent", ->
|
||||
@ce.keys @twoItemKeys.concat ['backspace']
|
||||
|
||||
xdescribe "multi-depth bullets", ->
|
||||
it "creates multi level bullet when tabbed in", ->
|
||||
@ce.keys ['-', ' ', 'a', 'tab']
|
||||
|
||||
it "creates multi level bullet when tabbed in", ->
|
||||
@ce.keys ['-', ' ', 'tab', 'a']
|
||||
|
||||
it "returns to single level bullet on backspace", ->
|
||||
@ce.keys ['-', ' ', 'a', 'tab', 'left', 'backspace']
|
||||
|
||||
it "returns to single level bullet on shift-tab", ->
|
||||
@ce.keys ['-', ' ', 'a', 'tab', 'shift-tab']
|
|
@ -43,22 +43,16 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
|||
|
||||
NylasEnv.initialize()
|
||||
|
||||
# Tests that run under an integration environment need Spectron to be
|
||||
# asynchronously setup and connected to the Selenium API before proceeding.
|
||||
# Once setup, one can test `NylasEnv.inIntegrationSpecMode()`
|
||||
#
|
||||
# This safely works regardless if Spectron is loaded.
|
||||
NylasEnv.setupSpectron().finally ->
|
||||
require specSuite
|
||||
require specSuite
|
||||
|
||||
jasmineEnv = jasmine.getEnv()
|
||||
jasmineEnv.addReporter(reporter)
|
||||
jasmineEnv.addReporter(timeReporter)
|
||||
jasmineEnv.setIncludedTags([process.platform])
|
||||
jasmineEnv = jasmine.getEnv()
|
||||
jasmineEnv.addReporter(reporter)
|
||||
jasmineEnv.addReporter(timeReporter)
|
||||
jasmineEnv.setIncludedTags([process.platform])
|
||||
|
||||
$('body').append $$ -> @div id: 'jasmine-content'
|
||||
$('body').append $$ -> @div id: 'jasmine-content'
|
||||
|
||||
jasmineEnv.execute()
|
||||
jasmineEnv.execute()
|
||||
|
||||
disableFocusMethods = ->
|
||||
['fdescribe', 'ffdescribe', 'fffdescribe', 'fit', 'ffit', 'fffit'].forEach (methodName) ->
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {N1Launcher} from './integration-helper'
|
||||
import ContenteditableTestHarness from './contenteditable-test-harness.es6'
|
||||
|
||||
fdescribe('Contenteditable Integration Spec', function() {
|
||||
describe('Contenteditable Integration Spec', function() {
|
||||
beforeAll((done)=>{
|
||||
this.app = new N1Launcher(["--dev"]);
|
||||
this.app.popoutComposerWindowReady().finally(done);
|
||||
|
@ -77,23 +77,53 @@ fdescribe('Contenteditable Integration Spec', function() {
|
|||
}).then(done).catch(done.fail)
|
||||
});
|
||||
|
||||
// it("create a single item then delete it with backspace", (done) => {
|
||||
// this.ce.test({
|
||||
// keys: ['-', 'Space', 'a', 'Left arrow', 'Back space'],
|
||||
// expectedHTML: "<span style=\"line-height: 1.4;\">a</span><br>",
|
||||
// expectedSelectionResolver: (dom) => {
|
||||
// return {node: dom.childNodes[0], offset: 0} }
|
||||
// }).then(done).catch(done.fail)
|
||||
// });
|
||||
//
|
||||
// it("create a single item then delete it with tab", (done) => {
|
||||
// this.ce.test({
|
||||
// keys: ['-', 'Space', 'a', 'Shift', 'Tab'],
|
||||
// expectedHTML: "<span style=\"line-height: 1.4;\">a</span><br>",
|
||||
// expectedSelectionResolver: (dom) => {
|
||||
// return {node: dom.childNodes[0], offset: 1} }
|
||||
// }).then(done).catch(done.fail)
|
||||
// });
|
||||
// describe "when creating two items in a list", ->
|
||||
// beforeEach ->
|
||||
// @twoItemKeys = ['-', 'Space', 'a', 'Return', 'b']
|
||||
//
|
||||
// it "creates two items with enter at end", -> waitsForPromise =>
|
||||
// @ce.keys(@twoItemKeys).then =>
|
||||
// @ce.expectHTML "<ul><li>a</li><li>b</li></ul>"
|
||||
// @ce.expectSelection (dom) ->
|
||||
// node: dom.querySelectorAll('li')[1].childNodes[0]
|
||||
// offset: 1
|
||||
//
|
||||
// xit "backspace from the start of the 1st item outdents", ->
|
||||
// @ce.keys @twoItemKeys.concat ['left', 'up', 'backspace']
|
||||
//
|
||||
// xit "backspace from the start of the 2nd item outdents", ->
|
||||
// @ce.keys @twoItemKeys.concat ['left', 'backspace']
|
||||
//
|
||||
// xit "shift-tab from the start of the 1st item outdents", ->
|
||||
// @ce.keys @twoItemKeys.concat ['left', 'up', 'shift-tab']
|
||||
//
|
||||
// xit "shift-tab from the start of the 2nd item outdents", ->
|
||||
// @ce.keys @twoItemKeys.concat ['left', 'shift-tab']
|
||||
//
|
||||
// xit "shift-tab from the end of the 1st item outdents", ->
|
||||
// @ce.keys @twoItemKeys.concat ['up', 'shift-tab']
|
||||
//
|
||||
// xit "shift-tab from the end of the 2nd item outdents", ->
|
||||
// @ce.keys @twoItemKeys.concat ['shift-tab']
|
||||
//
|
||||
// xit "backspace from the end of the 1st item doesn't outdent", ->
|
||||
// @ce.keys @twoItemKeys.concat ['up', 'backspace']
|
||||
//
|
||||
// xit "backspace from the end of the 2nd item doesn't outdent", ->
|
||||
// @ce.keys @twoItemKeys.concat ['backspace']
|
||||
//
|
||||
// xdescribe "multi-depth bullets", ->
|
||||
// it "creates multi level bullet when tabbed in", ->
|
||||
// @ce.keys ['-', ' ', 'a', 'tab']
|
||||
//
|
||||
// it "creates multi level bullet when tabbed in", ->
|
||||
// @ce.keys ['-', ' ', 'tab', 'a']
|
||||
//
|
||||
// it "returns to single level bullet on backspace", ->
|
||||
// @ce.keys ['-', ' ', 'a', 'tab', 'left', 'backspace']
|
||||
//
|
||||
// it "returns to single level bullet on shift-tab", ->
|
||||
// @ce.keys ['-', ' ', 'a', 'tab', 'shift-tab']
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
import {N1Launcher} from './integration-helper'
|
||||
|
||||
// Some unit tests, such as the Contenteditable specs need to be run with
|
||||
// Spectron availble in the environment.
|
||||
describe('Integrated Unit Tests', function() {
|
||||
beforeAll((done)=>{
|
||||
// Boot in dev mode with no arguments
|
||||
this.app = new N1Launcher(["--test=window"]);
|
||||
this.app.start().then(done).catch(done)
|
||||
this.originalTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5*60*1000 // 5 minutes
|
||||
});
|
||||
|
||||
afterAll((done)=> {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = this.originalTimeoutInterval
|
||||
if (this.app && this.app.isRunning()) {
|
||||
this.app.stop().then(done);
|
||||
} else {
|
||||
done()
|
||||
}
|
||||
});
|
||||
|
||||
it("Passes all integrated unit tests", (done)=> {
|
||||
var client = this.app.client
|
||||
client.waitForExist(".specs-complete", jasmine.UNIT_TEST_TIMEOUT)
|
||||
.then(()=>{ return client.getHTML(".specs-complete .message") })
|
||||
.then((results)=>{
|
||||
expect(results).toMatch(/0 failures/)
|
||||
}).then(()=>{ return client.getHTML(".plain-text-output") })
|
||||
.then((errorOutput)=>{
|
||||
expect(errorOutput).toBe('<pre class="plain-text-output"></pre>')
|
||||
done()
|
||||
}).catch(done)
|
||||
});
|
||||
|
||||
});
|
|
@ -223,52 +223,6 @@ class NylasEnvConstructor extends Model
|
|||
window.onbeforeunload = => @_unloading()
|
||||
@_unloadCallbacks = []
|
||||
|
||||
# Some unit tests require access to the Selenium web driver APIs as exposed
|
||||
# by Spectron/Chromedriver. The app must be booted by Spectron as is done in the `run-integration-tests` task. Once Spectron boots the app, it will expose a RESTful API
|
||||
#
|
||||
# The Selenium API spec is here: https://code.google.com/p/selenium/wiki/JsonWireProtocol
|
||||
#
|
||||
# The Node wrapper for that API is provided by webdriver: http://webdriver.io/api.html
|
||||
#
|
||||
# Spectron wraps webdriver (in its `client` property) and adds additional methods: https://github.com/kevinsawicki/spectron
|
||||
#
|
||||
# Spectron requests that Selenium use Chromedriver
|
||||
# https://sites.google.com/a/chromium.org/chromedriver/home to interface
|
||||
# with the app, but points the binary at Electron.
|
||||
#
|
||||
# Since this code here is "inside" the booted process, we have no way of
|
||||
# directly accessing the client from the test runner. However, we can still
|
||||
# connect directly to the Selenium server to control ourself.
|
||||
#
|
||||
# We unfortunately can't create a new session with Selenium, because we
|
||||
# won't be connected to the correct process (us!). Instead we need to
|
||||
# inspect the existing sessions and use the existing one instead.
|
||||
#
|
||||
# We then manually setup the WebDriver session, and add in the extra
|
||||
# spectron APIs via `Spectron.Application::addCommands`.
|
||||
#
|
||||
# http://webdriver.io/api/protocol/windowHandles.html
|
||||
# https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value
|
||||
setupSpectron: ->
|
||||
options =
|
||||
host: "127.0.0.1"
|
||||
port: 9515
|
||||
SpectronApp = require('spectron').Application
|
||||
@spectron = new SpectronApp
|
||||
WebDriver = require('webdriverio')
|
||||
@spectron.client = new WebDriver.remote(options)
|
||||
@spectron.addCommands()
|
||||
@spectron.client.sessions().then ({value}) =>
|
||||
{sessionId, capabilities} = value[0]
|
||||
@spectron.client.requestHandler.sessionID = sessionId
|
||||
# https://github.com/webdriverio/webdriverio/blob/master/lib/protocol/init.js
|
||||
@spectron.client.sessionID = sessionId
|
||||
@spectron.client.capabilities = capabilities
|
||||
@spectron.client.desiredCapabilities = capabilities
|
||||
|
||||
inIntegrationSpecMode: ->
|
||||
@inSpecMode() and @spectron?.client?.sessionID
|
||||
|
||||
# Start our error reporting to the backend and attach error handlers
|
||||
# to the window and the Bluebird Promise library, converting things
|
||||
# back through the sourcemap as necessary.
|
||||
|
|
Loading…
Reference in a new issue