qlive 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in qlive.gemspec
4
+ gemspec
@@ -0,0 +1,44 @@
1
+ # Qlive
2
+
3
+ Qlive is rack middleware for running qunit javascript tests against a live server.
4
+ It is mainly intended to be used for testing javascript-heavy, single-page web applications
5
+ (like those built using backbone, angularjs, emberjs, etc.)
6
+
7
+ Qlive inserts the qunit framework and your test sources into the page's response.
8
+ Qlive provides hooks for setting server state before the request is processed by your app, so you can
9
+ do things like popuplate content with your favorite fixtures library (like factory_girl) and log in a user for the qunit test page.
10
+
11
+
12
+ ## Benefits:
13
+
14
+ * Precisely set fixture content and user login state for your qunit tests
15
+ * Insert qunit tests and any custom html into live pages generated by your server
16
+ * Run the same qunit tests in a browser or headlessly, alongside your normal integration test suite. (When used with Ruby on Rails and the [qlive-headless](https://github.com/proxv/qlive-headless) gem.)
17
+
18
+
19
+ ## Installation
20
+
21
+ ### Ruby on Rails
22
+
23
+ If you are using Ruby on Rails, you should use one of these gems:
24
+
25
+ * [qlive-rails](https://github.com/proxv/qlive-rails). Configures most of qlive for you and provides an index page linking to your test suites.
26
+ * [qlive-headless](https://github.com/proxv/qlive-headless). Run your qunit tests headlessly as part of your rspec or test suite. (Builds on qlive-rails.)
27
+
28
+
29
+ ### Non-rails:
30
+
31
+ * Configure base path, the top of the directory tree that contains your qlive suites. (See suites section below)
32
+ <pre>Qlive.setup[:base_path] = /absolute/path/to/qunit/tests/tree</pre>
33
+ * Configure url prefix for serving your test sources in this tree.
34
+ * The default is /qlive/sources.
35
+ * So a request to /qlive/sources/my_suite/test-stuff.js would need to resolve to #{base_path}/my_suite/test-stuff.js
36
+ * Mount Qlive::Rack late enough for it to access the database or whatever else the suite needs for preparing page state
37
+
38
+ todo: improve/complete non-rails instructions should anyone want to use it.
39
+
40
+
41
+ ## Usage
42
+
43
+ See [suites wiki page](https://github.com/proxv/qlive/wiki/qlive-suites).
44
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ require "qlive/version"
2
+ require "qlive/setup"
3
+ require "qlive/registry"
4
+ require "qlive/suite"
5
+ require "qlive/rack"
6
+
7
+ module Qlive
8
+ end
Binary file
@@ -0,0 +1,21 @@
1
+ module Qlive
2
+ class DevReload
3
+
4
+ def initialize(app, opts={})
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ self.class.reload_main if env['QUERY_STRING'].include?('qlive=')
10
+ @app.call(env)
11
+ end
12
+
13
+
14
+ def self.reload_main
15
+ load "#{File.expand_path('../rack.rb', __FILE__)}"
16
+ load "#{File.expand_path('../qunit_assets.rb', __FILE__)}"
17
+ load "#{File.expand_path('../suite.rb', __FILE__)}"
18
+ load "#{File.expand_path('../registry.rb', __FILE__)}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ module Qlive
2
+ module QunitAssets
3
+
4
+ # default is to serve assets for qlive-rails. Override if your qunit assets are elsewhere.
5
+ def prepare_assets
6
+ before_body_close.concat(
7
+ qunit_html_structure |
8
+ qunit_support_assets |
9
+ qunit_framework |
10
+ qunit_disable_autostart |
11
+ qunit_javascript_test_sources |
12
+ qunit_finalize
13
+ )
14
+ end
15
+
16
+ def qunit_framework
17
+ [
18
+ '<link rel="stylesheet" href="/qlive/qunit-1.9.0/qunit.css" type="text/css" media="screen" />',
19
+ '<script type="text/javascript" src="/qlive/qunit-1.9.0/qunit.js"></script>'
20
+ ]
21
+ end
22
+
23
+ def qunit_support_assets
24
+ support_relpath = Qlive.setup[:js_support_relpath]
25
+ path = "#{Qlive.setup[:base_path]}#{support_relpath}"
26
+ if (File.exist?(path))
27
+ glob_script_tags(path, "#{Qlive.setup[:url_prefix] || ''}#{support_relpath}")
28
+ else
29
+ []
30
+ end
31
+ end
32
+
33
+ def qunit_javascript_test_sources
34
+ test_path = File.expand_path('..', self.meta_data[:path])
35
+ url_prefix = "#{Qlive.setup[:url_prefix] || ''}/#{suite_name}"
36
+ glob_script_tags(test_path, url_prefix)
37
+ end
38
+
39
+ def qunit_html_structure
40
+ [
41
+ '<div class="qlive-structure">',
42
+ "<h1 id='qunit-header'>Qlive Suite: #{suite_name}</h1>",
43
+ '<h2 id="qunit-banner"></h2>',
44
+ '<div id="qunit-testrunner-toolbar"></div>',
45
+ '<h2 id="qunit-userAgent"></h2>',
46
+ '<ol id="qunit-tests"></ol>',
47
+ '<div id="qunit-fixture">test markup, will be hidden</div>',
48
+ '<div id="display-proxified-tests"></div>',
49
+ '</div>'
50
+ ]
51
+ end
52
+
53
+ def qunit_disable_autostart
54
+ [
55
+ '<script>QUnit.config.autostart = false;</script>'
56
+ ]
57
+ end
58
+
59
+ def qunit_finalize
60
+ [
61
+ '<script>QUnit.done = function(failed, passed, total, runtime) { window.qunitComplete = true; };</script>'
62
+ ]
63
+ end
64
+
65
+ def glob_script_tags(src_base_path, url_prefix)
66
+ sources = Dir.glob("#{src_base_path}#{src_base_path.end_with?('/') ? '' : '/'}**/*.js").sort.flatten
67
+ sources.map do |src|
68
+ src = src.to_s
69
+ href = "#{url_prefix}#{src.sub(src_base_path, '')}"
70
+ "<script type='text/javascript' src='#{href}'></script>"
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,76 @@
1
+ require 'qlive/setup'
2
+ require 'qlive/registry'
3
+
4
+ module Qlive
5
+ class Rack
6
+
7
+ def initialize(app, opts)
8
+ Qlive.setup.merge!(opts)
9
+ @app = app
10
+ @regex_qs = /#{opts[:magic_param] || 'qlive'}=([^&\?]+)/i
11
+ Registry.find_suites
12
+ end
13
+
14
+ def call(env)
15
+ suite = nil
16
+ if env["REQUEST_METHOD"].upcase == 'GET'
17
+ m = @regex_qs.match(env['QUERY_STRING'])
18
+ if m && m.length > 0
19
+ request = ::Rack::Request.new(env)
20
+ suite = Registry.build_suite(m[1])
21
+ suite.prepare({
22
+ :request => request,
23
+ :session => env["rack.session"]
24
+ })
25
+ suite.before_each_request(request)
26
+ end
27
+ end
28
+
29
+ status, headers, body = @app.call(env)
30
+
31
+ if suite
32
+ inject_html(:after_open, :head, suite.html_after_head_open, body, headers)
33
+ inject_html(:before_close, :head, suite.html_before_head_close, body, headers)
34
+ inject_html(:after_open, :body, suite.html_after_body_open, body, headers)
35
+ inject_html(:before_close, :body, suite.html_before_body_close, body, headers)
36
+ end
37
+
38
+ [status, headers, body]
39
+ end
40
+
41
+
42
+ protected
43
+
44
+
45
+ private
46
+
47
+ def inject_html(place, tag_type, html, body, headers)
48
+ return if !html || html.length == 0
49
+ html = html.join("\n") if html.kind_of?(Array)
50
+
51
+ if place == :before_close
52
+ regex = /<\/#{tag_type}>/i
53
+ substitution = "\n#{html}\n</#{tag_type}>"
54
+ else # :after_open
55
+ regex = /<#{tag_type}[^>]*>/i
56
+ substitution = "\\0\n#{html}\n"
57
+ end
58
+
59
+ body.each do |part|
60
+ if part =~ regex
61
+ part.sub!(regex, substitution)
62
+ fix_content_length(headers, html)
63
+ break
64
+ end
65
+ end
66
+ end
67
+
68
+ def fix_content_length(headers, inserted_text)
69
+ if headers['Content-Length'] && inserted_text && inserted_text.length > 0
70
+ headers['Content-Length'] = (headers['Content-Length'].to_i + inserted_text.length).to_s
71
+ end
72
+ end
73
+
74
+
75
+ end
76
+ end
@@ -0,0 +1,72 @@
1
+ require 'qlive/setup'
2
+ require 'qlive/suite'
3
+
4
+ module Qlive
5
+ module Registry
6
+
7
+ unless String.public_method_defined?(:underscore)
8
+ String.class_eval do
9
+ def underscore
10
+ self.gsub(/(.)([A-Z])/,'\1_\2').downcase
11
+ end
12
+ end
13
+ end
14
+
15
+
16
+ $qlive_all_suites ||= {}
17
+ #@all_suites ||= {} # use module instance variable
18
+
19
+ def self.suites
20
+ $qlive_all_suites
21
+ end
22
+
23
+
24
+ def self.find_suites
25
+ suites = {}
26
+ base_path = Qlive.setup[:base_path]
27
+ sources = Dir.glob("#{base_path}#{base_path.end_with?('/') ? '' : '/'}**/*_qlive.rb").sort.flatten
28
+ sources.each do |path|
29
+ path = path.to_s
30
+ name = self.extract_suite_name_from_path(path)
31
+ suites[name] ||= {}
32
+ suites[name][:path] = path
33
+ end
34
+
35
+ $qlive_all_suites = suites
36
+ end
37
+
38
+ def self.build_suite(suite_name)
39
+ meta = Registry.suites[suite_name]
40
+ unless meta || Qlive.setup[:skip_suite_reloader]
41
+ Registry.find_suites
42
+ meta = Registry.suites[suite_name]
43
+ end
44
+ raise "Qlive Suite not found: #{suite_name}" unless meta
45
+ load meta[:path]
46
+ klass = meta[:klass]
47
+ raise "Qlive could not find class for suite: #{suite_name}" unless klass
48
+ klass.new
49
+ end
50
+
51
+ def self.register_class(klass)
52
+ name = self.extract_suite_name_from_class(klass)
53
+ meta = Registry.suites[name] || {}
54
+ meta.merge!(:name => name,
55
+ :klass => klass)
56
+ meta
57
+ end
58
+
59
+
60
+ def self.extract_suite_name_from_path(path)
61
+ res = path.split('/')[-1]
62
+ res = res.split('.')[0]
63
+ res = res.downcase.sub(/_qlive$/, '')
64
+ res
65
+ end
66
+
67
+ def self.extract_suite_name_from_class(klass)
68
+ klass.name.underscore.sub(/_qlive$/, '')
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,14 @@
1
+ module Qlive
2
+ @qlive_config = {
3
+ :base_path => nil, # required. qlive-rails sets this to "#{Rails.root}/spec/qunits"
4
+ :url_prefix => '/qlive/sources',
5
+ :magic_param => 'qlive',
6
+ :js_support_relpath => '/qunit_support', # gets loaded before all of the qunit js tests
7
+ :skip_suite_reloader => false, # when true, does not re-crawl base_path looking for suites whenever a suite_name is missing
8
+ :gem_dev_mode => true
9
+ }
10
+
11
+ def self.setup
12
+ @qlive_config
13
+ end
14
+ end
@@ -0,0 +1,67 @@
1
+ require 'qlive/setup'
2
+ require 'qlive/qunit_assets'
3
+
4
+ module Qlive
5
+ module Suite
6
+ include QunitAssets
7
+
8
+ attr_reader :request, :session
9
+
10
+ InsertionPoints ||= [ 'after_head_open', 'before_head_close', 'after_body_open', 'before_body_close']
11
+
12
+ def self.included(base)
13
+ meta = Registry.register_class(base)
14
+ base.class_eval do
15
+ class << self
16
+ attr_reader :suite_meta_data
17
+ end
18
+ end
19
+ base.instance_variable_set(:@suite_meta_data, meta)
20
+
21
+ InsertionPoints.each do |place|
22
+ attr_accessor place
23
+
24
+ define_method "html_#{place}" do
25
+ htmls = instance_variable_get("@#{place}")
26
+ has_content = htmls.length > 0
27
+ htmls.unshift "\n<!-- Begin Qlive Insertions (#{place}) -->" if has_content
28
+ htmls << "<!-- End Qlive Insertions (#{place}) -->\n" if has_content
29
+ htmls.join("\n")
30
+ end
31
+ end
32
+ end
33
+
34
+
35
+
36
+ def prepare(args={})
37
+ @session = args[:session]
38
+ @request = args[:request]
39
+ InsertionPoints.each do |place|
40
+ instance_variable_set("@#{place}", [ ])
41
+ end
42
+ prepare_assets
43
+ end
44
+
45
+
46
+ def name
47
+ self.meta_data[:name]
48
+ end
49
+
50
+ def meta_data
51
+ self.class.suite_meta_data
52
+ end
53
+
54
+
55
+ def suite_name
56
+ self.name
57
+ end
58
+
59
+
60
+ protected
61
+
62
+ def before_each_request(rack_request)
63
+ # override to create server-side fixtures here for the qlive request
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,3 @@
1
+ module Qlive
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "qlive/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "qlive"
7
+ s.version = Qlive::VERSION
8
+ s.authors = ["ProxV"]
9
+ s.email = ["support@proxv.com"]
10
+ s.homepage = "https://github.com/proxv/qlive/"
11
+ s.summary = "run qunit tests against actual back-end server with prepared test fixtures"
12
+ s.description = s.summary
13
+
14
+ s.rubyforge_project = "qlive"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'rack', '~> 1.4'
22
+ s.add_development_dependency "rspec", '~> 2.8.0'
23
+ end
Binary file
@@ -0,0 +1,5 @@
1
+ $(document).ready(function() {
2
+ nextTick(function() {
3
+ QUnit.start();
4
+ });
5
+ });
@@ -0,0 +1,9 @@
1
+ class FancyWorkflowQlive
2
+ include Qlive::Suite
3
+ # include QliveHelper
4
+
5
+ def before_each_request(rack_request)
6
+ # login_as Factory(:user)
7
+ end
8
+
9
+ end
@@ -0,0 +1,5 @@
1
+ $(document).ready(function() {
2
+ module("post-new-recipe.js");
3
+
4
+ test("creation pages", 26, window.ns.goodQunitTestFunction);
5
+ });
@@ -0,0 +1,5 @@
1
+ $(document).ready(function() {
2
+ module("verify-creds.js");
3
+
4
+ test("permissions", 3, window.ns.permissionCheckB);
5
+ });
@@ -0,0 +1,51 @@
1
+ require File.expand_path("../../spec_helper.rb", __FILE__)
2
+
3
+ describe Qlive::Rack do
4
+ class HappyGoLuckyQlive
5
+ include Qlive::Suite
6
+
7
+ def before_each_request(rack_request)
8
+ rack_request.session[:logged_in_as] = 1255
9
+ end
10
+ end
11
+
12
+ before(:each) do
13
+ suite = HappyGoLuckyQlive.new
14
+ Qlive::Registry.stub!(:build_suite).and_return suite
15
+ end
16
+
17
+ let(:environment) { Rack::MockRequest.env_for('/webapp/tinfoiled?qlive=happy_go_lucky#frontpage') }
18
+ let(:application) { lambda{|env| [200, {'Content-Type' => 'text/html'}, [ html_page ]]} }
19
+ let(:middleware) do
20
+ Qlive::Rack.new(application, { :base_path => fixtures_base_path })
21
+ end
22
+
23
+ it "should insert qunit test resources when magic_param is present in query string" do
24
+ body = middleware.call(environment)[2].join('')
25
+ body.should match(/qunit\.js/)
26
+ end
27
+
28
+ it "should allow suite to modify session data" do
29
+ middleware.call(environment)
30
+ environment['rack.session'].should == {:logged_in_as => 1255} # see before_each_request
31
+ end
32
+
33
+ #todo: describe "magic param" do
34
+ # it "should do nothing when magic param is missing"
35
+ # it "should permit configuration of magic_param to use a query param other than 'qlive'"
36
+ #end
37
+
38
+
39
+ def html_page
40
+ <<-END.gsub(/^\s+/, '')
41
+ <html><head>
42
+ <title>Why Jasmine Is Annoying</title>
43
+ <script src='/app-ui.js'></script>
44
+ </head>
45
+ <body class="webapp">
46
+ <div class="app-content-holder"></div>
47
+ </body></html>
48
+ END
49
+ end
50
+
51
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path("../../spec_helper.rb", __FILE__)
2
+
3
+ describe Qlive::Registry, "find_suites" do
4
+ it "should find qlive suites" do
5
+ suites = Qlive::Registry.find_suites
6
+ suites.length.should > 0
7
+ suites['fancy_workflow'].should_not be_nil
8
+ end
9
+ end
10
+
11
+ describe Qlive::Registry, "build_suite" do
12
+
13
+ it "should instantiate suite and add class to meta data registry" do
14
+ suite = Qlive::Registry.build_suite('fancy_workflow')
15
+ suite.class.name.should == 'FancyWorkflowQlive'
16
+
17
+ end
18
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path("../../spec_helper.rb", __FILE__)
2
+
3
+ describe Qlive::Suite do
4
+ class BlueSuite
5
+ include Qlive::Suite
6
+
7
+ def before_each_request(rack_request)
8
+ @pretend_factory_girl = true
9
+ @pretend_devise_user_login = true
10
+ end
11
+ end
12
+
13
+ let(:suite) do
14
+ suite = BlueSuite.new
15
+ suite.prepare
16
+ suite.after_head_open << '<script> doSomethingEarly();</script>'
17
+ suite
18
+ end
19
+
20
+ it "should provide array of desired html at all insertion points" do
21
+ suite.after_head_open.length.should == 1
22
+ suite.html_after_head_open.should match(/doSomethingEarly/) # it also adds before & after comments
23
+ suite.html_before_body_close.should match(/qunit\.js/)
24
+ end
25
+
26
+ end
27
+
28
+
29
+ describe Qlive::Suite, "qunit source" do
30
+ before(:each) do
31
+ @suite = Qlive::Registry.build_suite('fancy_workflow')
32
+ @suite.prepare
33
+ end
34
+
35
+ it "should insert qunit resources and all js files in the same directory as the suite" do
36
+ source_tags = @suite.qunit_javascript_test_sources
37
+ source_tags.length.should == 2
38
+ source_tags.join("\n").should match(/#{Regexp.escape("/qlive/sources/fancy_workflow/post-new-recipe.js")}/)
39
+ end
40
+
41
+ end
42
+
43
+
44
+ describe Qlive::Suite, "insertion helper methods" do
45
+ class GreenSuite
46
+ include Qlive::Suite
47
+ end
48
+
49
+ let(:suite) { GreenSuite.new }
50
+
51
+ it "should not mess up metacoding too much" do
52
+ a = GreenSuite.new
53
+ b = GreenSuite.new
54
+ a.after_head_open = [ 8 ]
55
+ b.after_head_open = [ 9 ]
56
+ a.after_head_open[0].should == 8
57
+ b.after_head_open[0].should == 9
58
+ end
59
+ end
60
+
@@ -0,0 +1,2 @@
1
+ --color
2
+ --backtrace
@@ -0,0 +1,14 @@
1
+ QliveHome = File.expand_path('../..', __FILE__)
2
+ require 'rack/mock'
3
+ require "#{QliveHome}/lib/qlive"
4
+
5
+ def fixtures_base_path
6
+ "#{QliveHome}/spec/fixtures"
7
+ end
8
+
9
+
10
+ RSpec.configure do |config|
11
+ Qlive.setup[:base_path] = fixtures_base_path
12
+
13
+ end
14
+
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qlive
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - ProxV
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: &2152313360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.4'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2152313360
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &2152310660 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 2.8.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2152310660
36
+ description: run qunit tests against actual back-end server with prepared test fixtures
37
+ email:
38
+ - support@proxv.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - README.md
46
+ - Rakefile
47
+ - lib/qlive.rb
48
+ - lib/qlive/.DS_Store
49
+ - lib/qlive/dev_reload.rb
50
+ - lib/qlive/qunit_assets.rb
51
+ - lib/qlive/rack.rb
52
+ - lib/qlive/registry.rb
53
+ - lib/qlive/setup.rb
54
+ - lib/qlive/suite.rb
55
+ - lib/qlive/version.rb
56
+ - qlive.gemspec
57
+ - spec/.DS_Store
58
+ - spec/fixtures/qunit_support/start-qunit.js
59
+ - spec/fixtures/suites/fancy_workflow/fancy_workflow_qlive.rb
60
+ - spec/fixtures/suites/fancy_workflow/post-new-recipe.js
61
+ - spec/fixtures/suites/fancy_workflow/verify-creds.js
62
+ - spec/qlive/rack_spec.rb
63
+ - spec/qlive/registry_spec.rb
64
+ - spec/qlive/suite_spec.rb
65
+ - spec/spec.opts
66
+ - spec/spec_helper.rb
67
+ homepage: https://github.com/proxv/qlive/
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project: qlive
87
+ rubygems_version: 1.8.10
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: run qunit tests against actual back-end server with prepared test fixtures
91
+ test_files:
92
+ - spec/fixtures/qunit_support/start-qunit.js
93
+ - spec/fixtures/suites/fancy_workflow/fancy_workflow_qlive.rb
94
+ - spec/fixtures/suites/fancy_workflow/post-new-recipe.js
95
+ - spec/fixtures/suites/fancy_workflow/verify-creds.js
96
+ - spec/qlive/rack_spec.rb
97
+ - spec/qlive/registry_spec.rb
98
+ - spec/qlive/suite_spec.rb
99
+ - spec/spec.opts
100
+ - spec/spec_helper.rb