mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-01-27 18:37:53 +08:00
cleanup(specs): Remove space-pen. Goodbye, jQuery!
This commit is contained in:
parent
1b62e09f71
commit
7c557c0c8f
12 changed files with 407 additions and 696 deletions
|
@ -3094,7 +3094,6 @@
|
|||
2998273: node_modules/theorist/lib/sequence.js
|
||||
3004878: node_modules/coffeestack/index.js
|
||||
3010047: src/window-event-handler.js
|
||||
3033233: node_modules/space-pen/lib/space-pen.js
|
||||
3054355: src/styles-element.js
|
||||
1995661: src/flux/models/utils.js
|
||||
3061775: src/flux/errors.js
|
||||
|
@ -4562,7 +4561,6 @@
|
|||
2998273: node_modules/theorist/lib/sequence.js
|
||||
3004878: node_modules/coffeestack/index.js
|
||||
3010047: src/window-event-handler.js
|
||||
3033233: node_modules/space-pen/lib/space-pen.js
|
||||
3054355: src/styles-element.js
|
||||
1995661: src/flux/models/utils.js
|
||||
3061775: src/flux/errors.js
|
||||
|
|
|
@ -8,10 +8,6 @@ _ = require 'underscore'
|
|||
donna = require 'donna'
|
||||
tello = require 'tello'
|
||||
|
||||
moduleBlacklist = [
|
||||
'space-pen'
|
||||
]
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{cp, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
|
@ -23,7 +19,6 @@ module.exports = (grunt) ->
|
|||
return false if modulePath.match(/node_modules/g)
|
||||
|
||||
# Don't traverse blacklisted packages (that have docs, but we don't want to include)
|
||||
return false if path.basename(modulePath) in moduleBlacklist
|
||||
return true unless path.basename(modulePath) is 'package.json'
|
||||
return true unless fs.isFileSync(modulePath)
|
||||
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
"season": "^5.1",
|
||||
"semver": "^4.2",
|
||||
"source-map-support": "^0.3.2",
|
||||
"space-pen": "3.8.2",
|
||||
"spellchecker": "3.2.3",
|
||||
"temp": "^0.8",
|
||||
"underscore": "^1.8",
|
||||
|
|
|
@ -2,8 +2,6 @@ fs = require 'fs'
|
|||
{remote} = require 'electron'
|
||||
|
||||
module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
window[key] = value for key, value of require './jasmine'
|
||||
|
||||
{TerminalReporter} = require 'jasmine-tagged'
|
||||
|
@ -21,8 +19,7 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
|||
remote.process.stdout.write(str)
|
||||
|
||||
if NylasEnv.getLoadSettings().showSpecsInWindow
|
||||
N1SpecReporter = require './n1-spec-reporter'
|
||||
reporter = new N1SpecReporter()
|
||||
reporter = require './n1-spec-reporter'
|
||||
else if NylasEnv.getLoadSettings().exitWhenDone
|
||||
reporter = new TerminalReporter
|
||||
color: true
|
||||
|
@ -38,8 +35,7 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
|||
else
|
||||
NylasEnv.exit(0)
|
||||
else
|
||||
N1SpecReporter = require './n1-spec-reporter'
|
||||
reporter = new N1SpecReporter()
|
||||
reporter = require './n1-spec-reporter'
|
||||
|
||||
NylasEnv.initialize()
|
||||
|
||||
|
@ -50,7 +46,9 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
|||
jasmineEnv.addReporter(timeReporter)
|
||||
jasmineEnv.setIncludedTags([process.platform])
|
||||
|
||||
$('body').append $$ -> @div id: 'jasmine-content'
|
||||
div = document.createElement('div')
|
||||
div.id = 'jasmine-content'
|
||||
document.body.appendChild(div)
|
||||
|
||||
jasmineEnv.execute()
|
||||
|
||||
|
|
|
@ -1,181 +0,0 @@
|
|||
(function(jQuery) {
|
||||
|
||||
jasmine.JQuery = function() {};
|
||||
|
||||
jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
|
||||
return jQuery('<div/>').append(html).html();
|
||||
};
|
||||
|
||||
jasmine.JQuery.elementToString = function(element) {
|
||||
return jQuery('<div />').append(element.clone()).html();
|
||||
};
|
||||
|
||||
jasmine.JQuery.matchersClass = {};
|
||||
|
||||
(function(namespace) {
|
||||
var data = {
|
||||
spiedEvents: {},
|
||||
handlers: []
|
||||
};
|
||||
|
||||
namespace.events = {
|
||||
spyOn: function(selector, eventName) {
|
||||
var handler = function(e) {
|
||||
data.spiedEvents[[selector, eventName]] = e;
|
||||
};
|
||||
jQuery(selector).bind(eventName, handler);
|
||||
data.handlers.push(handler);
|
||||
},
|
||||
|
||||
wasTriggered: function(selector, eventName) {
|
||||
return !!(data.spiedEvents[[selector, eventName]]);
|
||||
},
|
||||
|
||||
cleanUp: function() {
|
||||
data.spiedEvents = {};
|
||||
data.handlers = [];
|
||||
}
|
||||
}
|
||||
})(jasmine.JQuery);
|
||||
|
||||
(function(){
|
||||
var jQueryMatchers = {
|
||||
toHaveClass: function(className) {
|
||||
return this.actual.hasClass(className);
|
||||
},
|
||||
|
||||
toBeVisible: function() {
|
||||
return this.actual.is(':visible');
|
||||
},
|
||||
|
||||
toBeHidden: function() {
|
||||
return this.actual.is(':hidden');
|
||||
},
|
||||
|
||||
toBeSelected: function() {
|
||||
return this.actual.is(':selected');
|
||||
},
|
||||
|
||||
toBeChecked: function() {
|
||||
return this.actual.is(':checked');
|
||||
},
|
||||
|
||||
toBeEmpty: function() {
|
||||
return this.actual.is(':empty');
|
||||
},
|
||||
|
||||
toExist: function() {
|
||||
return this.actual.size() > 0;
|
||||
},
|
||||
|
||||
toHaveAttr: function(attributeName, expectedAttributeValue) {
|
||||
return hasProperty(this.actual.attr(attributeName), expectedAttributeValue);
|
||||
},
|
||||
|
||||
toHaveId: function(id) {
|
||||
return this.actual.attr('id') == id;
|
||||
},
|
||||
|
||||
toHaveHtml: function(html) {
|
||||
return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html);
|
||||
},
|
||||
|
||||
toHaveText: function(text) {
|
||||
if (text && jQuery.isFunction(text.test)) {
|
||||
return text.test(this.actual.text());
|
||||
} else {
|
||||
return this.actual.text() == text;
|
||||
}
|
||||
},
|
||||
|
||||
toHaveValue: function(value) {
|
||||
return this.actual.val() == value;
|
||||
},
|
||||
|
||||
toHaveData: function(key, expectedValue) {
|
||||
return hasProperty(this.actual.data(key), expectedValue);
|
||||
},
|
||||
|
||||
toMatchSelector: function(selector) {
|
||||
return this.actual.is(selector);
|
||||
},
|
||||
|
||||
toContain: function(selector) {
|
||||
return this.actual.find(selector).size() > 0;
|
||||
},
|
||||
|
||||
toBeDisabled: function(selector){
|
||||
return this.actual.is(':disabled');
|
||||
},
|
||||
|
||||
// tests the existence of a specific event binding
|
||||
toHandle: function(eventName) {
|
||||
var events = this.actual.data("events");
|
||||
return events && events[eventName].length > 0;
|
||||
},
|
||||
|
||||
// tests the existence of a specific event binding + handler
|
||||
toHandleWith: function(eventName, eventHandler) {
|
||||
var stack = this.actual.data("events")[eventName];
|
||||
var i;
|
||||
for (i = 0; i < stack.length; i++) {
|
||||
if (stack[i].handler == eventHandler) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var hasProperty = function(actualValue, expectedValue) {
|
||||
if (expectedValue === undefined) {
|
||||
return actualValue !== undefined;
|
||||
}
|
||||
return actualValue == expectedValue;
|
||||
};
|
||||
|
||||
var bindMatcher = function(methodName) {
|
||||
var builtInMatcher = jasmine.Matchers.prototype[methodName];
|
||||
|
||||
jasmine.JQuery.matchersClass[methodName] = function() {
|
||||
if (this.actual instanceof HTMLElement) {
|
||||
this.actual = jQuery(this.actual);
|
||||
}
|
||||
if (this.actual && this.actual.jquery) {
|
||||
var result = jQueryMatchers[methodName].apply(this, arguments);
|
||||
this.actual = jasmine.JQuery.elementToString(this.actual);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (builtInMatcher) {
|
||||
return builtInMatcher.apply(this, arguments);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
for(var methodName in jQueryMatchers) {
|
||||
bindMatcher(methodName);
|
||||
}
|
||||
})();
|
||||
|
||||
beforeEach(function() {
|
||||
this.addMatchers(jasmine.JQuery.matchersClass);
|
||||
this.addMatchers({
|
||||
toHaveBeenTriggeredOn: function(selector) {
|
||||
this.message = function() {
|
||||
return [
|
||||
"Expected event " + this.actual + " to have been triggered on" + selector,
|
||||
"Expected event " + this.actual + " not to have been triggered on" + selector
|
||||
];
|
||||
};
|
||||
return jasmine.JQuery.events.wasTriggered(selector, this.actual);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
jasmine.JQuery.events.cleanUp();
|
||||
});
|
||||
})(require('../src/space-pen-extensions').jQuery);
|
315
spec/n1-spec-reporter.cjsx
Normal file
315
spec/n1-spec-reporter.cjsx
Normal file
|
@ -0,0 +1,315 @@
|
|||
path = require 'path'
|
||||
_ = require 'underscore'
|
||||
_str = require 'underscore.string'
|
||||
{convertStackTrace} = require 'coffeestack'
|
||||
React = require 'react'
|
||||
ReactDOM = require 'react-dom'
|
||||
grim = require 'grim'
|
||||
marked = require 'marked'
|
||||
|
||||
sourceMaps = {}
|
||||
formatStackTrace = (spec, message='', stackTrace, indent="") ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
jasminePattern = /^\s*at\s+.*\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
firstJasmineLinePattern = /^\s*at [/\\].*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
convertedLines = []
|
||||
for line in stackTrace.split('\n')
|
||||
convertedLines.push(line) unless jasminePattern.test(line)
|
||||
break if firstJasmineLinePattern.test(line)
|
||||
|
||||
stackTrace = convertStackTrace(convertedLines.join('\n'), sourceMaps)
|
||||
lines = stackTrace.split('\n')
|
||||
|
||||
# Remove first line of stack when it is the same as the error message
|
||||
errorMatch = lines[0]?.match(/^Error: (.*)/)
|
||||
lines.shift() if message.trim() is errorMatch?[1]?.trim()
|
||||
|
||||
for line, index in lines
|
||||
# Remove prefix of lines matching: at [object Object].<anonymous> (path:1:2)
|
||||
prefixMatch = line.match(/at \[object Object\]\.<anonymous> \(([^)]+)\)/)
|
||||
line = "at #{prefixMatch[1]}" if prefixMatch
|
||||
|
||||
# Relativize locations to spec directory
|
||||
lines[index] = line.replace("at #{spec.specDirectory}#{path.sep}", 'at ')
|
||||
|
||||
lines = lines.map (line) -> indent + line.trim()
|
||||
lines.join('\n')
|
||||
|
||||
|
||||
indentationString: (suite, plus=0) ->
|
||||
rootSuite = suite
|
||||
indentLevel = 0 + plus
|
||||
while rootSuite.parentSuite
|
||||
rootSuite = rootSuite.parentSuite
|
||||
indentLevel += 1
|
||||
return [0...indentLevel].map(-> " ").join("")
|
||||
|
||||
|
||||
suiteString: (spec) ->
|
||||
descriptions = [spec.suite.description]
|
||||
|
||||
rootSuite = spec.suite
|
||||
while rootSuite.parentSuite
|
||||
indent = indentationString(rootSuite)
|
||||
descriptions.unshift(indent + rootSuite.description)
|
||||
rootSuite = rootSuite.parentSuite
|
||||
|
||||
descriptions.join("\n")
|
||||
|
||||
|
||||
class N1SpecReporter extends React.Component
|
||||
constructor: (@props) ->
|
||||
|
||||
render: ->
|
||||
<div className="spec-reporter">
|
||||
<div className="padded pull-right">
|
||||
<button className="btn reload-button" onClick={@onReloadSpecs}>Reload Specs</button>
|
||||
</div>
|
||||
<div className="symbol-area">
|
||||
<div className="symbol-header">Core</div>
|
||||
<div className="symbol-summary list-unstyled">{@_renderSpecsOfType('core')}</div>
|
||||
</div>
|
||||
<div className="symbol-area">
|
||||
<div className="symbol-header">Bundled</div>
|
||||
<div className="symbol-summary list-unstyled">{@_renderSpecsOfType('bundled')}</div>
|
||||
</div>
|
||||
<div className="symbol-area">
|
||||
<div className="symbol-header">User</div>
|
||||
<div className="symbol-summary list-unstyled">{@_renderSpecsOfType('user')}</div>
|
||||
</div>
|
||||
{@_renderStatus()}
|
||||
<div className="results">
|
||||
{@_renderFailures()}
|
||||
</div>
|
||||
{@_renderDeprecations()}
|
||||
<div className="plain-text-output">
|
||||
{@props.plainTextOutput}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
_renderSpecsOfType: (type) =>
|
||||
items = []
|
||||
@props.specs.forEach (spec, idx) =>
|
||||
return unless spec.specType is type
|
||||
statusClass = "pending"
|
||||
title = undefined
|
||||
results = spec.results()
|
||||
if results
|
||||
if results.skipped
|
||||
statusClass = "skipped"
|
||||
else if results.failedCount > 0
|
||||
statusClass = "failed"
|
||||
title = spec.getFullName()
|
||||
else if spec.endedAt
|
||||
statusClass = "passed"
|
||||
|
||||
items.push <li key={idx} title={title} className="spec-summary #{statusClass}"/>
|
||||
|
||||
items
|
||||
|
||||
_renderFailures: =>
|
||||
# We have an array of specs with `suite` and potentially N `parentSuite` from there.
|
||||
# Create a tree instead.
|
||||
topLevelSuites = []
|
||||
|
||||
failedSpecs = @props.specs.filter (spec) ->
|
||||
spec.endedAt and spec.results().failedCount > 0
|
||||
|
||||
for spec in failedSpecs
|
||||
suite = spec.suite
|
||||
suite = suite.parentSuite while suite.parentSuite
|
||||
if topLevelSuites.indexOf(suite) is -1
|
||||
topLevelSuites.push(suite)
|
||||
|
||||
topLevelSuites.map (suite, idx) =>
|
||||
<SuiteResultView suite={suite} key={idx} allSpecs={failedSpecs} />
|
||||
|
||||
_renderDeprecations: =>
|
||||
return if @props.deprecations.length is 0
|
||||
|
||||
if @props.deprecations.length is 1
|
||||
label = "1 deprecation"
|
||||
else
|
||||
label = "#{@props.deprecations.length} deprecations"
|
||||
|
||||
<div className="status alert alert-warning">
|
||||
<span>{label}</span>
|
||||
<div className="deprecation-toggle">
|
||||
<div className="deprecation-list">
|
||||
{@_renderDeprecationList()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
_renderDeprecationList: =>
|
||||
@props.deprecations.map (deprecation) =>
|
||||
<div className="padded" key={deprecation.message}>
|
||||
<div className="result-message fail deprecation-message">
|
||||
{deprecation.message}
|
||||
{
|
||||
deprecation.getStacks().map (stack) =>
|
||||
fullStack = stack.map ({functionName, location}) ->
|
||||
if functionName is '<unknown>'
|
||||
" at #{location}"
|
||||
else
|
||||
" at #{functionName} (#{location})"
|
||||
<pre className="stack-trace padded">
|
||||
{formatStackTrace(deprecation.spec, deprecation.message, fullStack.join('\n'))}
|
||||
</pre>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
_renderStatus: =>
|
||||
failedCount = 0
|
||||
skippedCount = 0
|
||||
completeCount = 0
|
||||
for spec in @props.specs
|
||||
results = spec.results()
|
||||
continue unless spec.endedAt
|
||||
failedCount += 1 if results.failedCount > 0
|
||||
skippedCount += 1 if results.skipped
|
||||
completeCount += 1 if results.passedCount > 0 and results.failedCount is 0
|
||||
|
||||
if failedCount is 1
|
||||
message = "#{failedCount} failure"
|
||||
else
|
||||
message = "#{failedCount} failures"
|
||||
|
||||
if skippedCount
|
||||
specCount = "#{completeCount - skippedCount}/#{@props.specs.length - skippedCount} (#{skippedCount} skipped)"
|
||||
else
|
||||
specCount = "#{completeCount}/#{@props.specs.length}"
|
||||
|
||||
<div className="status alert alert-info">
|
||||
<div className="time"></div>
|
||||
<div className="spec-count">{specCount}</div>
|
||||
<div className="message">{message}</div>
|
||||
</div>
|
||||
|
||||
onReloadSpecs: =>
|
||||
require('electron').ipcRenderer.send('call-webcontents-method', 'reload')
|
||||
|
||||
|
||||
class SuiteResultView extends React.Component
|
||||
@propTypes: ->
|
||||
suite: React.PropTypes.object
|
||||
allSpecs: React.PropTypes.array
|
||||
|
||||
render: ->
|
||||
items = []
|
||||
subsuites = []
|
||||
|
||||
@props.allSpecs.forEach (spec) =>
|
||||
if spec.suite is @props.suite
|
||||
items.push(spec)
|
||||
else
|
||||
suite = spec.suite
|
||||
while suite.parentSuite
|
||||
if suite.parentSuite is @props.suite
|
||||
subsuites.push(suite)
|
||||
return
|
||||
suite = suite.parentSuite
|
||||
|
||||
items = items.map (spec, idx) =>
|
||||
<SpecResultView key={idx} spec={spec} />
|
||||
|
||||
subsuites = subsuites.map (suite, idx) =>
|
||||
<SuiteResultView key={idx} suite={suite} allSpecs={@props.allSpecs} />
|
||||
|
||||
<div className="suite">
|
||||
<div className="description">{@props.suite.description}</div>
|
||||
<div className="results">
|
||||
{items}
|
||||
{subsuites}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
class SpecResultView extends React.Component
|
||||
@propTypes: ->
|
||||
spec: React.PropTypes.object
|
||||
|
||||
render: ->
|
||||
description = @props.spec.description
|
||||
resultItems = @props.spec.results().getItems()
|
||||
description = "it #{description}" if description.indexOf('it ') isnt 0
|
||||
|
||||
failures = []
|
||||
for result, idx in resultItems
|
||||
continue if result.passed()
|
||||
stackTrace = formatStackTrace(@props.spec, result.message, result.trace.stack)
|
||||
failures.push(
|
||||
<div key={idx}>
|
||||
<div className="result-message fail">{result.message}</div>
|
||||
<div className="stack-trace padded">{stackTrace}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
<div className="spec">
|
||||
<div className="description">{description}</div>
|
||||
<div className="spec-failures">{failures}</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
el = document.createElement('div')
|
||||
document.body.appendChild(el)
|
||||
|
||||
startedAt = null
|
||||
specs = []
|
||||
deprecations = []
|
||||
plainTextOutput = ""
|
||||
|
||||
update = =>
|
||||
component = <N1SpecReporter
|
||||
startedAt={startedAt}
|
||||
specs={specs}
|
||||
deprecations={deprecations}
|
||||
/>
|
||||
ReactDOM.render(component, el)
|
||||
|
||||
updateSoon = _.debounce(update, 125)
|
||||
|
||||
module.exports =
|
||||
reportRunnerStarting: (runner) ->
|
||||
specs = runner.specs()
|
||||
startedAt = Date.now()
|
||||
updateSoon()
|
||||
|
||||
reportRunnerResults: (runner) ->
|
||||
updateSoon()
|
||||
|
||||
reportSuiteResults: (suite) ->
|
||||
|
||||
reportSpecResults: (spec) ->
|
||||
spec.endedAt = Date.now()
|
||||
specDeprecations = grim.getDeprecations()
|
||||
d.spec = spec for d in specDeprecations
|
||||
deprecations = deprecations.concat(specDeprecations)
|
||||
grim.clearDeprecations()
|
||||
updateSoon()
|
||||
|
||||
reportPlainTextSpecResult: (spec) ->
|
||||
str = ""
|
||||
if spec.results().failedCount > 0
|
||||
str += suiteString(spec) + "\n"
|
||||
indent = indentationString(spec.suite, 1)
|
||||
stackIndent = indentationString(spec.suite, 2)
|
||||
|
||||
description = spec.description
|
||||
description = "it #{description}" if description.indexOf('it ') isnt 0
|
||||
str += indent + description + "\n"
|
||||
|
||||
for result in spec.results().getItems()
|
||||
continue if result.passed()
|
||||
str += indent + result.message + "\n"
|
||||
stackTrace = formatStackTrace(spec, result.message, result.trace.stack, stackIndent)
|
||||
str += stackTrace + "\n"
|
||||
str += "\n\n"
|
||||
|
||||
plainTextOutput = plainTextOutput + str
|
||||
updateSoon()
|
||||
|
||||
reportSpecStarting: (spec) ->
|
||||
updateSoon()
|
|
@ -1,317 +0,0 @@
|
|||
path = require 'path'
|
||||
_ = require 'underscore'
|
||||
_str = require 'underscore.string'
|
||||
{convertStackTrace} = require 'coffeestack'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
grim = require 'grim'
|
||||
marked = require 'marked'
|
||||
|
||||
sourceMaps = {}
|
||||
formatStackTrace = (spec, message='', stackTrace, indent="") ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
jasminePattern = /^\s*at\s+.*\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
firstJasmineLinePattern = /^\s*at [/\\].*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
convertedLines = []
|
||||
for line in stackTrace.split('\n')
|
||||
convertedLines.push(line) unless jasminePattern.test(line)
|
||||
break if firstJasmineLinePattern.test(line)
|
||||
|
||||
stackTrace = convertStackTrace(convertedLines.join('\n'), sourceMaps)
|
||||
lines = stackTrace.split('\n')
|
||||
|
||||
# Remove first line of stack when it is the same as the error message
|
||||
errorMatch = lines[0]?.match(/^Error: (.*)/)
|
||||
lines.shift() if message.trim() is errorMatch?[1]?.trim()
|
||||
|
||||
for line, index in lines
|
||||
# Remove prefix of lines matching: at [object Object].<anonymous> (path:1:2)
|
||||
prefixMatch = line.match(/at \[object Object\]\.<anonymous> \(([^)]+)\)/)
|
||||
line = "at #{prefixMatch[1]}" if prefixMatch
|
||||
|
||||
# Relativize locations to spec directory
|
||||
lines[index] = line.replace("at #{spec.specDirectory}#{path.sep}", 'at ')
|
||||
|
||||
lines = lines.map (line) -> indent + line.trim()
|
||||
lines.join('\n')
|
||||
|
||||
module.exports =
|
||||
class N1SpecReporter extends View
|
||||
@content: ->
|
||||
@div class: 'spec-reporter', =>
|
||||
@div class: 'padded pull-right', =>
|
||||
@button outlet: 'reloadButton', class: 'btn reload-button', 'Reload Specs'
|
||||
@div outlet: 'coreArea', class: 'symbol-area', =>
|
||||
@div outlet: 'coreHeader', class: 'symbol-header'
|
||||
@ul outlet: 'coreSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'bundledArea', class: 'symbol-area', =>
|
||||
@div outlet: 'bundledHeader', class: 'symbol-header'
|
||||
@ul outlet: 'bundledSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'userArea', class: 'symbol-area', =>
|
||||
@div outlet: 'userHeader', class: 'symbol-header'
|
||||
@ul outlet: 'userSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: "status", class: 'status alert alert-info', =>
|
||||
@div outlet: "time", class: 'time'
|
||||
@div outlet: "specCount", class: 'spec-count'
|
||||
@div outlet: "message", class: 'message'
|
||||
@div outlet: "results", class: 'results'
|
||||
|
||||
@div outlet: "deprecations", class: 'status alert alert-warning', style: 'display: none', =>
|
||||
@span outlet: 'deprecationStatus', '0 deprecations'
|
||||
@div class: 'deprecation-toggle'
|
||||
@div outlet: 'deprecationList', class: 'deprecation-list'
|
||||
@pre outlet: "plainTextOutput", class: 'plain-text-output'
|
||||
|
||||
startedAt: null
|
||||
runningSpecCount: 0
|
||||
completeSpecCount: 0
|
||||
passedCount: 0
|
||||
failedCount: 0
|
||||
skippedCount: 0
|
||||
totalSpecCount: 0
|
||||
deprecationCount: 0
|
||||
@timeoutId: 0
|
||||
|
||||
reportRunnerStarting: (runner) ->
|
||||
@handleEvents()
|
||||
@startedAt = Date.now()
|
||||
specs = runner.specs()
|
||||
@totalSpecCount = specs.length
|
||||
@addSpecs(specs)
|
||||
$(document.body).append this
|
||||
|
||||
@on 'click', '.stack-trace', ->
|
||||
$(this).toggleClass('expanded')
|
||||
|
||||
@reloadButton.on 'click', -> require('electron').ipcRenderer.send('call-webcontents-method', 'reload')
|
||||
|
||||
reportRunnerResults: (runner) ->
|
||||
@updateSpecCounts()
|
||||
@status.addClass('alert-success').removeClass('alert-info') if @failedCount is 0
|
||||
if @failedCount is 1
|
||||
@message.text "#{@failedCount} failure"
|
||||
else
|
||||
@message.text "#{@failedCount} failures"
|
||||
|
||||
@status.addClass("specs-complete")
|
||||
|
||||
reportSuiteResults: (suite) ->
|
||||
|
||||
reportSpecResults: (spec) ->
|
||||
@completeSpecCount++
|
||||
spec.endedAt = Date.now()
|
||||
@specComplete(spec)
|
||||
@updateStatusView(spec)
|
||||
@reportPlainTextSpecResult(spec)
|
||||
|
||||
reportPlainTextSpecResult: (spec) ->
|
||||
str = ""
|
||||
if spec.results().failedCount > 0
|
||||
str += @suiteString(spec) + "\n"
|
||||
indent = @indentationString(spec.suite, 1)
|
||||
stackIndent = @indentationString(spec.suite, 2)
|
||||
|
||||
description = spec.description
|
||||
description = "it #{description}" if description.indexOf('it ') isnt 0
|
||||
str += indent + description + "\n"
|
||||
|
||||
for result in spec.results().getItems()
|
||||
continue if result.passed()
|
||||
str += indent + result.message + "\n"
|
||||
stackTrace = formatStackTrace(spec, result.message, result.trace.stack, stackIndent)
|
||||
str += stackTrace + "\n"
|
||||
str += "\n\n"
|
||||
@plainTextOutput.append(str)
|
||||
|
||||
indentationString: (suite, plus=0) ->
|
||||
rootSuite = suite
|
||||
indentLevel = 0 + plus
|
||||
while rootSuite.parentSuite
|
||||
rootSuite = rootSuite.parentSuite
|
||||
indentLevel += 1
|
||||
return [0...indentLevel].map(-> " ").join("")
|
||||
|
||||
suiteString: (spec) ->
|
||||
descriptions = [spec.suite.description]
|
||||
|
||||
rootSuite = spec.suite
|
||||
while rootSuite.parentSuite
|
||||
indent = @indentationString(rootSuite)
|
||||
descriptions.unshift(indent + rootSuite.description)
|
||||
rootSuite = rootSuite.parentSuite
|
||||
|
||||
descriptions.join("\n")
|
||||
|
||||
reportSpecStarting: (spec) ->
|
||||
@specStarted(spec)
|
||||
|
||||
addDeprecations: (spec) ->
|
||||
deprecations = grim.getDeprecations()
|
||||
@deprecationCount += deprecations.length
|
||||
@deprecations.show() if @deprecationCount > 0
|
||||
if @deprecationCount is 1
|
||||
@deprecationStatus.text("1 deprecation")
|
||||
else
|
||||
@deprecationStatus.text("#{@deprecationCount} deprecations")
|
||||
|
||||
for deprecation in deprecations
|
||||
@deprecationList.append $$ ->
|
||||
@div class: 'padded', =>
|
||||
@div class: 'result-message fail deprecation-message', =>
|
||||
@raw marked(deprecation.message)
|
||||
|
||||
for stack in deprecation.getStacks()
|
||||
fullStack = stack.map ({functionName, location}) ->
|
||||
if functionName is '<unknown>'
|
||||
" at #{location}"
|
||||
else
|
||||
" at #{functionName} (#{location})"
|
||||
@pre class: 'stack-trace padded', formatStackTrace(spec, deprecation.message, fullStack.join('\n'))
|
||||
grim.clearDeprecations()
|
||||
|
||||
handleEvents: ->
|
||||
$(document).on "click", ".spec-toggle", ({currentTarget}) ->
|
||||
element = $(currentTarget)
|
||||
specFailures = element.parent().find('.spec-failures')
|
||||
specFailures.toggle()
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
|
||||
$(document).on "click", ".deprecation-toggle", ({currentTarget}) ->
|
||||
element = $(currentTarget)
|
||||
deprecationList = $(document).find('.deprecation-list')
|
||||
deprecationList.toggle()
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
|
||||
updateSpecCounts: ->
|
||||
if @skippedCount
|
||||
specCount = "#{@completeSpecCount - @skippedCount}/#{@totalSpecCount - @skippedCount} (#{@skippedCount} skipped)"
|
||||
else
|
||||
specCount = "#{@completeSpecCount}/#{@totalSpecCount}"
|
||||
@specCount[0].textContent = specCount
|
||||
|
||||
updateStatusView: (spec) ->
|
||||
if @failedCount > 0
|
||||
@status.addClass('alert-danger').removeClass('alert-info')
|
||||
|
||||
@updateSpecCounts()
|
||||
|
||||
rootSuite = spec.suite
|
||||
rootSuite = rootSuite.parentSuite while rootSuite.parentSuite
|
||||
@message.text rootSuite.description
|
||||
|
||||
time = "#{Math.round((spec.endedAt - @startedAt) / 10)}"
|
||||
time = "0#{time}" if time.length < 3
|
||||
@time[0].textContent = "#{time[0...-2]}.#{time[-2..]}s"
|
||||
|
||||
addSpecs: (specs) ->
|
||||
coreSpecs = 0
|
||||
bundledPackageSpecs = 0
|
||||
userPackageSpecs = 0
|
||||
for spec in specs
|
||||
symbol = $$ -> @li id: "spec-summary-#{spec.id}", class: "spec-summary pending"
|
||||
switch spec.specType
|
||||
when 'core'
|
||||
coreSpecs++
|
||||
@coreSummary.append symbol
|
||||
when 'bundled'
|
||||
bundledPackageSpecs++
|
||||
@bundledSummary.append symbol
|
||||
when 'user'
|
||||
userPackageSpecs++
|
||||
@userSummary.append symbol
|
||||
|
||||
if coreSpecs > 0
|
||||
@coreHeader.text("Core Specs (#{coreSpecs})")
|
||||
else
|
||||
@coreArea.hide()
|
||||
if bundledPackageSpecs > 0
|
||||
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs})")
|
||||
else
|
||||
@bundledArea.hide()
|
||||
if userPackageSpecs > 0
|
||||
if coreSpecs is 0 and bundledPackageSpecs is 0
|
||||
# Package specs being run, show a more descriptive label
|
||||
{specDirectory} = specs[0]
|
||||
packageFolderName = path.basename(path.dirname(specDirectory))
|
||||
packageName = _str.humanize(packageFolderName)
|
||||
@userHeader.text("#{packageName} Specs")
|
||||
else
|
||||
@userHeader.text("User Package Specs (#{userPackageSpecs})")
|
||||
else
|
||||
@userArea.hide()
|
||||
|
||||
specStarted: (spec) ->
|
||||
@runningSpecCount++
|
||||
|
||||
specComplete: (spec) ->
|
||||
specSummaryElement = $("#spec-summary-#{spec.id}")
|
||||
specSummaryElement.removeClass('pending')
|
||||
specSummaryElement.attr('title', spec.getFullName())
|
||||
|
||||
results = spec.results()
|
||||
if results.skipped
|
||||
specSummaryElement.addClass("skipped")
|
||||
@skippedCount++
|
||||
else if results.passed()
|
||||
specSummaryElement.addClass("passed")
|
||||
@passedCount++
|
||||
else
|
||||
specSummaryElement.addClass("failed")
|
||||
|
||||
specView = new SpecResultView(spec)
|
||||
specView.attach()
|
||||
@failedCount++
|
||||
@addDeprecations(spec)
|
||||
|
||||
class SuiteResultView extends View
|
||||
@content: ->
|
||||
@div class: 'suite', =>
|
||||
@div outlet: 'description', class: 'description'
|
||||
|
||||
initialize: (@suite) ->
|
||||
@attr('id', "suite-view-#{@suite.id}")
|
||||
@description.text(@suite.description)
|
||||
|
||||
attach: ->
|
||||
(@parentSuiteView() or $('.results')).append this
|
||||
|
||||
parentSuiteView: ->
|
||||
return unless @suite.parentSuite
|
||||
|
||||
if not suiteView = $("#suite-view-#{@suite.parentSuite.id}").view()
|
||||
suiteView = new SuiteResultView(@suite.parentSuite)
|
||||
suiteView.attach()
|
||||
|
||||
suiteView
|
||||
|
||||
class SpecResultView extends View
|
||||
@content: ->
|
||||
@div class: 'spec', =>
|
||||
@div class: 'spec-toggle'
|
||||
@div outlet: 'description', class: 'description'
|
||||
@div outlet: 'specFailures', class: 'spec-failures'
|
||||
|
||||
initialize: (@spec) ->
|
||||
@addClass("spec-view-#{@spec.id}")
|
||||
|
||||
description = @spec.description
|
||||
description = "it #{description}" if description.indexOf('it ') isnt 0
|
||||
@description.text(description)
|
||||
|
||||
for result in @spec.results().getItems() when not result.passed()
|
||||
stackTrace = formatStackTrace(@spec, result.message, result.trace.stack)
|
||||
@specFailures.append $$ ->
|
||||
@div result.message, class: 'result-message fail'
|
||||
@pre stackTrace, class: 'stack-trace padded' if stackTrace
|
||||
|
||||
attach: ->
|
||||
@parentSuiteView().append this
|
||||
|
||||
parentSuiteView: ->
|
||||
if not suiteView = $("#suite-view-#{@spec.suite.id}").view()
|
||||
suiteView = new SuiteResultView(@spec.suite)
|
||||
suiteView.attach()
|
||||
|
||||
suiteView
|
|
@ -456,9 +456,9 @@ describe "PackageManager", ->
|
|||
one = require.resolve("./fixtures/packages/package-with-style-sheets-manifest/styles/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-style-sheets-manifest/styles/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-style-sheets-manifest/styles/3.css")
|
||||
expect(NylasEnv.themes.stylesheetElementForId(one)).not.toExist()
|
||||
expect(NylasEnv.themes.stylesheetElementForId(two)).not.toExist()
|
||||
expect(NylasEnv.themes.stylesheetElementForId(three)).not.toExist()
|
||||
expect(NylasEnv.themes.stylesheetElementForId(one)).toBe(null)
|
||||
expect(NylasEnv.themes.stylesheetElementForId(two)).toBe(null)
|
||||
expect(NylasEnv.themes.stylesheetElementForId(three)).toBe(null)
|
||||
|
||||
it "invokes ::onDidDeactivatePackage listeners with the deactivated package", ->
|
||||
waitsForPromise ->
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
{$} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
ThemePackage = require '../src/theme-package'
|
||||
|
@ -41,51 +40,57 @@ describe "Package", ->
|
|||
theme = null
|
||||
|
||||
beforeEach ->
|
||||
$("#jasmine-content").append $("<nylas-theme-wrap></nylas-theme-wrap>")
|
||||
@wrap = document.createElement('nylas-theme-wrap')
|
||||
document.getElementById("jasmine-content").appendChild(@wrap)
|
||||
|
||||
afterEach ->
|
||||
theme.deactivate() if theme?
|
||||
|
||||
describe "when the theme contains a single style file", ->
|
||||
it "loads and applies css", ->
|
||||
expect($("nylas-theme-wrap").css("padding-bottom")).not.toBe "1234px"
|
||||
|
||||
expect(window.getComputedStyle(@wrap)['padding-bottom']).not.toBe "1234px"
|
||||
themePath = resolveFixturePath('theme-with-index-css')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("nylas-theme-wrap").css("padding-top")).toBe "1234px"
|
||||
expect(window.getComputedStyle(@wrap)['padding-top']).toBe "1234px"
|
||||
|
||||
it "parses, loads and applies less", ->
|
||||
expect($("nylas-theme-wrap").css("padding-bottom")).not.toBe "1234px"
|
||||
expect(window.getComputedStyle(@wrap)['padding-bottom']).not.toBe "1234px"
|
||||
themePath = resolveFixturePath('theme-with-index-less')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("nylas-theme-wrap").css("padding-top")).toBe "4321px"
|
||||
expect(window.getComputedStyle(@wrap)['padding-top']).toBe "4321px"
|
||||
|
||||
describe "when the theme contains a package.json file", ->
|
||||
it "loads and applies stylesheets from package.json in the correct order", ->
|
||||
expect($("nylas-theme-wrap").css("padding-top")).not.toBe("101px")
|
||||
expect($("nylas-theme-wrap").css("padding-right")).not.toBe("102px")
|
||||
expect($("nylas-theme-wrap").css("padding-bottom")).not.toBe("103px")
|
||||
styles = window.getComputedStyle(@wrap)
|
||||
expect(styles["padding-top"]).not.toBe("101px")
|
||||
expect(styles["padding-right"]).not.toBe("102px")
|
||||
expect(styles["padding-bottom"]).not.toBe("103px")
|
||||
|
||||
themePath = resolveFixturePath('theme-with-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("nylas-theme-wrap").css("padding-top")).toBe("101px")
|
||||
expect($("nylas-theme-wrap").css("padding-right")).toBe("102px")
|
||||
expect($("nylas-theme-wrap").css("padding-bottom")).toBe("103px")
|
||||
styles = window.getComputedStyle(@wrap)
|
||||
expect(styles["padding-top"]).toBe("101px")
|
||||
expect(styles["padding-right"]).toBe("102px")
|
||||
expect(styles["padding-bottom"]).toBe("103px")
|
||||
|
||||
describe "when the theme does not contain a package.json file and is a directory", ->
|
||||
it "loads all stylesheet files in the directory", ->
|
||||
expect($("nylas-theme-wrap").css("padding-top")).not.toBe "10px"
|
||||
expect($("nylas-theme-wrap").css("padding-right")).not.toBe "20px"
|
||||
expect($("nylas-theme-wrap").css("padding-bottom")).not.toBe "30px"
|
||||
styles = window.getComputedStyle(@wrap)
|
||||
expect(styles["padding-top"]).not.toBe("10px")
|
||||
expect(styles["padding-right"]).not.toBe("20px")
|
||||
expect(styles["padding-bottom"]).not.toBe("30px")
|
||||
|
||||
themePath = resolveFixturePath('theme-without-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("nylas-theme-wrap").css("padding-top")).toBe "10px"
|
||||
expect($("nylas-theme-wrap").css("padding-right")).toBe "20px"
|
||||
expect($("nylas-theme-wrap").css("padding-bottom")).toBe "30px"
|
||||
styles = window.getComputedStyle(@wrap)
|
||||
expect(styles["padding-top"]).toBe("10px")
|
||||
expect(styles["padding-right"]).toBe("20px")
|
||||
expect(styles["padding-bottom"]).toBe("30px")
|
||||
|
||||
describe "reloading a theme", ->
|
||||
beforeEach ->
|
||||
|
|
|
@ -7,15 +7,11 @@ require '../src/window'
|
|||
NylasEnv.restoreWindowDimensions()
|
||||
|
||||
require 'jasmine-json'
|
||||
require './jasmine-jquery'
|
||||
|
||||
Grim = require 'grim'
|
||||
TimeOverride = require './time-override'
|
||||
KeymapManager = require '../src/keymap-manager'
|
||||
|
||||
# FIXME: Remove jquery from this
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
|
||||
Config = require '../src/config'
|
||||
pathwatcher = require 'pathwatcher'
|
||||
{clipboard} = require 'electron'
|
||||
|
@ -40,7 +36,9 @@ window.addEventListener 'core:close', -> window.close()
|
|||
window.addEventListener 'beforeunload', ->
|
||||
NylasEnv.storeWindowDimensions()
|
||||
NylasEnv.saveSync()
|
||||
$('html,body').css('overflow', 'auto')
|
||||
|
||||
document.querySelector('html').style.overflow = 'initial'
|
||||
document.querySelector('body').style.overflow = 'initial'
|
||||
|
||||
# Allow document.title to be assigned in specs without screwing up spec window title
|
||||
documentTitle = null
|
||||
|
@ -142,7 +140,6 @@ beforeEach ->
|
|||
TaskQueue._completed = []
|
||||
TaskQueue._onlineStatus = true
|
||||
|
||||
$.fx.off = true
|
||||
documentTitle = null
|
||||
NylasEnv.styles.restoreSnapshot(styleElementsToRestore)
|
||||
NylasEnv.workspaceViewParentSelector = '#jasmine-content'
|
||||
|
@ -243,8 +240,8 @@ afterEach ->
|
|||
|
||||
delete NylasEnv.state?.packageStates
|
||||
|
||||
$('#jasmine-content').empty() unless window.debugContent
|
||||
|
||||
unless window.debugContent
|
||||
document.getElementById('jasmine-content').innerHTML = ''
|
||||
ReactTestUtils.unmountAll()
|
||||
|
||||
jasmine.unspy(NylasEnv, 'saveSync')
|
||||
|
@ -354,8 +351,8 @@ window.keydownEvent = (key, properties={}) ->
|
|||
originalEventProperties.target = properties.target?[0] ? properties.target
|
||||
originalEventProperties.which = properties.which
|
||||
originalEvent = KeymapManager.keydownEvent(key, originalEventProperties)
|
||||
properties = $.extend({originalEvent}, properties)
|
||||
$.Event("keydown", properties)
|
||||
properties = _.extend({originalEvent}, properties)
|
||||
new CustomEvent('keydown', properties)
|
||||
|
||||
window.mouseEvent = (type, properties) ->
|
||||
if properties.point
|
||||
|
@ -364,7 +361,7 @@ window.mouseEvent = (type, properties) ->
|
|||
properties.pageX = left + 1
|
||||
properties.pageY = top + 1
|
||||
properties.originalEvent ?= {detail: 1}
|
||||
$.Event type, properties
|
||||
new CustomEvent(type, properties)
|
||||
|
||||
window.clickEvent = (properties={}) ->
|
||||
window.mouseEvent("click", properties)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
path = require 'path'
|
||||
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
|
||||
|
@ -101,7 +100,7 @@ describe "ThemeManager", ->
|
|||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style.theme')).toHaveLength 0
|
||||
expect(document.querySelectorAll('style.theme')).toHaveLength 0
|
||||
NylasEnv.config.set('core.themes', ['ui-dark'])
|
||||
|
||||
waitsFor ->
|
||||
|
@ -109,8 +108,9 @@ describe "ThemeManager", ->
|
|||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style[priority=1]')).toHaveLength 1
|
||||
expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /ui-dark/
|
||||
sheets = Array.from(document.querySelectorAll('style[priority="1"]'))
|
||||
expect(sheets).toHaveLength 1
|
||||
expect(sheets[0].getAttribute('source-path')).toMatch /ui-dark/
|
||||
NylasEnv.config.set('core.themes', ['ui-light', 'ui-dark'])
|
||||
|
||||
waitsFor ->
|
||||
|
@ -118,9 +118,10 @@ describe "ThemeManager", ->
|
|||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /ui-dark/
|
||||
expect($('style[priority=1]:eq(1)').attr('source-path')).toMatch /ui-light/
|
||||
sheets = Array.from(document.querySelectorAll('style[priority="1"]'))
|
||||
expect(sheets).toHaveLength 2
|
||||
expect(sheets[0].getAttribute('source-path')).toMatch /ui-dark/
|
||||
expect(sheets[1].getAttribute('source-path')).toMatch /ui-light/
|
||||
NylasEnv.config.set('core.themes', [])
|
||||
|
||||
waitsFor ->
|
||||
|
@ -128,7 +129,8 @@ describe "ThemeManager", ->
|
|||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style[priority=1]')).toHaveLength(1)
|
||||
sheets = Array.from(document.querySelectorAll('style[priority="1"]'))
|
||||
expect(sheets).toHaveLength(1)
|
||||
# ui-dark has an directory path, the syntax one doesn't
|
||||
NylasEnv.config.set('core.themes', ['theme-with-index-less', 'ui-light'])
|
||||
|
||||
|
@ -136,7 +138,8 @@ describe "ThemeManager", ->
|
|||
didChangeActiveThemesHandler.callCount == 1
|
||||
|
||||
runs ->
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
sheets = Array.from(document.querySelectorAll('style[priority="1"]'))
|
||||
expect(sheets).toHaveLength 2
|
||||
importPaths = themeManager.getImportPaths()
|
||||
expect(importPaths.length).toBe 1
|
||||
expect(importPaths[0]).toContain 'ui-light'
|
||||
|
@ -151,7 +154,7 @@ describe "ThemeManager", ->
|
|||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
expect(workspaceElement).toHaveClass 'theme-ui-light'
|
||||
expect(workspaceElement.classList.contains('theme-ui-light')).toBe(true)
|
||||
|
||||
themeManager.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
NylasEnv.config.set('core.themes', ['theme-with-ui-variables'])
|
||||
|
@ -161,8 +164,8 @@ describe "ThemeManager", ->
|
|||
|
||||
runs ->
|
||||
# `theme-` twice as it prefixes the name with `theme-`
|
||||
expect(workspaceElement).toHaveClass 'theme-theme-with-ui-variables'
|
||||
expect(workspaceElement).not.toHaveClass 'theme-ui-dark'
|
||||
expect(workspaceElement.classList.contains('theme-theme-with-ui-variables')).toBe(true)
|
||||
expect(workspaceElement.classList.contains('theme-ui-dark')).toBe(false)
|
||||
|
||||
describe "when a theme fails to load", ->
|
||||
it "logs a warning", ->
|
||||
|
@ -183,37 +186,37 @@ describe "ThemeManager", ->
|
|||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
|
||||
cssPath = path.join(__dirname, 'fixtures', 'css.css')
|
||||
lengthBefore = $('head style').length
|
||||
lengthBefore = document.querySelectorAll('head style').length
|
||||
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
element = $('head style[source-path*="css.css"]')
|
||||
expect(element.attr('source-path')).toBe themeManager.stringToId(cssPath)
|
||||
expect(element.text()).toBe fs.readFileSync(cssPath, 'utf8')
|
||||
expect(element[0].sheet).toBe stylesheetAddedHandler.argsForCall[0][0]
|
||||
element = document.querySelector('head style[source-path*="css.css"]')
|
||||
expect(element.getAttribute('source-path')).toBe themeManager.stringToId(cssPath)
|
||||
expect(element.textContent).toBe fs.readFileSync(cssPath, 'utf8')
|
||||
|
||||
# doesn't append twice
|
||||
styleElementAddedHandler.reset()
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
expect(styleElementAddedHandler).not.toHaveBeenCalled()
|
||||
|
||||
$('head style[id*="css.css"]').remove()
|
||||
element .remove()
|
||||
|
||||
it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", ->
|
||||
lessPath = path.join(__dirname, 'fixtures', 'sample.less')
|
||||
lengthBefore = $('head style').length
|
||||
lengthBefore = document.querySelectorAll('head style').length
|
||||
themeManager.requireStylesheet(lessPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
lengthAfter = document.querySelectorAll('head style').length
|
||||
expect(lengthAfter).toBe lengthBefore + 1
|
||||
|
||||
element = $('head style[source-path*="sample.less"]')
|
||||
expect(element.attr('source-path')).toBe themeManager.stringToId(lessPath)
|
||||
expect(element.text()).toBe """
|
||||
element = document.querySelector('head style[source-path*="sample.less"]')
|
||||
expect(element.getAttribute('source-path')).toBe themeManager.stringToId(lessPath)
|
||||
expect(element.textContent).toBe """
|
||||
#header {
|
||||
color: #4d926f;
|
||||
}
|
||||
|
@ -225,24 +228,24 @@ describe "ThemeManager", ->
|
|||
|
||||
# doesn't append twice
|
||||
themeManager.requireStylesheet(lessPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
$('head style[id*="sample.less"]').remove()
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
element.remove()
|
||||
|
||||
it "supports requiring css and less stylesheets without an explicit extension", ->
|
||||
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'css')
|
||||
expect($('head style[source-path*="css.css"]').attr('source-path')).toBe themeManager.stringToId(path.join(__dirname, 'fixtures', 'css.css'))
|
||||
expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')).toBe themeManager.stringToId(path.join(__dirname, 'fixtures', 'css.css'))
|
||||
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'sample')
|
||||
expect($('head style[source-path*="sample.less"]').attr('source-path')).toBe themeManager.stringToId(path.join(__dirname, 'fixtures', 'sample.less'))
|
||||
expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')).toBe themeManager.stringToId(path.join(__dirname, 'fixtures', 'sample.less'))
|
||||
|
||||
$('head style[id*="css.css"]').remove()
|
||||
$('head style[id*="sample.less"]').remove()
|
||||
document.querySelector('head style[source-path*="css.css"]').remove()
|
||||
document.querySelector('head style[source-path*="sample.less"]').remove()
|
||||
|
||||
it "returns a disposable allowing styles applied by the given path to be removed", ->
|
||||
cssPath = require.resolve('./fixtures/css.css')
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
expect(window.getComputedStyle(document.body)['font-weight']).not.toBe("bold")
|
||||
disposable = themeManager.requireStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).toBe("bold")
|
||||
expect(window.getComputedStyle(document.body)['font-weight']).toBe("bold")
|
||||
|
||||
NylasEnv.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
|
@ -250,7 +253,7 @@ describe "ThemeManager", ->
|
|||
|
||||
disposable.dispose()
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
expect(window.getComputedStyle(document.body)['font-weight']).not.toBe("bold")
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
|
@ -291,9 +294,11 @@ describe "ThemeManager", ->
|
|||
expect(getComputedStyle(workspaceElement)["background-color"]).toBe "rgb(0, 0, 255)"
|
||||
|
||||
# a value that is not overridden in the theme
|
||||
expect($("nylas-theme-wrap").css("padding-top")).toBe "150px"
|
||||
expect($("nylas-theme-wrap").css("padding-right")).toBe "150px"
|
||||
expect($("nylas-theme-wrap").css("padding-bottom")).toBe "150px"
|
||||
node = document.querySelector('nylas-theme-wrap')
|
||||
nodeStyle = window.getComputedStyle(node)
|
||||
expect(nodeStyle['padding-top']).toBe "150px"
|
||||
expect(nodeStyle['padding-right']).toBe "150px"
|
||||
expect(nodeStyle['padding-bottom']).toBe "150px"
|
||||
|
||||
describe "when there is a theme with incomplete variables", ->
|
||||
it "loads the correct values from the fallback ui-variables", ->
|
||||
|
@ -304,8 +309,10 @@ describe "ThemeManager", ->
|
|||
# an override loaded in the base css of theme-with-incomplete-ui-variables
|
||||
expect(getComputedStyle(workspaceElement)["background-color"]).toBe "rgb(0, 0, 255)"
|
||||
|
||||
# a value that is not overridden in the theme
|
||||
expect($("nylas-theme-wrap").css("background-color")).toBe "rgb(152, 123, 0)"
|
||||
# a value that is not overridden in the theme
|
||||
node = document.querySelector('nylas-theme-wrap')
|
||||
nodeStyle = window.getComputedStyle(node)
|
||||
expect(nodeStyle['background-color']).toBe "rgb(152, 123, 0)"
|
||||
|
||||
describe "user stylesheet", ->
|
||||
userStylesheetPath = null
|
||||
|
@ -337,14 +344,16 @@ describe "ThemeManager", ->
|
|||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
bodyStyle = window.getComputedStyle(document.body)
|
||||
expect(bodyStyle['border-style']).toBe "dotted"
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
bodyStyle = window.getComputedStyle(document.body)
|
||||
expect(bodyStyle['border-style']).toBe "dashed"
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dotted'
|
||||
|
@ -382,7 +391,9 @@ describe "ThemeManager", ->
|
|||
match = null
|
||||
for rule in stylesheetRemovedHandler.argsForCall[0][0].cssRules
|
||||
match = rule if rule.selectorText is 'body'
|
||||
match.style.border is 'dashed' and $(document.body).css('border-style') is 'none'
|
||||
|
||||
bodyStyle = window.getComputedStyle(document.body)
|
||||
match.style.border is 'dashed' and bodyStyle['border-style'] is 'none'
|
||||
|
||||
runs ->
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
_ = require 'underscore'
|
||||
_ = _.extend(_, require('./space-pen-utils'))
|
||||
SpacePen = require 'space-pen'
|
||||
{Subscriber} = require 'emissary'
|
||||
|
||||
###
|
||||
Edgehill Note:
|
||||
|
||||
I want this file gone—plan is to slowly delete stuff below as we clean spacepen
|
||||
and it's helpers out of the project.
|
||||
|
||||
- Ben
|
||||
###
|
||||
|
||||
|
||||
Subscriber.includeInto(SpacePen.View)
|
||||
|
||||
jQuery = SpacePen.jQuery
|
||||
JQueryCleanData = jQuery.cleanData
|
||||
jQuery.cleanData = (elements) ->
|
||||
jQuery(element).view()?.unsubscribe?() for element in elements
|
||||
JQueryCleanData(elements)
|
||||
|
||||
SpacePenCallRemoveHooks = SpacePen.callRemoveHooks
|
||||
SpacePen.callRemoveHooks = (element) ->
|
||||
view.unsubscribe?() for view in SpacePen.viewsForElement(element)
|
||||
SpacePenCallRemoveHooks(element)
|
||||
|
||||
NativeEventNames = new Set
|
||||
NativeEventNames.add(nativeEvent) for nativeEvent in ["blur", "focus", "focusin",
|
||||
"focusout", "load", "resize", "scroll", "unload", "click", "dblclick", "mousedown",
|
||||
"mouseup", "mousemove", "mouseover", "mouseout", "mouseenter", "mouseleave", "change",
|
||||
"select", "submit", "keydown", "keypress", "keyup", "error", "contextmenu", "textInput",
|
||||
"textinput", "beforeunload"]
|
||||
|
||||
JQueryTrigger = jQuery.fn.trigger
|
||||
jQuery.fn.trigger = (eventName, data) ->
|
||||
if NativeEventNames.has(eventName) or typeof eventName is 'object'
|
||||
JQueryTrigger.call(this, eventName, data)
|
||||
else
|
||||
data ?= {}
|
||||
data.jQueryTrigger = true
|
||||
|
||||
for element in this
|
||||
NylasEnv.commands.dispatch(eventName, data)
|
||||
this
|
||||
|
||||
HandlersByOriginalHandler = new WeakMap
|
||||
CommandDisposablesByElement = new WeakMap
|
||||
|
||||
AddEventListener = (element, type, listener) ->
|
||||
if NativeEventNames.has(type)
|
||||
element.addEventListener(type, listener)
|
||||
else
|
||||
disposable = NylasEnv.commands.add(element, type, listener)
|
||||
|
||||
unless disposablesByType = CommandDisposablesByElement.get(element)
|
||||
disposablesByType = {}
|
||||
CommandDisposablesByElement.set(element, disposablesByType)
|
||||
|
||||
unless disposablesByListener = disposablesByType[type]
|
||||
disposablesByListener = new WeakMap
|
||||
disposablesByType[type] = disposablesByListener
|
||||
|
||||
disposablesByListener.set(listener, disposable)
|
||||
|
||||
RemoveEventListener = (element, type, listener) ->
|
||||
if NativeEventNames.has(type)
|
||||
element.removeEventListener(type, listener)
|
||||
else
|
||||
CommandDisposablesByElement.get(element)?[type]?.get(listener)?.dispose()
|
||||
|
||||
JQueryEventAdd = jQuery.event.add
|
||||
jQuery.event.add = (elem, types, originalHandler, data, selector) ->
|
||||
handler = (event) ->
|
||||
if arguments.length is 1 and event.originalEvent?.detail?
|
||||
{detail} = event.originalEvent
|
||||
if Array.isArray(detail)
|
||||
originalHandler.apply(this, [event].concat(detail))
|
||||
else
|
||||
originalHandler.call(this, event, detail)
|
||||
else
|
||||
originalHandler.apply(this, arguments)
|
||||
|
||||
HandlersByOriginalHandler.set(originalHandler, handler)
|
||||
|
||||
JQueryEventAdd.call(this, elem, types, handler, data, selector, AddEventListener if NylasEnv?.commands?)
|
||||
|
||||
JQueryEventRemove = jQuery.event.remove
|
||||
jQuery.event.remove = (elem, types, originalHandler, selector, mappedTypes) ->
|
||||
if originalHandler?
|
||||
handler = HandlersByOriginalHandler.get(originalHandler) ? originalHandler
|
||||
JQueryEventRemove(elem, types, handler, selector, mappedTypes, RemoveEventListener if NylasEnv?.commands?)
|
||||
|
||||
JQueryContains = jQuery.contains
|
||||
|
||||
jQuery.contains = (a, b) ->
|
||||
shadowRoot = null
|
||||
currentNode = b
|
||||
while currentNode
|
||||
if currentNode instanceof ShadowRoot and a.contains(currentNode.host)
|
||||
return true
|
||||
currentNode = currentNode.parentNode
|
||||
|
||||
JQueryContains.call(this, a, b)
|
||||
|
||||
Object.defineProperty jQuery.fn, 'element', get: -> @[0]
|
||||
|
||||
module.exports = SpacePen
|
Loading…
Reference in a new issue