rspec-jasmine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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