mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Merge pull request #4378 from GeoffreyBooth/fix-browser-tests
Fix browser tests
This commit is contained in:
commit
5588658641
7 changed files with 256 additions and 221 deletions
168
Cakefile
168
Cakefile
|
@ -45,60 +45,6 @@ run = (args, cb) ->
|
|||
log = (message, color, explanation) ->
|
||||
console.log color + message + reset + ' ' + (explanation or '')
|
||||
|
||||
codeFor = ->
|
||||
counter = 0
|
||||
hljs = require 'highlight.js'
|
||||
hljs.configure classPrefix: ''
|
||||
(file, executable = false, showLoad = true) ->
|
||||
counter++
|
||||
return unless fs.existsSync "docs/v#{majorVersion}/examples/#{file}.js"
|
||||
cs = fs.readFileSync "documentation/examples/#{file}.coffee", 'utf-8'
|
||||
js = fs.readFileSync "docs/v#{majorVersion}/examples/#{file}.js", 'utf-8'
|
||||
js = js.replace /^\/\/ generated.*?\n/i, ''
|
||||
|
||||
cshtml = "<pre><code>#{hljs.highlight('coffeescript', cs).value}</code></pre>"
|
||||
# Temporary fix until highlight.js adds support for newer CoffeeScript keywords
|
||||
# Added in https://github.com/isagalaev/highlight.js/pull/1357, awaiting release
|
||||
if file in ['generator_iteration', 'generators', 'modules']
|
||||
cshtml = cshtml.replace /(yield|import|export|from|as|default) /g, '<span class="keyword">$1</span> '
|
||||
jshtml = "<pre><code>#{hljs.highlight('javascript', js).value}</code></pre>"
|
||||
append = if executable is yes then '' else "alert(#{executable});"
|
||||
if executable and executable isnt yes
|
||||
cs.replace /(\S)\s*\Z/m, "$1\n\nalert #{executable}"
|
||||
run = if executable is true then 'run' else "run: #{executable}"
|
||||
name = "example#{counter}"
|
||||
script = "<script>window.#{name} = #{JSON.stringify cs}</script>"
|
||||
load = if showLoad then "<div class='minibutton load' onclick='javascript: loadConsole(#{name});'>load</div>" else ''
|
||||
button = if executable then "<div class='minibutton ok' onclick='javascript: #{js};#{append}'>#{run}</div>" else ''
|
||||
"<div class='code'>#{cshtml}#{jshtml}#{script}#{load}#{button}<br class='clear' /></div>"
|
||||
|
||||
monthNames = [
|
||||
'January'
|
||||
'February'
|
||||
'March'
|
||||
'April'
|
||||
'May'
|
||||
'June'
|
||||
'July'
|
||||
'August'
|
||||
'September'
|
||||
'October'
|
||||
'November'
|
||||
'December'
|
||||
]
|
||||
|
||||
formatDate = (date) ->
|
||||
date.replace /^(\d\d\d\d)-(\d\d)-(\d\d)$/, (match, $1, $2, $3) ->
|
||||
"#{monthNames[$2 - 1]} #{+$3}, #{$1}"
|
||||
|
||||
releaseHeader = (date, version, prevVersion) -> """
|
||||
<div class="anchor" id="#{version}"></div>
|
||||
<b class="header">
|
||||
#{prevVersion and "<a href=\"https://github.com/jashkenas/coffeescript/compare/#{prevVersion}...#{version}\">#{version}</a>" or version}
|
||||
<span class="timestamp"> — <time datetime="#{date}">#{formatDate date}</time></span>
|
||||
</b>
|
||||
"""
|
||||
|
||||
option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`'
|
||||
|
||||
task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options) ->
|
||||
|
@ -137,7 +83,7 @@ task 'build:full', 'rebuild the source twice, and run the tests', ->
|
|||
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
helpers.extend global, require('util')
|
||||
helpers.extend global, require 'util'
|
||||
require 'jison'
|
||||
parser = require('./lib/coffee-script/grammar').parser
|
||||
fs.writeFileSync 'lib/coffee-script/parser.js', parser.generate()
|
||||
|
@ -182,13 +128,93 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
|||
|
||||
|
||||
task 'doc:site', 'watch and continually rebuild the documentation for the website', ->
|
||||
# Helpers
|
||||
codeFor = ->
|
||||
counter = 0
|
||||
hljs = require 'highlight.js'
|
||||
hljs.configure classPrefix: ''
|
||||
(file, executable = false, showLoad = true) ->
|
||||
counter++
|
||||
return unless fs.existsSync "docs/v#{majorVersion}/examples/#{file}.js"
|
||||
cs = fs.readFileSync "documentation/examples/#{file}.coffee", 'utf-8'
|
||||
js = fs.readFileSync "docs/v#{majorVersion}/examples/#{file}.js", 'utf-8'
|
||||
js = js.replace /^\/\/ generated.*?\n/i, ''
|
||||
|
||||
cshtml = "<pre><code>#{hljs.highlight('coffeescript', cs).value}</code></pre>"
|
||||
# Temporary fix until highlight.js adds support for newer CoffeeScript keywords
|
||||
# Added in https://github.com/isagalaev/highlight.js/pull/1357, awaiting release
|
||||
if file in ['generator_iteration', 'generators', 'modules']
|
||||
cshtml = cshtml.replace /(yield|import|export|from|as|default) /g, '<span class="keyword">$1</span> '
|
||||
jshtml = "<pre><code>#{hljs.highlight('javascript', js).value}</code></pre>"
|
||||
append = if executable is yes then '' else "alert(#{executable});"
|
||||
if executable and executable isnt yes
|
||||
cs.replace /(\S)\s*\Z/m, "$1\n\nalert #{executable}"
|
||||
run = if executable is true then 'run' else "run: #{executable}"
|
||||
name = "example#{counter}"
|
||||
script = "<script>window.#{name} = #{JSON.stringify cs}</script>"
|
||||
load = if showLoad then "<div class='minibutton load' onclick='javascript: loadConsole(#{name});'>load</div>" else ''
|
||||
button = if executable then "<div class='minibutton ok' onclick='javascript: #{js};#{append}'>#{run}</div>" else ''
|
||||
"<div class='code'>#{cshtml}#{jshtml}#{script}#{load}#{button}<br class='clear' /></div>"
|
||||
|
||||
monthNames = [
|
||||
'January'
|
||||
'February'
|
||||
'March'
|
||||
'April'
|
||||
'May'
|
||||
'June'
|
||||
'July'
|
||||
'August'
|
||||
'September'
|
||||
'October'
|
||||
'November'
|
||||
'December'
|
||||
]
|
||||
|
||||
formatDate = (date) ->
|
||||
date.replace /^(\d\d\d\d)-(\d\d)-(\d\d)$/, (match, $1, $2, $3) ->
|
||||
"#{monthNames[$2 - 1]} #{+$3}, #{$1}"
|
||||
|
||||
releaseHeader = (date, version, prevVersion) -> """
|
||||
<div class="anchor" id="#{version}"></div>
|
||||
<b class="header">
|
||||
#{prevVersion and "<a href=\"https://github.com/jashkenas/coffeescript/compare/#{prevVersion}...#{version}\">#{version}</a>" or version}
|
||||
<span class="timestamp"> — <time datetime="#{date}">#{formatDate date}</time></span>
|
||||
</b>
|
||||
"""
|
||||
|
||||
testHelpers = fs.readFileSync('test/support/helpers.coffee', 'utf-8').replace /exports\./g, '@'
|
||||
|
||||
testsInScriptBlocks = ->
|
||||
output = ''
|
||||
excludedTestFiles = ['error_messages.coffee']
|
||||
for filename in fs.readdirSync 'test'
|
||||
continue if filename in excludedTestFiles
|
||||
|
||||
if filename.indexOf('.coffee') isnt -1
|
||||
type = 'coffeescript'
|
||||
else if filename.indexOf('.litcoffee') isnt -1
|
||||
type = 'literate-coffeescript'
|
||||
else
|
||||
continue
|
||||
|
||||
# Set the type to text/x-coffeescript or text/x-literate-coffeescript
|
||||
# to prevent the browser compiler from automatically running the script
|
||||
output += """
|
||||
<script type="text/x-#{type}" class="test" id="#{filename.split('.')[0]}">
|
||||
#{fs.readFileSync "test/#{filename}", 'utf-8'}
|
||||
</script>\n
|
||||
"""
|
||||
output
|
||||
|
||||
# Task
|
||||
examplesSourceFolder = 'documentation/examples'
|
||||
examplesOutputFolder = "docs/v#{majorVersion}/examples"
|
||||
fs.mkdirSync examplesOutputFolder unless fs.existsSync examplesOutputFolder
|
||||
do renderExamples = ->
|
||||
execSync "bin/coffee -bc -o #{examplesOutputFolder} #{examplesSourceFolder}/*.coffee"
|
||||
|
||||
indexFile = 'documentation/index.html.js'
|
||||
indexFile = 'documentation/index.html'
|
||||
do renderIndex = ->
|
||||
render = _.template fs.readFileSync(indexFile, 'utf-8')
|
||||
output = render
|
||||
|
@ -198,10 +224,22 @@ task 'doc:site', 'watch and continually rebuild the documentation for the websit
|
|||
fs.writeFileSync "docs/v#{majorVersion}/index.html", output
|
||||
log 'compiled', green, "#{indexFile} → docs/v#{majorVersion}/index.html"
|
||||
|
||||
testFile = 'documentation/test.html'
|
||||
do renderTest = ->
|
||||
render = _.template fs.readFileSync(testFile, 'utf-8')
|
||||
output = render
|
||||
testHelpers: testHelpers
|
||||
tests: testsInScriptBlocks()
|
||||
majorVersion: majorVersion
|
||||
fs.writeFileSync "docs/v#{majorVersion}/test.html", output
|
||||
log 'compiled', green, "#{testFile} → docs/v#{majorVersion}/test.html"
|
||||
|
||||
fs.watch examplesSourceFolder, interval: 200, ->
|
||||
renderExamples()
|
||||
renderIndex()
|
||||
fs.watch indexFile, interval: 200, renderIndex
|
||||
fs.watch testFile, interval: 200, renderTest
|
||||
fs.watch 'test', interval: 200, renderTest
|
||||
log 'watching...' , green
|
||||
|
||||
|
||||
|
@ -258,23 +296,7 @@ runTests = (CoffeeScript) ->
|
|||
description: description if description?
|
||||
source: fn.toString() if fn.toString?
|
||||
|
||||
# See http://wiki.ecmascript.org/doku.php?id=harmony:egal
|
||||
egal = (a, b) ->
|
||||
if a is b
|
||||
a isnt 0 or 1/a is 1/b
|
||||
else
|
||||
a isnt a and b isnt b
|
||||
|
||||
# A recursive functional equivalence helper; uses egal for testing equivalence.
|
||||
arrayEgal = (a, b) ->
|
||||
if egal a, b then yes
|
||||
else if a instanceof Array and b instanceof Array
|
||||
return no unless a.length is b.length
|
||||
return no for el, idx in a when not arrayEgal el, b[idx]
|
||||
yes
|
||||
|
||||
global.eq = (a, b, msg) -> ok egal(a, b), msg ? "Expected #{a} to equal #{b}"
|
||||
global.arrayEq = (a, b, msg) -> ok arrayEgal(a,b), msg ? "Expected #{a} to deep equal #{b}"
|
||||
helpers.extend global, require './test/support/helpers'
|
||||
|
||||
# When all the tests have run, collect and print errors.
|
||||
# If a stacktrace is available, output the compiled function source.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
v1
|
114
documentation/test.html
Normal file
114
documentation/test.html
Normal file
|
@ -0,0 +1,114 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<title>CoffeeScript Test Suite</title>
|
||||
<script src="browser-compiler/coffee-script.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/underscorejs/1.8.3/underscore-min.js"></script>
|
||||
<style>
|
||||
body, pre {
|
||||
font-family: Consolas, Menlo, Monaco, monospace;
|
||||
}
|
||||
body {
|
||||
margin: 1em;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
div {
|
||||
margin: 0.6em;
|
||||
}
|
||||
.good {
|
||||
color: #22b24c
|
||||
}
|
||||
.bad {
|
||||
color: #eb6864
|
||||
}
|
||||
.subtle {
|
||||
font-size: 0.7em;
|
||||
color: #999999
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>CoffeeScript Test Suite</h1>
|
||||
|
||||
<pre id="stdout"></pre>
|
||||
|
||||
<script type="text/coffeescript">
|
||||
@testingBrowser = yes
|
||||
@global = window
|
||||
stdout = document.getElementById 'stdout'
|
||||
start = new Date
|
||||
success = total = done = failed = 0
|
||||
|
||||
say = (msg, className) ->
|
||||
div = document.createElement 'div'
|
||||
div.className = className if className?
|
||||
div.appendChild document.createTextNode msg
|
||||
stdout.appendChild div
|
||||
msg
|
||||
|
||||
@test = (description, fn) ->
|
||||
++total
|
||||
try
|
||||
fn.call(fn)
|
||||
++success
|
||||
catch exception
|
||||
say "#{description}:", 'bad'
|
||||
say fn.toString(), 'subtle' if fn.toString?
|
||||
say exception, 'bad'
|
||||
console.error exception
|
||||
|
||||
@ok = (good, msg = 'Error') ->
|
||||
throw Error msg unless good
|
||||
|
||||
# Polyfill Node assert's fail
|
||||
@fail = ->
|
||||
ok no
|
||||
|
||||
# Polyfill Node assert's deepEqual with Underscore's isEqual
|
||||
@deepEqual = (a, b) ->
|
||||
ok _.isEqual(a, b), "Expected #{JSON.stringify a} to deep equal #{JSON.stringify b}"
|
||||
|
||||
<%= testHelpers %>
|
||||
|
||||
@doesNotThrow = (fn) ->
|
||||
fn()
|
||||
ok yes
|
||||
|
||||
@throws = (fun, err, msg) ->
|
||||
try
|
||||
fun()
|
||||
catch e
|
||||
if err
|
||||
if typeof err is 'function' and e instanceof err # Handle comparing exceptions
|
||||
ok yes
|
||||
else
|
||||
eq e, err
|
||||
else
|
||||
ok yes
|
||||
return
|
||||
ok no
|
||||
|
||||
|
||||
# Run the tests
|
||||
for test in document.getElementsByClassName 'test'
|
||||
say '\u2714 ' + test.id
|
||||
options = {}
|
||||
options.literate = yes if test.type is 'text/x-literate-coffeescript'
|
||||
CoffeeScript.run test.innerHTML, options
|
||||
|
||||
# Finish up
|
||||
yay = success is total and not failed
|
||||
sec = (new Date - start) / 1000
|
||||
msg = "passed #{success} tests in #{ sec.toFixed 2 } seconds"
|
||||
msg = "failed #{ total - success } tests and #{msg}" unless yay
|
||||
say msg, (if yay then 'good' else 'bad')
|
||||
</script>
|
||||
|
||||
<%= tests %>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -293,25 +293,25 @@ test "#3132: Format jsdoc-style block-comment nicely", ->
|
|||
input = """
|
||||
###*
|
||||
# Multiline for jsdoc-"@doctags"
|
||||
#
|
||||
#
|
||||
# @type {Function}
|
||||
###
|
||||
fn = () -> 1
|
||||
"""
|
||||
|
||||
result = """
|
||||
|
||||
|
||||
/**
|
||||
* Multiline for jsdoc-"@doctags"
|
||||
*
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
var fn;
|
||||
|
||||
|
||||
fn = function() {
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
"""
|
||||
eq CoffeeScript.compile(input, bare: on), result
|
||||
|
||||
|
@ -321,25 +321,25 @@ test "#3132: Format hand-made (raw) jsdoc-style block-comment nicely", ->
|
|||
input = """
|
||||
###*
|
||||
* Multiline for jsdoc-"@doctags"
|
||||
*
|
||||
*
|
||||
* @type {Function}
|
||||
###
|
||||
fn = () -> 1
|
||||
"""
|
||||
|
||||
result = """
|
||||
|
||||
|
||||
/**
|
||||
* Multiline for jsdoc-"@doctags"
|
||||
*
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
var fn;
|
||||
|
||||
|
||||
fn = function() {
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
"""
|
||||
eq CoffeeScript.compile(input, bare: on), result
|
||||
|
||||
|
@ -349,54 +349,54 @@ test "#3132: Place block-comments nicely", ->
|
|||
input = """
|
||||
###*
|
||||
# A dummy class definition
|
||||
#
|
||||
#
|
||||
# @class
|
||||
###
|
||||
class DummyClass
|
||||
|
||||
|
||||
###*
|
||||
# @constructor
|
||||
###
|
||||
constructor: ->
|
||||
|
||||
|
||||
###*
|
||||
# Singleton reference
|
||||
#
|
||||
#
|
||||
# @type {DummyClass}
|
||||
###
|
||||
@instance = new DummyClass()
|
||||
|
||||
|
||||
"""
|
||||
|
||||
result = """
|
||||
|
||||
|
||||
/**
|
||||
* A dummy class definition
|
||||
*
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
var DummyClass;
|
||||
|
||||
|
||||
DummyClass = (function() {
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function DummyClass() {}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Singleton reference
|
||||
*
|
||||
*
|
||||
* @type {DummyClass}
|
||||
*/
|
||||
|
||||
|
||||
DummyClass.instance = new DummyClass();
|
||||
|
||||
|
||||
return DummyClass;
|
||||
|
||||
|
||||
})();
|
||||
|
||||
|
||||
"""
|
||||
eq CoffeeScript.compile(input, bare: on), result
|
||||
|
||||
|
@ -427,3 +427,7 @@ test "#3761: Multiline comment at end of an object", ->
|
|||
###
|
||||
|
||||
ok anObject.x is 3
|
||||
|
||||
test "#4375: UTF-8 characters in comments", ->
|
||||
# 智に働けば角が立つ、情に掉させば流される。
|
||||
ok yes
|
||||
|
|
17
test/support/helpers.coffee
Normal file
17
test/support/helpers.coffee
Normal file
|
@ -0,0 +1,17 @@
|
|||
# See http://wiki.ecmascript.org/doku.php?id=harmony:egal
|
||||
egal = (a, b) ->
|
||||
if a is b
|
||||
a isnt 0 or 1/a is 1/b
|
||||
else
|
||||
a isnt a and b isnt b
|
||||
|
||||
# A recursive functional equivalence helper; uses egal for testing equivalence.
|
||||
arrayEgal = (a, b) ->
|
||||
if egal a, b then yes
|
||||
else if a instanceof Array and b instanceof Array
|
||||
return no unless a.length is b.length
|
||||
return no for el, idx in a when not arrayEgal el, b[idx]
|
||||
yes
|
||||
|
||||
exports.eq = (a, b, msg) -> ok egal(a, b), msg or "Expected #{a} to equal #{b}"
|
||||
exports.arrayEq = (a, b, msg) -> ok arrayEgal(a,b), msg or "Expected #{a} to deep equal #{b}"
|
121
test/test.html
121
test/test.html
|
@ -1,121 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<title>CoffeeScript Test Suite</title>
|
||||
<script src="../docs/current/browser-compiler/coffee-script.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 30px;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
#stdout {
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>CoffeeScript Test Suite</h1>
|
||||
<pre id="stdout"></pre>
|
||||
|
||||
<script type="text/coffeescript">
|
||||
|
||||
stdout = document.getElementById 'stdout'
|
||||
start = new Date
|
||||
success = total = done = failed = 0
|
||||
|
||||
say = (msg) ->
|
||||
div = document.createElement 'div'
|
||||
div.appendChild document.createTextNode msg
|
||||
stdout.appendChild div
|
||||
msg
|
||||
|
||||
@test = (desc, fn) ->
|
||||
fn()
|
||||
|
||||
@ok = (good, msg) ->
|
||||
++total
|
||||
if good then ++success else throw Error say msg
|
||||
|
||||
@eq = (x, y, msg) -> ok x is y, msg ? x + ' !== ' + y
|
||||
|
||||
arrayEqual = (a, b) ->
|
||||
if a is b
|
||||
# 0 isnt -0
|
||||
a isnt 0 or 1/a is 1/b
|
||||
else if a instanceof Array and b instanceof Array
|
||||
return no unless a.length is b.length
|
||||
return no for el, idx in a when not arrayEq el, b[idx]
|
||||
yes
|
||||
else
|
||||
# NaN is NaN
|
||||
a isnt a and b isnt b
|
||||
|
||||
@doesNotThrow = (fn) ->
|
||||
fn()
|
||||
ok true
|
||||
|
||||
@arrayEq = (a, b, msg) -> ok arrayEqual(a,b), msg
|
||||
|
||||
@throws = (fun, err, msg) ->
|
||||
try
|
||||
fun()
|
||||
catch e
|
||||
if err
|
||||
eq e, err
|
||||
else
|
||||
ok yes
|
||||
return
|
||||
ok no
|
||||
|
||||
run = (name) ->
|
||||
CoffeeScript.load "#{name}.coffee", ->
|
||||
say '\u2714 ' + name
|
||||
fin() if ++done is names.length
|
||||
|
||||
fin = ->
|
||||
yay = success is total and not failed
|
||||
sec = (new Date - start) / 1000
|
||||
msg = "passed #{success} tests in #{ sec.toFixed 2 } seconds"
|
||||
msg = "failed #{ total - success } tests and #{msg}" unless yay
|
||||
say msg, yay
|
||||
|
||||
run name for name in names = [
|
||||
'arrays'
|
||||
'assignment'
|
||||
'booleans'
|
||||
'classes'
|
||||
'cluster'
|
||||
'comments'
|
||||
'compilation'
|
||||
'comprehensions'
|
||||
'control_flow'
|
||||
'exception_handling'
|
||||
'formatting'
|
||||
'function_invocation'
|
||||
'functions'
|
||||
'helpers'
|
||||
'importing'
|
||||
'interpolation'
|
||||
'javascript_literals'
|
||||
'modules'
|
||||
'numbers'
|
||||
'objects'
|
||||
'operators'
|
||||
'option_parser'
|
||||
'ranges'
|
||||
'regexps'
|
||||
'scope'
|
||||
'slicing_and_splicing'
|
||||
'soaks'
|
||||
'strings'
|
||||
]
|
||||
# allow utf-8 chars in comments
|
||||
# 智に働けば角が立つ、情に掉させば流される。
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue