alloy-js-test-san 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/README.rdoc +83 -0
  2. data/Rakefile +27 -0
  3. data/VERSION.yml +4 -0
  4. data/bin/jstest +10 -0
  5. data/lib/js_test_san/runner.rb +70 -0
  6. data/lib/js_test_san/test.rb +17 -0
  7. data/lib/js_test_san/test_case.rb +103 -0
  8. data/lib/js_test_san.rb +2 -0
  9. data/test/fixtures/a_unit_test.html +27 -0
  10. data/test/fixtures/a_unit_test.js +22 -0
  11. data/test/regression/prototype/unit/ajax_test.html +29 -0
  12. data/test/regression/prototype/unit/array_test.html +28 -0
  13. data/test/regression/prototype/unit/assets/prototype.js +4900 -0
  14. data/test/regression/prototype/unit/assets/unittest.css +50 -0
  15. data/test/regression/prototype/unit/assets/unittest.js +615 -0
  16. data/test/regression/prototype/unit/assets/unittest_transport.js +1 -0
  17. data/test/regression/prototype/unit/base_test.html +27 -0
  18. data/test/regression/prototype/unit/class_test.html +27 -0
  19. data/test/regression/prototype/unit/date_test.html +27 -0
  20. data/test/regression/prototype/unit/dom_test.html +304 -0
  21. data/test/regression/prototype/unit/element_mixins_test.html +30 -0
  22. data/test/regression/prototype/unit/enumerable_test.html +35 -0
  23. data/test/regression/prototype/unit/event_test.html +31 -0
  24. data/test/regression/prototype/unit/fixtures/ajax.html +2 -0
  25. data/test/regression/prototype/unit/fixtures/ajax.js +42 -0
  26. data/test/regression/prototype/unit/fixtures/array.html +1 -0
  27. data/test/regression/prototype/unit/fixtures/class.js +83 -0
  28. data/test/regression/prototype/unit/fixtures/content.html +1 -0
  29. data/test/regression/prototype/unit/fixtures/data.json +1 -0
  30. data/test/regression/prototype/unit/fixtures/dom.css +84 -0
  31. data/test/regression/prototype/unit/fixtures/dom.html +278 -0
  32. data/test/regression/prototype/unit/fixtures/dom.js +17 -0
  33. data/test/regression/prototype/unit/fixtures/element_mixins.html +4 -0
  34. data/test/regression/prototype/unit/fixtures/element_mixins.js +2 -0
  35. data/test/regression/prototype/unit/fixtures/empty.html +0 -0
  36. data/test/regression/prototype/unit/fixtures/empty.js +1 -0
  37. data/test/regression/prototype/unit/fixtures/enumerable.html +8 -0
  38. data/test/regression/prototype/unit/fixtures/enumerable.js +23 -0
  39. data/test/regression/prototype/unit/fixtures/event.html +4 -0
  40. data/test/regression/prototype/unit/fixtures/form.html +108 -0
  41. data/test/regression/prototype/unit/fixtures/function.js +13 -0
  42. data/test/regression/prototype/unit/fixtures/hash.js +25 -0
  43. data/test/regression/prototype/unit/fixtures/hello.js +1 -0
  44. data/test/regression/prototype/unit/fixtures/logo.gif +0 -0
  45. data/test/regression/prototype/unit/fixtures/object.html +6 -0
  46. data/test/regression/prototype/unit/fixtures/object.js +7 -0
  47. data/test/regression/prototype/unit/fixtures/position.html +9 -0
  48. data/test/regression/prototype/unit/fixtures/selector.html +71 -0
  49. data/test/regression/prototype/unit/fixtures/string.js +8 -0
  50. data/test/regression/prototype/unit/fixtures/unittest.html +18 -0
  51. data/test/regression/prototype/unit/form_test.html +135 -0
  52. data/test/regression/prototype/unit/function_test.html +27 -0
  53. data/test/regression/prototype/unit/hash_test.html +27 -0
  54. data/test/regression/prototype/unit/number_test.html +27 -0
  55. data/test/regression/prototype/unit/object_test.html +32 -0
  56. data/test/regression/prototype/unit/periodical_executer_test.html +27 -0
  57. data/test/regression/prototype/unit/position_test.html +36 -0
  58. data/test/regression/prototype/unit/prototype_test.html +27 -0
  59. data/test/regression/prototype/unit/range_test.html +27 -0
  60. data/test/regression/prototype/unit/regexp_test.html +27 -0
  61. data/test/regression/prototype/unit/selector_test.html +98 -0
  62. data/test/regression/prototype/unit/string_test.html +27 -0
  63. data/test/regression/prototype/unit/tests/ajax_test.js +379 -0
  64. data/test/regression/prototype/unit/tests/array_test.js +186 -0
  65. data/test/regression/prototype/unit/tests/base_test.js +43 -0
  66. data/test/regression/prototype/unit/tests/class_test.js +136 -0
  67. data/test/regression/prototype/unit/tests/date_test.js +5 -0
  68. data/test/regression/prototype/unit/tests/dom_test.js +1493 -0
  69. data/test/regression/prototype/unit/tests/element_mixins_test.js +32 -0
  70. data/test/regression/prototype/unit/tests/enumerable_test.js +271 -0
  71. data/test/regression/prototype/unit/tests/event_test.js +235 -0
  72. data/test/regression/prototype/unit/tests/form_test.js +382 -0
  73. data/test/regression/prototype/unit/tests/function_test.js +133 -0
  74. data/test/regression/prototype/unit/tests/hash_test.js +178 -0
  75. data/test/regression/prototype/unit/tests/number_test.js +44 -0
  76. data/test/regression/prototype/unit/tests/object_test.js +180 -0
  77. data/test/regression/prototype/unit/tests/periodical_executer_test.js +15 -0
  78. data/test/regression/prototype/unit/tests/position_test.js +44 -0
  79. data/test/regression/prototype/unit/tests/prototype_test.js +43 -0
  80. data/test/regression/prototype/unit/tests/range_test.js +58 -0
  81. data/test/regression/prototype/unit/tests/regexp_test.js +42 -0
  82. data/test/regression/prototype/unit/tests/selector_test.js +408 -0
  83. data/test/regression/prototype/unit/tests/string_test.js +548 -0
  84. data/test/regression/prototype/unit/tests/unittest_test.js +148 -0
  85. data/test/regression/prototype/unit/unittest_test.html +45 -0
  86. data/test/regression/prototype/upstream +1 -0
  87. data/test/test_helper.rb +20 -0
  88. data/test/unit/runner_test.rb +165 -0
  89. data/test/unit/test_case_test.rb +167 -0
  90. data/test/unit/test_test.rb +24 -0
  91. metadata +145 -0
