Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

attempting to nodify it :)

  • Loading branch information...
commit 5c893814ede5871e602fc68a15543928b8555239 1 parent 3ba5c11
@thatdutchguy authored
View
4 .gitignore
@@ -1,7 +1,3 @@
.DS_Store
node_modules/
jspec/
-*.js
-!ext/*
-
-
View
36 bin/wt
@@ -1,2 +1,34 @@
-#!/usr/bin/env bash
-/usr/bin/env node `dirname $0`/../app/windtunnel.js $@
+#!/usr/bin/env node
+
+var fs = require('fs'),
+ sys = require('sys'),
+ path = require('path'),
+ nomnom = require('nomnom')
+
+require.paths.unshift(path.join(__dirname, '..', 'lib'))
+
+var wt = require('windtunnel')
+
+var cmdLine = {
+ version: {
+ string: "--version",
+ help: "print version",
+ callback: function() {
+ return "Wind Tunnel version " + wt.VERSION;
+ }
+ },
+ path: {
+ position: 0,
+ help: "file or directory"
+ },
+ summarizer: {
+ string: "--summarizer",
+ help: "summarizer to use [console/html]",
+ "default": 'console'
+ }
+}
+
+var options = nomnom.opts(cmdLine),
+ parsed = options.parseArgs()
+
+wt.run(parsed)
View
8 lib/paths.js
@@ -0,0 +1,8 @@
+var tools = require('tools'),
+ path = require('path')
+
+var lib = tools.realpath(__dirname),
+ ext = tools.realpath(path.join(lib, '..', 'ext'))
+
+exports.lib = lib
+exports.ext = ext
View
29 lib/tools.js
@@ -0,0 +1,29 @@
+var fs = require('fs'),
+ vm = require('vm'),
+ path = require('path')
+
+function realpath(path) {
+ return fs.realpathSync(path)
+}
+
+function readfile(path) {
+ return fs.readFileSync(path).toString()
+}
+
+function script(path) {
+ var fullpath = realpath(path)
+ return vm.createScript(readfile(fullpath), fullpath)
+}
+
+function load(path, context) {
+ if (context) {
+ script(path).runInNewContext(context)
+ } else {
+ script(path).runInThisContext()
+ }
+}
+
+exports.realpath = fs.realpathSync
+exports.readfile = readfile
+exports.script = script
+exports.load = load
View
62 lib/windtunnel/index.js
@@ -0,0 +1,62 @@
+var fs = require('fs'),
+ sys = require('sys'),
+ path = require('path')
+
+require.paths.unshift(path.join(__dirname, '..'))
+
+var tools = require('tools'),
+ jasmine = require('windtunnel/jasmine/helpers'),
+ reporter = require('windtunnel/jasmine/reporter')
+
+var env = {
+ summarizer: null,
+ reporter: null
+}
+
+function summarizer(name) {
+ return require('windtunnel/jasmine/summarizer/' + name).Summarizer
+}
+
+function createContext() {
+ var context = {
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ console: console,
+ require: require // might want to reconsider this
+ }
+ jasmine.load(context)
+ jasmine.init(context, new reporter.SpecReporter(env.reporter))
+ return context
+}
+
+module.exports = {
+ version: [0, 0, 1],
+ run: function(options) {
+ env.reporter = new reporter.Reporter()
+ env.summarizer = new (summarizer(options.summarizer))(env.reporter)
+
+ var p = tools.realpath(options.path),
+ s = fs.statSync(p)
+ if (s.isDirectory()) {
+ this.runPath(p);
+ } else {
+ this.runFile(p);
+ }
+ },
+ runFile: function(path) {
+ var context = createContext()
+ tools.load(path, context)
+ jasmine.exec(context)
+ },
+ runPath: function(path) {
+ var files = fs.readdirSync(path), file, i
+ for (i = 0; i < files.length; i++) {
+ file = files[i]
+ if (file.match(/\_spec\.js$/)) {
+ this.runFile(path + '/' + file)
+ }
+ }
+ }
+}
View
32 lib/windtunnel/jasmine/helpers.js
@@ -0,0 +1,32 @@
+var vm = require('vm'),
+ path = require('path'),
+ tools = require('tools'),
+ paths = require('paths')
+
+function load(context) {
+ tools.load(path.join(paths.ext, 'jasmine.js'), context)
+}
+
+var execScript = vm.createScript('jasmineEnv.execute()');
+var initScript = vm.createScript(
+ [ // Unfortunately in the reporter we can't use 'instanceof jasmine.Spec' because
+ // we either don't have access to the same instance of jasmine.
+ // This workaround will let us determine what kind of object we're dealing with.
+ 'jasmine.Spec.prototype.isSpec = function() { return true }',
+ 'jasmine.Spec.prototype.isSuite = function() { return false }',
+ 'jasmine.Suite.prototype.isSpec = function() { return false }',
+ 'jasmine.Suite.prototype.isSuite = function() { return true }',
+ // prepare the jasmine environment
+ 'var jasmineEnv = jasmine.getEnv()',
+ 'jasmineEnv.addReporter(wtReporter)'
+ ].join("\n")
+)
+
+exports.load = load
+exports.exec = function(context) {
+ execScript.runInNewContext(context)
+}
+exports.init = function(context, reporter) {
+ context.wtReporter = reporter
+ initScript.runInNewContext(context)
+}
View
82 lib/windtunnel/jasmine/reporter.js
@@ -0,0 +1,82 @@
+function now() {
+ return (new Date).getTime()
+}
+
+function Reporter() {
+ this.startedAt = null
+ this.finishedAt = null
+ this.specReporters = []
+ this.done = false
+ this.callbacks = {
+ finished: [],
+ specResults: []
+ }
+}
+Reporter.prototype = {
+ finished: function(cb) {
+ this.callbacks.finished.push(cb)
+ },
+ result: function(cb) {
+ this.callbacks.specResults.push(cb)
+ },
+ start: function() {
+ this.startedAt = now()
+ },
+ duration: function() {
+ return (this.finishedAt - this.startedAt) / 1000
+ },
+ finish: function() {
+ this.finishedAt = now()
+ this.callbacks.finished.forEach(function(cb) { cb() })
+ },
+ register: function(specReporter) {
+ this.specReporters.push(specReporter)
+ },
+ checkDone: function() {
+ var remaining = this.specReporters.filter(function(r) { return !r.done })
+ if (!remaining.length) this.finish()
+ },
+ reportRunnerStarting: function(reporter, runner) {
+ if (!this.startedAt) this.start()
+ },
+ reportRunnerResults: function(reporter, runner) {
+ reporter.done = true
+ reporter.runner = runner
+ this.checkDone()
+ },
+ reportSuiteResults: function(reporter, suite) {},
+ reportSpecResults: function(reporter, spec) {
+ var result = spec.results().passed()
+ this.callbacks.specResults.forEach(function(r) { r(result) })
+ },
+ reportSpecStarting: function(reporter, spec) {}
+}
+
+
+
+function SpecReporter(reporter) {
+ this.reporter = reporter;
+ this.reporter.register(this);
+ this.runner = null;
+ this.done = false;
+}
+SpecReporter.prototype = {
+ reportRunnerStarting: function(runner) {
+ return this.reporter.reportRunnerStarting(this, runner)
+ },
+ reportRunnerResults: function(runner) {
+ return this.reporter.reportRunnerResults(this, runner)
+ },
+ reportSuiteResults: function(suite) {
+ return this.reporter.reportSuiteResults(this, suite)
+ },
+ reportSpecStarting: function(spec) {
+ return this.reporter.reportSpecStarting(this, spec)
+ },
+ reportSpecResults: function(spec) {
+ return this.reporter.reportSpecResults(this, spec)
+ }
+}
+
+exports.Reporter = Reporter;
+exports.SpecReporter = SpecReporter;
View
81 lib/windtunnel/jasmine/summarizer/console.js
@@ -0,0 +1,81 @@
+var fs = require('fs'),
+ sys = require('sys'),
+ path = require('path'),
+ tools = require('tools'),
+ paths = require('paths')
+
+var puts = sys.puts,
+ print = sys.print
+
+function printTrace(trace, indent) {
+ var prefix = '', i
+ for (i = 0; i < indent.length; i++) {
+ prefix += ' '
+ }
+ trace.split("\n").forEach(function(line) {
+ if (!(line.match(paths.lib) || line.match(paths.ext))) {
+ puts(prefix + line)
+ }
+ })
+}
+
+function ConsoleSummarizer(reporter) {
+ var self = this
+ this.reporter = reporter
+ this.reporter.finished(function() { self.summarize() })
+ this.reporter.result(function(r) { self.specResult(r) })
+ this.exampleCount = 0
+ this.failedCount = 0
+}
+ConsoleSummarizer.prototype = {
+ summarize: function() {
+ puts("\n")
+ this.render()
+ puts("")
+ puts("Finished in " + (this.reporter.duration()) + "s")
+ puts("Examples: " + this.exampleCount + ", Failure" + (this.failedCount == 1 ? '' : 's') + ": " + this.failedCount);
+ },
+ render: function() {
+ var self = this
+ this.reporter.specReporters.forEach(function(r) {
+ self.renderResults(r.runner.topLevelSuites())
+ self.renderResults(r.runner)
+ })
+ },
+ renderResults: function(suitesOrSpecs) {
+ var i, s
+ for (i = 0; i < suitesOrSpecs.length; i++) {
+ s = suitesOrSpecs[i]
+ if (s.isSuite()) {
+ this.renderSuite(s)
+ } else if (s.isSpec()) {
+ this.renderSpec(s)
+ }
+ }
+ },
+ renderSuite: function(suite) {
+ this.renderResults(suite.children())
+ },
+ renderSpec: function(spec) {
+ this.exampleCount++
+ var results = spec.results(), items, backtrace
+ if (!results.passed()) {
+ this.failedCount++
+ indent = this.failedCount.toString().length + 4
+
+ if (this.failedCount === 1) puts("Failures:")
+ puts(" " + this.failedCount + ") " + spec.getFullName())
+ items = results.getItems()
+ items.forEach(function(item) {
+ backtrace = item.passed() ? '' : (item.error && item.error.stack || item.trace && item.trace.stack)
+ printTrace(backtrace, indent)
+ puts("")
+ })
+ }
+ },
+ specResult: function(r) {
+ print(r ? '.' : 'F');
+ }
+}
+
+exports.Summarizer = ConsoleSummarizer;
View
137 lib/windtunnel/jasmine/summarizer/html.js
@@ -0,0 +1,137 @@
+var fs = require('fs'),
+ sys = require('sys'),
+ path = require('path'),
+ tools = require('tools'),
+ paths = require('paths')
+
+var puts = sys.puts
+var css = tools.readfile(path.join(paths.lib, 'windtunnel', 'jasmine', 'summarizer', 'html.css'))
+
+function t(template, replacements) {
+ var r, rex
+ for (r in replacements) {
+ template = template.replace(new RegExp('\{\{' + r + '\}\}', 'g'), replacements[r])
+ }
+ return template;
+}
+
+function prepTrace(traceText) {
+ return textMateTrace(filterTrace(traceText.split("\n"))).join("\n")
+}
+
+function filterTrace(traceArray) {
+ return traceArray.filter(function(line) {
+ return !(line.match(paths.lib) || line.match(paths.ext))
+ })
+}
+
+function textMateTrace(traceArray) {
+ return traceArray.map(function(line) {
+ return line.replace(/(\/.*\.js):(\d*)/, "<a href=\"txmt://open?url=file://$1&line=$2\">$1:$2</a>");
+ })
+}
+
+function HTMLSummarizer(reporter) {
+ var self = this
+ this.reporter = reporter
+ this.reporter.finished(function() {
+ self.summarize()
+ })
+ this.exampleCount = 0
+ this.failedCount = 0
+}
+
+HTMLSummarizer.prototype = {
+ summarize: function() {
+ puts(t("<!DOCTYPE html><html><head><title>Jasmine results</title><style>{{css}}</style></head><body>" +
+ "<div class='report'><div id='header' class='{{status}}'><h1>Jasmine Code Examples</h1>" +
+ "{{summary}}<div id='results' class='results'>{{results}}</div></div></body></html>", {
+ results: this.renderResults(),
+ summary: this.renderSummary(),
+ status: this.failedCount == 0 ? 'passed' : 'failed',
+ css: css
+ }))
+ },
+ renderResults: function() {
+ var reporters = this.reporter.specReporters,
+ html = [], reporter, i
+ for (i = 0; i < reporters.length; i++) {
+ reporter = reporters[i]
+ html.push(this.render(reporter.runner.topLevelSuites()))
+ html.push(this.render(reporter.runner))
+ }
+ return html.join('')
+ },
+ render: function(suitesOrSpecs) {
+ var html = [], i, s
+ for (i = 0; i < suitesOrSpecs.length; i++) {
+ var s = suitesOrSpecs[i]
+ if (s.isSuite()) {
+ html.push(this.renderSuite(s))
+ } else if (s.isSpec()) {
+ html.push(this.renderSpec(s))
+ }
+ }
+ return html.join('')
+ },
+ renderSuite: function(suite) {
+ var result = suite.results().passed() ? 'passed' : 'failed',
+ content = this.render(suite.children())
+ return t("<div class='group {{result}}'><div class='group-name'>{{description}}</div>{{content}}</div", {
+ result: result,
+ description: suite.description,
+ content: content
+ })
+ },
+ renderSpec: function(spec) {
+ this.exampleCount++
+ var results = spec.results(), result, content = ''
+ if (results.passed()) {
+ result = 'passed'
+ } else {
+ this.failedCount++
+ result = 'failed'
+ content = this.renderSpecFailed(spec)
+ }
+ return t("<div class='example {{result}}'><div class='example-name'>{{description}}</div>{{content}}</div>", {
+ result: result,
+ description: spec.description,
+ content: content
+ })
+ },
+ renderSpecFailed: function(spec) {
+ var html = [],
+ results = spec.results(),
+ backtrace
+
+ results.getItems().forEach(function(item) {
+ if (!item.passed()) {
+ backtrace = item.error && item.error.stack || item.trace && item.trace.stack
+ html.push(
+ t("<div class='example-failure'><div class='message'><pre>{{item}}</pre></div>" +
+ "<div class='backtrace'><pre>{{trace}}</pre></div></div>", {
+ item: item.toString(),
+ trace: prepTrace(backtrace)
+ })
+ )
+ }
+ })
+ return html.join('')
+ },
+ renderSummary: function() {
+ var duration = t("Finished in {{duration}}s", { duration: this.reporter.duration() }),
+ totals = t("Examples: {{count}}, Failure{{s}}: {{failed}}", {
+ failed: this.failedCount,
+ count: this.exampleCount,
+ s: this.failedCount === 1 ? '' : 's'
+ })
+
+ return t("<div class='summary'><p class='totals'>{{totals}}</p>" +
+ "<p class='duration'>{{duration}}</p></div></div>", {
+ totals: totals,
+ duration: duration
+ })
+ }
+}
+
+exports.Summarizer = HTMLSummarizer
View
20 package.json
@@ -1,9 +1,15 @@
{
- "name":"windtunnel",
- "version":"0.0.1",
- "dependencies": {
- "jsdom":"",
- "htmlparser": "",
- "nomnom": ""
- }
+ "name" : "windtunnel",
+ "description" : "Easy JavaScript testing",
+ "url" : "https://github.com/thatdutchguy/windtunnel",
+ "version" : "0.0.1",
+ "Author" : "Daniël van de Burgt <thatdutchguy@secretlymexico.com>",
+ "bin" : { "wt": "./bin/wt" },
+ "main" : "./lib/windtunnel/index",
+ "dependencies" : {
+ "jsdom":"",
+ "htmlparser": "",
+ "nomnom": ""
+ },
+ "engines" : { "node": ">=0.4.0" }
}
Please sign in to comment.
Something went wrong with that request. Please try again.