rspec-jasmine 0.0.1

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.
@@ -0,0 +1,58 @@
1
+ describe("Player", function() {
2
+ var player;
3
+ var song;
4
+
5
+ beforeEach(function() {
6
+ player = new Player();
7
+ song = new Song();
8
+ });
9
+
10
+ it("should be able to play a Song", function() {
11
+ player.play(song);
12
+ expect(player.currentlyPlayingSong).toEqual(song);
13
+
14
+ //demonstrates use of custom matcher
15
+ expect(player).toBePlaying(song);
16
+ });
17
+
18
+ describe("when song has been paused", function() {
19
+ beforeEach(function() {
20
+ player.play(song);
21
+ player.pause();
22
+ });
23
+
24
+ it("should indicate that the song is currently paused", function() {
25
+ expect(player.isPlaying).toBeFalsy();
26
+
27
+ // demonstrates use of 'not' with a custom matcher
28
+ expect(player).not.toBePlaying(song);
29
+ });
30
+
31
+ it("should be possible to resume", function() {
32
+ player.resume();
33
+ expect(player.isPlaying).toBeTruthy();
34
+ expect(player.currentlyPlayingSong).toEqual(song);
35
+ });
36
+ });
37
+
38
+ // demonstrates use of spies to intercept and test method calls
39
+ it("tells the current song if the user has made it a favorite", function() {
40
+ spyOn(song, 'persistFavoriteStatus');
41
+
42
+ player.play(song);
43
+ player.makeFavorite();
44
+
45
+ expect(song.persistFavoriteStatus).toHaveBeenCalledWith(false);
46
+ });
47
+
48
+ //demonstrates use of expected exceptions
49
+ describe("#resume", function() {
50
+ it("should throw an exception if song is already playing", function() {
51
+ player.play(song);
52
+
53
+ expect(function() {
54
+ player.resume();
55
+ }).toThrow("song is already playing");
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,9 @@
1
+ beforeEach(function() {
2
+ this.addMatchers({
3
+ toBePlaying: function(expectedSong) {
4
+ var player = this.actual;
5
+ return player.currentlyPlayingSong === expectedSong &&
6
+ player.isPlaying;
7
+ }
8
+ });
9
+ });
@@ -0,0 +1,22 @@
1
+ function Player() {
2
+ }
3
+ Player.prototype.play = function(song) {
4
+ this.currentlyPlayingSong = song;
5
+ this.isPlaying = true;
6
+ };
7
+
8
+ Player.prototype.pause = function() {
9
+ this.isPlaying = false;
10
+ };
11
+
12
+ Player.prototype.resume = function() {
13
+ if (this.isPlaying) {
14
+ throw new Error("song is already playing");
15
+ }
16
+
17
+ this.isPlaying = true;
18
+ };
19
+
20
+ Player.prototype.makeFavorite = function() {
21
+ this.currentlyPlayingSong.persistFavoriteStatus(true);
22
+ };
@@ -0,0 +1,7 @@
1
+ function Song() {
2
+ }
3
+
4
+ Song.prototype.persistFavoriteStatus = function(value) {
5
+ // something complicated
6
+ throw new Error("not yet implemented");
7
+ };
@@ -0,0 +1,61 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Jasmine Spec Runner</title>
5
+
6
+ <link rel="shortcut icon" type="image/png" href="/lib/jasmine-1.2.0/jasmine_favicon.png">
7
+ <link rel="stylesheet" type="text/css" href="/lib/jasmine-1.2.0/jasmine.css">
8
+
9
+ <!-- Jasmine lib files -->
10
+ <script type="text/javascript" src="/lib/jasmine-1.2.0/jasmine.js"></script>
11
+ <script type="text/javascript" src="/lib/jasmine-1.2.0/jasmine-html.js"></script>
12
+
13
+ <!-- Source files -->
14
+ <script type="text/javascript" src="src/Player.js"></script>
15
+ <script type="text/javascript" src="src/Song.js"></script>
16
+
17
+ <!--
18
+ Your spec files - can be all the scripts separately, or some
19
+ nicely combined together with asset pipeline, etc.
20
+ -->
21
+ <script type="text/javascript" src="spec/SpecHelper.js"></script>
22
+ <script type="text/javascript" src="spec/PlayerSpec.js"></script>
23
+
24
+ <!-- Jasmine suite runner -->
25
+ <script type="text/javascript">
26
+
27
+ var jsApiReporter;
28
+
29
+ (function() {
30
+ var jasmineEnv = jasmine.getEnv();
31
+ jasmineEnv.updateInterval = 1000;
32
+
33
+ jsApiReporter = new jasmine.JsApiReporter();
34
+ var htmlReporter = new jasmine.HtmlReporter();
35
+
36
+ jasmineEnv.addReporter(jsApiReporter);
37
+ jasmineEnv.addReporter(htmlReporter);
38
+
39
+ jasmineEnv.specFilter = function(spec) {
40
+ return htmlReporter.specFilter(spec);
41
+ };
42
+
43
+ var currentWindowOnload = window.onload;
44
+
45
+ window.onload = function() {
46
+ if (currentWindowOnload) {
47
+ currentWindowOnload();
48
+ }
49
+ execJasmine();
50
+ };
51
+
52
+ function execJasmine() {
53
+ jasmineEnv.execute();
54
+ }
55
+ })();
56
+
57
+ </script>
58
+ </head>
59
+ <body>
60
+ </body>
61
+ </html>
@@ -0,0 +1,13 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require 'rspec/jasmine'
3
+
4
+ config_ru = File.expand_path('../../config.ru', __FILE__)
5
+ app, _ = Rack::Builder.parse_file(config_ru)
6
+
7
+ selected_suites = ENV['SUITES'].split(':') if !!ENV['SUITES']
8
+
9
+ RSpec::Jasmine::SpecRunner.run(self,
10
+ :app => app,
11
+ :port => 3001,
12
+ :suites => selected_suites || %w{/tests.html}
13
+ )
@@ -0,0 +1,6 @@
1
+ ENV['RACK_ENV'] == 'test'
2
+
3
+ require 'rspec'
4
+
5
+ RSpec.configure do |conf|
6
+ end
@@ -0,0 +1,2 @@
1
+ require "rspec/jasmine"
2
+ require "rspec/jasmine/version"
@@ -0,0 +1,9 @@
1
+ require 'rspec/jasmine/spec_runner'
2
+
3
+ module RSpec
4
+ module Jasmine
5
+ class << self
6
+ attr_accessor :failed
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,46 @@
1
+ require 'rspec/core/example'
2
+ require 'rspec/jasmine/example_result'
3
+ require 'uri'
4
+
5
+ module RSpec
6
+ module Jasmine
7
+ class Example < RSpec::Core::Example
8
+ def run(example_group_instance, reporter)
9
+ @example_group_instance = example_group_instance
10
+ @example_group_instance.example = self
11
+
12
+ start(reporter)
13
+
14
+ begin
15
+ unless pending
16
+ begin
17
+ @example_group_instance.instance_eval(&@example_block)
18
+ @result = @example_group_instance.instance_variable_get('@result')
19
+ @result.screem! if @result
20
+ rescue RSpec::Core::Pending::PendingDeclaredInExample => e
21
+ @pending_declared_in_example = e.message
22
+ rescue Exception => e
23
+ set_exception(e)
24
+ end
25
+ end
26
+ rescue Exception => e
27
+ set_exception(e)
28
+ ensure
29
+ @example_group_instance.instance_variables.each do |ivar|
30
+ @example_group_instance.instance_variable_set(ivar, nil)
31
+ end
32
+ @example_group_instance = nil
33
+
34
+ begin
35
+ assign_generated_description
36
+ rescue Exception => e
37
+ set_exception(e, "while assigning the example description")
38
+ end
39
+ end
40
+
41
+ @result.merge_backtrace_with!(exception) if exception
42
+ finish(reporter)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,45 @@
1
+ module RSpec
2
+ module Jasmine
3
+ class ExampleResult < Hash
4
+ def initialize(results)
5
+ super()
6
+ merge!(results)
7
+ end
8
+
9
+ def failed?
10
+ self['result'] == 'failed'
11
+ end
12
+
13
+ def failure
14
+ @failed_message ||= self['messages'].to_a.find { |m| m['passed'] == false }
15
+ end
16
+
17
+ def error_message
18
+ failure['message'].to_s
19
+ end
20
+
21
+ def merge_backtrace_with!(e)
22
+ e.instance_variable_set('@stack', self.backtrace)
23
+
24
+ class << e
25
+ def backtrace
26
+ return @stack
27
+ end
28
+ end
29
+ end
30
+
31
+ def backtrace
32
+ trace = failure['trace'] || {}
33
+ trace['stack'].to_s.split(/$/).map(&:strip).delete_if do |line|
34
+ line =~ /\/lib\/jasmine-\d+\.\d+\.\d+\/jasmine\.js\:\d+/ || line.strip.empty?
35
+ end
36
+ end
37
+
38
+ def screem!
39
+ if failed?
40
+ raise RSpec::Expectations::ExpectationNotMetError.new(error_message)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,56 @@
1
+ require 'selenium-webdriver'
2
+ require 'enumerator'
3
+
4
+ module RSpec
5
+ module Jasmine
6
+ class SeleniumDriver
7
+ attr_reader :options, :browser, :address
8
+
9
+ def initialize(browser, options = {})
10
+ @options = options
11
+ @browser = browser
12
+ end
13
+
14
+ def selenium_server
15
+ @selenium_server = if ENV['SELENIUM_SERVER']
16
+ ENV['SELENIUM_SERVER']
17
+ elsif ENV['SELENIUM_SERVER_PORT']
18
+ "http://localhost:#{ENV['SELENIUM_SERVER_PORT']}/wd/hub"
19
+ end
20
+ end
21
+
22
+ def driver
23
+ @driver ||= if selenium_server
24
+ Selenium::WebDriver.for :remote, :url => selenium_server, :desired_capabilities => browser.to_sym
25
+ else
26
+ Selenium::WebDriver.for browser.to_sym, options
27
+ end
28
+ end
29
+
30
+ def tests_finished?
31
+ x("return jsApiReporter.finished") == 'true'
32
+ end
33
+
34
+ def connect(address)
35
+ driver.navigate.to(address)
36
+ end
37
+
38
+ def disconnect
39
+ driver.quit
40
+ end
41
+
42
+ def eval_js(script)
43
+ result = x(script)
44
+ JSON.parse("{\"result\":#{result}}", :max_nesting => false)["result"]
45
+ end
46
+
47
+ def json_generate(obj)
48
+ JSON.generate(obj)
49
+ end
50
+
51
+ def x(script)
52
+ driver.execute_script(script)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,130 @@
1
+ require 'rspec/jasmine/selenium_driver'
2
+ require 'rspec/jasmine/example'
3
+ require 'json'
4
+
5
+ module RSpec
6
+ module Jasmine
7
+ class SpecBuilder
8
+ def initialize(world, config = {})
9
+ @world = world
10
+ @config = config
11
+ @running = false
12
+ end
13
+
14
+ def suite
15
+ @config[:suite] || '/tests'
16
+ end
17
+
18
+ def browser
19
+ @config[:browser] || ENV["JASMINE_BROWSER"] || 'firefox'
20
+ end
21
+
22
+ def host
23
+ @config[:host] || ENV["JASMINE_HOST"] || 'localhost'
24
+ end
25
+
26
+ def port
27
+ @config[:port] || ENV["JASMINE_PORT"] || '5001'
28
+ end
29
+
30
+ def url
31
+ "http://#{host}:#{port}#{suite}"
32
+ end
33
+
34
+ def start
35
+ @client = Jasmine::SeleniumDriver.new(browser)
36
+ @running = true
37
+
38
+ @client.connect(url)
39
+
40
+ puts "Running test suite with Jasmine against: #{url}"
41
+
42
+ load_suite_info!
43
+ generate_report!
44
+ wait_for_suites_to_finish
45
+ end
46
+
47
+ def stop
48
+ @client.disconnect if @running
49
+ @running = false
50
+ end
51
+
52
+ def wait_for_suites_to_finish
53
+ sleep 0.1 until eval_js('return jsApiReporter.finished')
54
+ end
55
+
56
+ def eval_js(script)
57
+ @client.eval_js(script)
58
+ end
59
+
60
+ def load_suite_info!
61
+ started = Time.now
62
+
63
+ while !eval_js('return jsApiReporter && jsApiReporter.started') do
64
+ raise "couldn't connect to Jasmine after 60 seconds" if (started + 60 < Time.now)
65
+ sleep 0.1
66
+ end
67
+
68
+ @spec_ids = []
69
+ @spec_results = nil
70
+ @test_suites = eval_js("var result = jsApiReporter.suites(); return JSON.stringify(result)")
71
+ end
72
+
73
+ def generate_report!
74
+ @test_suites.to_a.each do |suite|
75
+ declare_suite!(@world, suite)
76
+ end
77
+ end
78
+
79
+ def declare_suite!(parent, suite)
80
+ me = self
81
+
82
+ parent.describe suite['name'] do
83
+ suite['children'].each do |suite_or_spec|
84
+ case suite_or_spec["type"]
85
+ when "suite"
86
+ me.declare_suite!(self, suite_or_spec)
87
+ when "spec"
88
+ me.declare_spec!(self, suite_or_spec)
89
+ else
90
+ raise "unknown type #{type} for #{suite_or_spec.inspect}"
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ def declare_spec!(parent, spec)
97
+ me = self
98
+
99
+ spec_id = spec['id']
100
+ @spec_ids << spec_id
101
+
102
+ meta = parent.build_metadata_hash_from([])
103
+ block = proc do
104
+ @result = Jasmine::ExampleResult.new(me.results_for(spec_id))
105
+ Jasmine.failed = true if @result.failed?
106
+ end
107
+
108
+ parent.examples << Jasmine::Example.new(parent, spec['name'], meta, block)
109
+ end
110
+
111
+ def json_generate(obj)
112
+ @client.json_generate(obj)
113
+ end
114
+
115
+ def results_for(spec_id)
116
+ @spec_results ||= load_results
117
+ @spec_results[spec_id.to_s]
118
+ end
119
+
120
+ def load_results
121
+ @spec_ids.each_slice(50).inject({}) do |results, slice|
122
+ results.merge(eval_js(<<-JS))
123
+ var result = jsApiReporter.resultsForSpecs(#{json_generate(slice)});
124
+ return JSON.stringify(result);
125
+ JS
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end