data/README.rdoc ADDED
@@ -0,0 +1,83 @@
1
+ = JSTestSan
2
+
3
+ A JavaScript test runner to run JavaScript tests from the comfort of your
4
+ terminal.
5
+
6
+ == Why?
7
+
8
+ Because we want to run tests in a real browser environment, in our case WebKit,
9
+ but in the same fashion we run out other (Rails) unit tests.
10
+
11
+ And we want to write the tests in a way that we can easily run them on other
12
+ browsers as well, you know, html and js… This way we can run the tests from the
13
+ terminal during regular development but still test on other browsers by loading
14
+ the html/js files manually.
15
+
16
+ == Install & Usage
17
+
18
+ $ sudo gem install alloy-js-test-san -s http://gems.github.com
19
+ $ jstest path/to/a/unit_test.html
20
+
21
+ To automatically run your test see http://github.com/alloy/kicker/tree/master.
22
+
23
+ == Problems?
24
+
25
+ You betcha! (See the example.)
26
+
27
+ But these shouldn't likely be a typical use case outside of testing the
28
+ Prototype implementation, I hope. So it actually works quite well seeing how
29
+ many tests pass ;)
30
+
31
+ == Example:
32
+
33
+ This is the output of the regression tests which are the Prototype unit tests:
34
+
35
+ $ ./bin/jstest test/regression/prototype/unit/*_test.html
36
+ EEFF.......F..............................................................................................................................F
37
+ ..............................................................F............................................................................
38
+ ..............................................................................
39
+
40
+ 1) Error:
41
+ testSynchronousRequest (Unit test file | Ajax | default template | 2009-04-11 15:28) [test/regression/prototype/unit/ajax_test.html]:
42
+ TypeError: Null value, error=(TypeError: Null value)
43
+
44
+ 2) Error:
45
+ testAsynchronousRequest (Unit test file | Ajax | default template | 2009-04-11 15:28) [test/regression/prototype/unit/ajax_test.html]:
46
+ TypeError: Null value, error=(TypeError: Null value)
47
+
48
+ 3) Failed:
49
+ testUpdater (Unit test file | Ajax | default template | 2009-04-11 15:28) [test/regression/prototype/unit/ajax_test.html]:
50
+ Failure: assertEqual
51
+ expected: <'pack my box with <em>five dozen</em> liquor jugs! oh, how <strong>quickly</strong> daft jumping zebras vex...'>, actual: <''>
52
+ Failure: assertEqual
53
+ expected: <'pack my box with <em>five dozen</em> liquor jugs! oh, how <strong>quickly</strong> daft jumping zebras vex...'>, actual: <''>
54
+
55
+ 4) Failed:
56
+ testUpdaterWithInsertion (Unit test file | Ajax | default template | 2009-04-11 15:28) [test/regression/prototype/unit/ajax_test.html]:
57
+ Failure: assertEqual
58
+ expected: <'pack my box with <em>five dozen</em> liquor jugs! oh, how <strong>quickly</strong> daft jumping zebras vex...'>, actual: <''>
59
+ Failure: assertEqual
60
+ expected: <'pack my box with <em>five dozen</em> liquor jugs! oh, how <strong>quickly</strong> daft jumping zebras vex...'>, actual: <''>
61
+ Failure: assertEqual
62
+ expected: <'five dozen'>, actual: <''>
63
+
64
+ 5) Failed:
65
+ testResponseText (Unit test file | Ajax | default template | 2009-04-11 15:28) [test/regression/prototype/unit/ajax_test.html]:
66
+ Failure: assertEqual
67
+ expected: <'pack my box with <em>five dozen</em> liquor jugs! oh, how <strong>quickly</strong> daft jumping zebras vex...'>, actual: <''>
68
+
69
+ 6) Failed:
70
+ testViewportDimensions (Unit test file | Dom | default template | 2009-04-11 15:28) [test/regression/prototype/unit/dom_test.html]:
71
+ Failure: NOTE: YOU MUST ALLOW JAVASCRIPT TO RESIZE YOUR WINDOW FOR THIS TEST TO PASS
72
+ expected: <50>, actual: <0>
73
+ Failure: NOTE: YOU MUST ALLOW JAVASCRIPT TO RESIZE YOUR WINDOW FOR THIS TEST TO PASS
74
+ expected: <50>, actual: <0>
75
+
76
+ 7) Failed:
77
+ testFormRequest (Unit test file | Form | default template | 2009-04-11 15:28) [test/regression/prototype/unit/form_test.html]:
78
+ Failure: wrong default action for form element with empty action attribute
79
+ got <false>
80
+
81
+ Finished in 17.729032 seconds.
82
+
83
+ 356 tests, 2237 assertions, 9 failures, 2 errors
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ task :default => :test
2
+
3
+ desc "Run the tests"
4
+ task :test do
5
+ sh "specrb -s #{Dir['test/unit/*_test.rb'].join(' ')}"
6
+ end
7
+
8
+ # JSTestSan::Rake::Runner.new :regression do |t|
9
+ # t.files = Dir['test/regression/prototype/unit/*.html']
10
+ # end
11
+
12
+ desc "Run the regression tests"
13
+ task :ci do
14
+ sh "./bin/jstest #{Dir['test/regression/prototype/unit/*.html'].join(' ')}"
15
+ end
16
+
17
+ begin
18
+ require 'jeweler'
19
+ Jeweler::Tasks.new do |gemspec|
20
+ gemspec.name = "js-test-san"
21
+ gemspec.summary = gemspec.description = "A JavaScript test runner which runs from the comfort of the terminal. OS X only."
22
+ gemspec.email = "eloy.de.enige@gmail.com"
23
+ gemspec.homepage = "http://github.com/alloy/js-test-san/tree/master"
24
+ gemspec.authors = ["Eloy Duran"]
25
+ end
26
+ rescue LoadError
27
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 1
data/bin/jstest ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'js_test_san'
5
+
6
+ if ARGV.empty?
7
+ puts "Usage: #{$0} [html files]"
8
+ else
9
+ JSTestSan::Runner.alloc.initWithHTMLFiles(ARGV).run
10
+ end
@@ -0,0 +1,70 @@
1
+ require 'osx/cocoa'
2
+
3
+ module JSTestSan
4
+ class Runner < OSX::NSObject
5
+ attr_reader :test_cases, :queued, :did_not_pass
6
+
7
+ def initWithHTMLFiles(html_files)
8
+ if init
9
+ @test_cases = []
10
+ @test_cases = html_files.map { |file| TestCase.alloc.initWithHTMLFile_delegate(file, self) }
11
+ @queued = @test_cases.dup
12
+ @did_not_pass = []
13
+
14
+ $stdout.sync = true
15
+
16
+ self
17
+ end
18
+ end
19
+
20
+ def run
21
+ @start_time = Time.now
22
+ @queued.first.run
23
+ OSX::NSApplication.sharedApplication.run
24
+ end
25
+
26
+ def tests; sum :tests end
27
+ def assertions; sum :assertions end
28
+ def failures; sum :failures end
29
+ def errors; sum :errors end
30
+
31
+ def test_ran(test)
32
+ @did_not_pass << test unless test.state == :passed
33
+
34
+ print case test.state
35
+ when :passed
36
+ '.'
37
+ when :failed
38
+ 'F'
39
+ when :error
40
+ 'E'
41
+ end
42
+ end
43
+
44
+ def test_case_finished(test_case)
45
+ @queued.delete(test_case)
46
+ @queued.empty? ? finalize : @queued.first.run
47
+ end
48
+
49
+ def finished?
50
+ @finished
51
+ end
52
+
53
+ private
54
+
55
+ def sum(attr)
56
+ @test_cases.inject(0) { |sum, tc| sum += tc.send(attr) }
57
+ end
58
+
59
+ def finalize
60
+ @finished = true
61
+
62
+ puts
63
+ @did_not_pass.each_with_index { |test, index| puts "\n #{index+1}) #{test}" }
64
+ puts "\nFinished in #{Time.now - @start_time} seconds."
65
+ puts "\n#{tests} tests, #{assertions} assertions, #{failures} failures, #{errors} errors"
66
+
67
+ OSX::NSApplication.sharedApplication.terminate(self)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,17 @@
1
+ module JSTestSan
2
+ class TestCase < OSX::NSObject
3
+ class Test
4
+ attr_reader :test_case, :name, :state, :output
5
+
6
+ def initialize(test_case, name, state, output)
7
+ @test_case, @name, @state, @output = test_case, name, state, output
8
+ end
9
+
10
+ def to_s
11
+ %{#{@state.to_s.capitalize}:
12
+ #{@name} (#{@test_case.title}) [#{@test_case.html_file}]:
13
+ #{@output}}
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,103 @@
1
+ require "osx/cocoa"
2
+ OSX.require_framework 'WebKit'
3
+
4
+ require 'js_test_san/test'
5
+
6
+ module JSTestSan
7
+ class TestCase < OSX::NSObject
8
+ class FileDoesNotExistError < StandardError; end
9
+
10
+ def self.sharedWebView
11
+ @sharedWebView ||= OSX::WebView.alloc.init
12
+ end
13
+
14
+ RESULTS_REGEXP = /^((\d+) tests, )?(\d+) assertions, (\d+) failures, (\d+) errors\n?/
15
+
16
+ STATES = %w{ passed failed error }
17
+
18
+ attr_reader :html_file, :delegate, :title
19
+ attr_reader :tests, :assertions, :failures, :errors
20
+
21
+ def initWithHTMLFile_delegate(html_file, delegate)
22
+ if init
23
+ raise FileDoesNotExistError, "The file `#{html_file}' does not exist." unless File.exist?(html_file)
24
+ @html_file, @delegate = html_file, delegate
25
+ @tests = @assertions = @failures = @errors = 0
26
+ @title = ''
27
+ self
28
+ end
29
+ end
30
+
31
+ def run
32
+ webView
33
+ end
34
+
35
+ def finished?
36
+ @finished
37
+ end
38
+
39
+ def webView
40
+ @webView ||= load_webView
41
+ end
42
+
43
+ def document
44
+ webView.mainFrame.DOMDocument
45
+ end
46
+
47
+ def log
48
+ document.getElementsByClassName('logsummary').item(0)
49
+ end
50
+
51
+ def loglines
52
+ document.getElementsByClassName('loglines').item(0)
53
+ end
54
+
55
+ # Not yet sure why the extra check for log not being nil is necessary.
56
+ # Might be a test only thing.
57
+ def webView_didFinishLoadForFrame(_, __)
58
+ @title = webView.mainFrameTitle.to_s
59
+ [log, loglines].each do |element|
60
+ element.addEventListener___('DOMSubtreeModified', self, true) if element
61
+ end
62
+ end
63
+
64
+ def handleEvent(event)
65
+ element = event.target
66
+ case element
67
+ when OSX::DOMText
68
+ finalize unless log.innerText == 'running...'
69
+ else
70
+ parent = element.parentNode
71
+ state = parent.className
72
+
73
+ if element == parent.lastChild && STATES.include?(state)
74
+ output = parent.children.item(2).innerText.to_s
75
+ return if output.empty?
76
+
77
+ output.sub!(RESULTS_REGEXP, '')
78
+ name = parent.children.item(0).innerText
79
+
80
+ @delegate.test_ran(Test.new(self, name, state.to_sym, output))
81
+ end
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def load_webView
88
+ url = OSX::NSURL.fileURLWithPath(@html_file)
89
+ req = OSX::NSURLRequest.requestWithURL(url)
90
+ webView = self.class.sharedWebView
91
+ webView.mainFrame.loadRequest(req)
92
+ webView.frameLoadDelegate = self
93
+ webView
94
+ end
95
+
96
+ def finalize
97
+ @finished = true
98
+ results = log.innerText.to_s.scan(RESULTS_REGEXP).first[1..-1]
99
+ @tests, @assertions, @failures, @errors = results.map { |x| x.to_i }
100
+ @delegate.test_case_finished(self)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,2 @@
1
+ require 'js_test_san/test_case'
2
+ require 'js_test_san/runner'
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <title>A JSTestSan Unit Test HTML File</title>
6
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
7
+
8
+ <script type="text/javascript" charset="utf-8">
9
+ var eventResults = {};
10
+ var originalElement = window.Element;
11
+ </script>
12
+
13
+ <script src="../regression/prototype/unit/assets/prototype.js" type="text/javascript" charset="utf-8"></script>
14
+ <script src="../regression/prototype/unit/assets/unittest.js" type="text/javascript" charset="utf-8"></script>
15
+ <script src="a_unit_test.js" type="text/javascript" charset="utf-8"></script>
16
+ </head>
17
+ <body>
18
+
19
+ <div id="testlog"></div>
20
+
21
+ <div id="content"></div>
22
+
23
+ </body>
24
+ </html>
25
+ <script type="text/javascript" charset="utf-8">
26
+ eventResults.endOfDocument = true;
27
+ </script>
@@ -0,0 +1,22 @@
1
+ // 3 tests, 2 assertions, 1 failures, 1 errors
2
+
3
+ new Test.Unit.Runner({
4
+ setup: function() {
5
+ this.content = $('content');
6
+ this.content.update('');
7
+ },
8
+
9
+ testHelloWorldSuccess: function() {
10
+ this.assertEqual("", this.content.innerHTML);
11
+ this.content.update('Hello world!');
12
+ this.assertEqual("Hello world!", this.content.innerHTML);
13
+ },
14
+
15
+ testHelloWorldFailure: function() {
16
+ this.assertEqual("Hello world!", this.content.innerHTML);
17
+ },
18
+
19
+ testHelloWorldError: function() {
20
+ this.content.foo();
21
+ },
22
+ });
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <title>Unit test file | Ajax | default template | 2009-04-11 15:28</title>
6
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
7
+ <script type="text/javascript" charset="utf-8">
8
+ var eventResults = {};
9
+ var originalElement = window.Element;
10
+ </script>
11
+ <script src="assets/prototype.js" type="text/javascript" charset="utf-8"></script>
12
+ <script src="assets/unittest.js" type="text/javascript" charset="utf-8"></script>
13
+ <link rel="stylesheet" href="assets/unittest.css" type="text/css" />
14
+
15
+ <script src="fixtures/ajax.js" type="text/javascript" charset="utf-8"></script>
16
+ <script src="tests/ajax_test.js" type="text/javascript" charset="utf-8"></script>
17
+ </head>
18
+ <body>
19
+
20
+ <div id="testlog"></div>
21
+
22
+ <div id="content"></div>
23
+ <div id="content2" style="color:red"></div>
24
+
25
+ </body>
26
+ </html>
27
+ <script type="text/javascript" charset="utf-8">
28
+ eventResults.endOfDocument = true;
29
+ </script>
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <title>Unit test file | Array | default template | 2009-04-11 15:28</title>
6
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
7
+ <script type="text/javascript" charset="utf-8">
8
+ var eventResults = {};
9
+ var originalElement = window.Element;
10
+ </script>
11
+ <script src="assets/prototype.js" type="text/javascript" charset="utf-8"></script>
12
+ <script src="assets/unittest.js" type="text/javascript" charset="utf-8"></script>
13
+ <link rel="stylesheet" href="assets/unittest.css" type="text/css" />
14
+
15
+
16
+ <script src="tests/array_test.js" type="text/javascript" charset="utf-8"></script>
17
+ </head>
18
+ <body>
19
+
20
+ <div id="testlog"></div>
21
+
22
+ <div id="test_node">22<span id="span_1"></span><span id="span_2"></span></div>
23
+
24
+ </body>
25
+ </html>
26
+ <script type="text/javascript" charset="utf-8">
27
+ eventResults.endOfDocument = true;
28
+ </script>