alfred_rails 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +20 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +209 -0
  7. data/Rakefile +5 -0
  8. data/alfred_rails.gemspec +45 -0
  9. data/app/assets/javascripts/alfred/sinon_adapter.js.coffee +35 -0
  10. data/app/assets/javascripts/alfred.js.coffee +61 -0
  11. data/bin/alfred +6 -0
  12. data/lib/alfred_rails/command_line.rb +62 -0
  13. data/lib/alfred_rails/configuration.rb +157 -0
  14. data/lib/alfred_rails/definition.rb +129 -0
  15. data/lib/alfred_rails/fixture_file.rb +70 -0
  16. data/lib/alfred_rails/mock.rb +14 -0
  17. data/lib/alfred_rails/rails.rb +14 -0
  18. data/lib/alfred_rails/registry.rb +84 -0
  19. data/lib/alfred_rails/request.rb +38 -0
  20. data/lib/alfred_rails/runner.rb +116 -0
  21. data/lib/alfred_rails/scenario.rb +99 -0
  22. data/lib/alfred_rails/scenario_dsl.rb +83 -0
  23. data/lib/alfred_rails/ui.rb +90 -0
  24. data/lib/alfred_rails/version.rb +3 -0
  25. data/lib/alfred_rails.rb +99 -0
  26. data/lib/generators/alfred/controller/controller_generator.rb +24 -0
  27. data/lib/generators/alfred/controller/templates/alfred.erb +7 -0
  28. data/lib/generators/alfred/install/install_generator.rb +85 -0
  29. data/lib/generators/alfred/install/templates/alfred_helper.erb +23 -0
  30. data/lib/tasks/alfred.rake +6 -0
  31. data/spec/command_line_spec.rb +64 -0
  32. data/spec/configuration_spec.rb +86 -0
  33. data/spec/definition_spec.rb +135 -0
  34. data/spec/fixture_file_spec.rb +60 -0
  35. data/spec/fixtures/database.yml +4 -0
  36. data/spec/generators/controller/controller_generator_spec.rb +23 -0
  37. data/spec/generators/install/install_generator_spec.rb +56 -0
  38. data/spec/javascripts/alfred/sinon_adapter_spec.js.coffee +33 -0
  39. data/spec/javascripts/alfred_spec.js.coffee +46 -0
  40. data/spec/javascripts/spec_helper.coffee +5 -0
  41. data/spec/mock_spec.rb +18 -0
  42. data/spec/registry_spec.rb +78 -0
  43. data/spec/request_spec.rb +32 -0
  44. data/spec/runner_spec.rb +179 -0
  45. data/spec/scenario_dsl_spec.rb +62 -0
  46. data/spec/scenario_spec.rb +24 -0
  47. data/spec/spec_helper.rb +24 -0
  48. data/spec/support/application.rb +21 -0
  49. data/spec/support/controllers/api/v1/posts_controller.rb +14 -0
  50. data/spec/support/controllers/api/v1/users_controller.rb +14 -0
  51. data/spec/support/lib/response_proxy.rb +11 -0
  52. data/spec/support/models/post.rb +1 -0
  53. data/spec/support/models/user.rb +1 -0
  54. data/spec/support/rails.rb +14 -0
  55. data/spec/support/routes.rb +9 -0
  56. data/spec/support/schema.rb +16 -0
  57. data/spec/teaspoon_env.rb +14 -0
  58. data/spec/ui_spec.rb +72 -0
  59. metadata +316 -0
@@ -0,0 +1,129 @@
1
+ module Alfred
2
+ module Definition
3
+
4
+ ##
5
+ # Defines a new Alfred scenario.
6
+ #
7
+ # === Params
8
+ #
9
+ # [block (Block)] the block to perform
10
+ #
11
+ # === Examples
12
+ #
13
+ # Alfred.define do
14
+ # setup do
15
+ # sign_in :user, create(:user)
16
+ # end
17
+ #
18
+ # controller Api::V1::PostsController do
19
+ # scenario 'update post by manager' do
20
+ # setup do
21
+ # create(:poset, :title => 'Alfred is awesome', :body => 'It saves me time')
22
+ # end
23
+ #
24
+ # patch :update, {
25
+ # :format => :json,
26
+ # :id => 1,
27
+ # :post => {
28
+ # :title => 'Alfred rocks!'
29
+ # }
30
+ # }
31
+ # end
32
+ # end
33
+ #
34
+ # scenario 'update post by manager' do
35
+ # controller Api::V1::PostsController
36
+ # end
37
+ # end
38
+ #
39
+ def define(&block)
40
+ Thread.current[:controller] = nil
41
+ Thread.current[:setup] = []
42
+
43
+ DSL.run(block)
44
+ end
45
+
46
+ class DSL
47
+
48
+ ##
49
+ # Define a new scenario.
50
+ #
51
+ # === Params
52
+ #
53
+ # [name (Symbol)] the name of the scenario
54
+ # [block (Block)] the block to perform
55
+ #
56
+ def scenario(name, &block)
57
+ scenario = Scenario.new(name)
58
+ scenario.controller = Thread.current[:controller]
59
+
60
+ Thread.current[:setup].each { |setup| scenario.setups << setup }
61
+
62
+ dsl = ScenarioDSL.new(scenario)
63
+ dsl.instance_eval(&block) if block_given?
64
+
65
+ Alfred.registry.register(scenario.controller_name, scenario)
66
+ end
67
+
68
+ ##
69
+ # Define the controller.
70
+ #
71
+ # === Params
72
+ #
73
+ # [controller (ActionController::Base)] the controller
74
+ # [block (Block)] the block to perform
75
+ #
76
+ def controller(controller, &block)
77
+ Thread.current[:controller] = controller
78
+
79
+ instance_eval(&block)
80
+ end
81
+
82
+ ##
83
+ # Define setup for every scenario.
84
+ #
85
+ # === Params
86
+ #
87
+ # [block (Block)] the block to setup on Alfred Scenario
88
+ #
89
+ # === Examples
90
+ #
91
+ # Alfred.define do
92
+ # setup do
93
+ # SomeController.stub(:current_user).and_return(create(:user))
94
+ # end
95
+ #
96
+ # scenario 'alfred is awesome' do
97
+ #
98
+ # end
99
+ # end
100
+ #
101
+ def setup(&block)
102
+ Thread.current[:setup] << block
103
+ end
104
+
105
+ ##
106
+ # Runs the code inside a block.
107
+ #
108
+ # === Params
109
+ #
110
+ # [block (Block)] the block to run
111
+ #
112
+ # === Examples
113
+ #
114
+ # new.run do
115
+ # setup do
116
+ # User.create(:name => 'John Doe')
117
+ # end
118
+ # end
119
+ #
120
+ # #=> Will call the setup method with a new block
121
+ #
122
+ def self.run(block)
123
+ new.instance_eval(&block)
124
+ end
125
+
126
+ end # DSL
127
+
128
+ end # Definition
129
+ end # Alfred
@@ -0,0 +1,70 @@
1
+ module Alfred
2
+ class FixtureFile
3
+
4
+ attr_reader :response, :controller_name, :action, :name
5
+
6
+ def initialize(response, controller_name, action, name)
7
+ @response = response
8
+ @controller_name = controller_name
9
+ @action = action
10
+ @name = name
11
+ end
12
+
13
+ ##
14
+ # Returns the path name to save the fixture.
15
+ #
16
+ def path
17
+ "#{Alfred.fixture_path}/#{controller_name}/#{action}"
18
+ end
19
+
20
+ ##
21
+ # Returns the folder name to save the fixture.
22
+ #
23
+ def filename
24
+ "#{path}/#{name.underscore}.js"
25
+ end
26
+
27
+ ##
28
+ # Saves the fixture.
29
+ #
30
+ def save
31
+ FileUtils.mkdir_p(path)
32
+
33
+ File.open(filename, 'w') do |fixture|
34
+ fixture.write(to_js)
35
+ end
36
+ end
37
+
38
+ ##
39
+ # Outputs the content to a JavaScript format wrapped around Alfred.register JavaScript method
40
+ #
41
+ def to_js
42
+ "Alfred.register(#{content.to_json})"
43
+ end
44
+
45
+ ##
46
+ # Scenario content with meta data outputted as a hash.
47
+ #
48
+ def content
49
+ @content ||= {
50
+ :name => name,
51
+ :action => "#{controller_name}/#{action}",
52
+ :meta => meta,
53
+ :response => response.body
54
+ }
55
+ end
56
+
57
+ ##
58
+ # Scenario meta data, such as path, method, status and content type
59
+ #
60
+ def meta
61
+ {
62
+ :path => response.request.fullpath,
63
+ :method => response.request.method,
64
+ :status => response.status,
65
+ :type => response.content_type,
66
+ }
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,14 @@
1
+ module Alfred
2
+ class Mock
3
+
4
+ ##
5
+ # Initialize mocking framework based on configuration.
6
+ #
7
+ def initialize
8
+ if Alfred.configuration.mock_with == :rspec
9
+ RSpec::Mocks::setup(Object.new)
10
+ end
11
+ end
12
+
13
+ end # Mock
14
+ end # Alfred
@@ -0,0 +1,14 @@
1
+ module Alfred
2
+ module Rails
3
+ class Engine < ::Rails::Engine; end
4
+
5
+ # :nocov:
6
+ class Railtie < ::Rails::Railtie
7
+ rake_tasks do
8
+ load "tasks/alfred.rake"
9
+ end
10
+ end # Railtie
11
+ # :nocov:
12
+
13
+ end # Rails
14
+ end # Alfred
@@ -0,0 +1,84 @@
1
+ module Alfred
2
+ class Registry
3
+
4
+ attr_accessor :items
5
+
6
+ def initialize
7
+ @items = {}
8
+ end
9
+
10
+ ##
11
+ # Register a new Scenario.
12
+ #
13
+ # === Params
14
+ #
15
+ # [identifier (String)] the scenario identifier
16
+ # [item (Scenario)] the scenario object
17
+ #
18
+ # === Example
19
+ #
20
+ # Alfred.registry.register('api/v1/posts_controller', #Alfred::Scenario:0x007f933a6aaa98>)
21
+ #
22
+ def register(identifier, item)
23
+ @items[identifier] ||= []
24
+ @items[identifier] << item
25
+ end
26
+
27
+ ##
28
+ # Check if controller and action are already registered.
29
+ #
30
+ # === Params
31
+ #
32
+ # [identifier (String)] the scenario identifier
33
+ #
34
+ # === Example
35
+ #
36
+ # Scenario.registry.registered?('api/v1/posts_controller')
37
+ #
38
+ # === Returns
39
+ #
40
+ # [found (TrueClass|FalseClass)] wheter found or not
41
+ #
42
+ def registered?(identifier)
43
+ @items.key?(identifier)
44
+ end
45
+
46
+ ##
47
+ # Finds a Scenario by its identifier.
48
+ #
49
+ # === Params
50
+ #
51
+ # [identifier (String)] unique identifier
52
+ #
53
+ # === Examples
54
+ #
55
+ # Alfred.registry.find("api/v1/sessions_controller")
56
+ # #=> [#<Alfred::Scenario:0x007f933a6aaa98>]
57
+ #
58
+ # === Returns
59
+ #
60
+ # [items (Array)] returns all the items for identifier
61
+ #
62
+ def find(identifier)
63
+ if registered?(identifier)
64
+ @items[identifier]
65
+ end
66
+ end
67
+ alias :[] :find
68
+
69
+ ##
70
+ # Returns all the items.
71
+ #
72
+ def all
73
+ @items.values.flatten
74
+ end
75
+
76
+ ##
77
+ # Removes al items from registry.
78
+ #
79
+ def clear!
80
+ @items.clear
81
+ end
82
+
83
+ end # Registry
84
+ end # Alfred
@@ -0,0 +1,38 @@
1
+ module Alfred
2
+ class Request < ActionController::TestCase
3
+
4
+ ##
5
+ # Runs setup block before it runs the controller action.
6
+ #
7
+ # [block (Block)] the block to execute
8
+ #
9
+ # === Example
10
+ #
11
+ # request = Alfred::Request.new('test')
12
+ # request.setup do
13
+ # User.create(:name => 'John Doe')
14
+ # end
15
+ #
16
+ def _setup(&block)
17
+ instance_eval(&block) if block_given?
18
+ end
19
+
20
+ ##
21
+ # Sets the controller instance to test.
22
+ #
23
+ # === Params
24
+ #
25
+ # [controller_instance (ActionController::Base#new)] the controller to test
26
+ #
27
+ # === Example
28
+ #
29
+ # request = Alfred::Request.new('test')
30
+ # request.set_controller(Api::V1::UsersController)
31
+ #
32
+ def set_controller(controller)
33
+ @routes = ::Rails.application.routes
34
+ @controller = controller.new
35
+ end
36
+
37
+ end # Request
38
+ end # Alfred
@@ -0,0 +1,116 @@
1
+ require 'ruby-progressbar'
2
+
3
+ module Alfred
4
+ class Runner
5
+
6
+ attr_accessor :files, :controllers, :matches, :scenarios
7
+
8
+ ##
9
+ # Initialize a new runner and find and run scenario's.
10
+ # Runs al scenarios if files are empty.
11
+ #
12
+ # === Params
13
+ #
14
+ # [files (Array)] the files to lookup
15
+ #
16
+ # === Example
17
+ #
18
+ # Run specific scenario's:
19
+ #
20
+ # Runner.new(['spec/alfreds/some_controller.rb'])
21
+ # #=> Will run scenario's for some_controller
22
+ #
23
+ # Run all scenario's:
24
+ #
25
+ # Runner.new
26
+ # #=> Will run all scenario's
27
+ #
28
+ def initialize(files=[])
29
+ @files = files
30
+ @controllers = controllers_for_files
31
+ @matches = matches_for_controllers
32
+ @scenarios = scenarios_for_controllers
33
+
34
+ run if @scenarios.any?
35
+ end
36
+
37
+ private
38
+
39
+ ##
40
+ # Returns controller_names for files in @files.
41
+ #
42
+ def controllers_for_files
43
+ if @files.any?
44
+ @files.map do |file|
45
+ file
46
+ .gsub('.rb', '')
47
+ .gsub("#{::Alfred.configuration.test_path}/alfreds/", '')
48
+ end
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Returns registered scenarios for @controllers.
54
+ # Returns all scenarios if @controllers is nil.
55
+ #
56
+ def scenarios_for_controllers
57
+ if @controllers
58
+ scenarios = []
59
+ @controllers.each do |controller|
60
+ scenarios << Alfred.registry[controller]
61
+ end
62
+ scenarios.flatten.compact
63
+ else
64
+ Alfred.registry.all
65
+ end
66
+ end
67
+
68
+ ##
69
+ # Returns controllers found in registry.
70
+ #
71
+ def matches_for_controllers
72
+ if @controllers
73
+ matches = []
74
+ @controllers.each do |controller|
75
+ if Alfred.registry.registered?(controller)
76
+ matches << "#{Alfred.configuration.test_path}/alfreds/#{controller}.rb"
77
+ end
78
+ end
79
+ matches
80
+ end
81
+ end
82
+
83
+ ##
84
+ # Display runner start message.
85
+ #
86
+ def start_message
87
+ message = @matches ? @matches.join(' ') : "all scenario's"
88
+ UI.info("Alfred: Serving #{message}", :empty_line_before => true)
89
+ end
90
+
91
+ ##
92
+ # Run scenarios defined in @scenarios
93
+ #
94
+ def run
95
+ start_message
96
+
97
+ progress = ProgressBar.create(
98
+ :starting_at => 0,
99
+ :format => '%c/%C: |%B| %a',
100
+ :total => @scenarios.size
101
+ )
102
+
103
+ message = UI.new(:empty_line_before => true, :empty_line_after => true)
104
+
105
+ @scenarios.each do |scenario|
106
+ scenario.run # Run the scenario
107
+ progress.increment # Increment progressbar
108
+ message.queue(scenario.file.filename) # Add filename to the message queue
109
+ end
110
+
111
+ message.queue('Alfred served the following fixtures:', :timestamp => true, :before => true)
112
+ message.display
113
+ end
114
+
115
+ end # Runner
116
+ end # Alfred
@@ -0,0 +1,99 @@
1
+ module Alfred
2
+ class Scenario
3
+
4
+ ## Attributes
5
+
6
+ attr_accessor :name, :setups, :method, :controller, :action, :params, :identifier
7
+
8
+ ##
9
+ # Initialize a new Alfred scenario.
10
+ #
11
+ # === Params
12
+ #
13
+ # [name (String)] name of the scenario
14
+ #
15
+ # === Example
16
+ #
17
+ # Scenario.new('admin permissions')
18
+ #
19
+ def initialize(name)
20
+ @name = name.downcase.gsub(' ', '_')
21
+ @setups = []
22
+ end
23
+
24
+ ##
25
+ # Returns the controller name based on controller.
26
+ #
27
+ # === Examples
28
+ #
29
+ # scenario = Scenario.new('test')
30
+ # scenario.controller = Api::V1::UserController
31
+ #
32
+ # scenario.controller_name #=> 'api/v1/users_controller'
33
+ #
34
+ def controller_name
35
+ controller.name.underscore
36
+ end
37
+
38
+ ##
39
+ # Runs the scenario.
40
+ #
41
+ def run
42
+ setup_request
43
+ apply_setup
44
+ perform_request
45
+
46
+ ## Persist response to disk
47
+ file.save
48
+ end
49
+
50
+ ##
51
+ # Initialize or return existing file instance.
52
+ #
53
+ def file
54
+ @file ||= FixtureFile.new(@response, controller_name, action, name)
55
+ end
56
+
57
+ private
58
+
59
+ ##
60
+ # Initialize a new Request.
61
+ #
62
+ def setup_request
63
+ controller.send(:include, ::Rails.application.routes.url_helpers)
64
+
65
+ ## Initialize mocking framework
66
+ Alfred::Mock.new
67
+
68
+ ## Setup request
69
+ @request = Request.new(name)
70
+ @request.set_controller(controller)
71
+ @request.setup_controller_request_and_response
72
+ end
73
+
74
+ ##
75
+ # Apply global and scenario setups to request.
76
+ #
77
+ def apply_setup
78
+ ## Run global setup before example
79
+ Alfred.configuration.setup.each do |setup|
80
+ @request._setup(&setup)
81
+ end
82
+
83
+ ## Run setup blocks for scenario
84
+ setups.each { |setup| @request._setup(&setup) }
85
+ end
86
+
87
+ ##
88
+ # Perform request and assign response.
89
+ #
90
+ def perform_request
91
+ ## Perform request
92
+ @request.send(method, action, params)
93
+
94
+ ## Set response
95
+ @response = @request.response
96
+ end
97
+
98
+ end # Scenario
99
+ end # Alfred
@@ -0,0 +1,83 @@
1
+ module Alfred
2
+ class ScenarioDSL
3
+
4
+ attr_accessor :scenario
5
+
6
+ def initialize(scenario)
7
+ @scenario = scenario
8
+ end
9
+
10
+ ##
11
+ # Apply setup to Scenario instance.
12
+ #
13
+ # === Params
14
+ #
15
+ # [block (Block)] the block to perform.
16
+ #
17
+ # === Example
18
+ #
19
+ # setup do
20
+ # User.create(:name => 'John Doe')
21
+ # end
22
+ #
23
+ def setup(&block)
24
+ scenario.setups << block
25
+ end
26
+
27
+ ##
28
+ # Set the controller to test.
29
+ #
30
+ # === Params
31
+ #
32
+ # [controller (ActionController::Base)] the controller to test
33
+ #
34
+ # === Example
35
+ #
36
+ # controller(ActionController::Base)
37
+ #
38
+ def controller(controller)
39
+ scenario.controller = controller
40
+ end
41
+
42
+ ##
43
+ # Respond to request methods
44
+ #
45
+ # === Examples
46
+ #
47
+ # post :create, :post => { :title => 'Some title' }
48
+ # get :show, :id => 1
49
+ #
50
+ [
51
+ :get,
52
+ :post,
53
+ :patch,
54
+ :put,
55
+ :delete,
56
+ :head
57
+ ].each do |method|
58
+ define_method(method) do |*args|
59
+ setup_request_data(method, *args)
60
+ end
61
+ end
62
+
63
+ ##
64
+ # Setup request data.
65
+ #
66
+ # === Params
67
+ #
68
+ # [method (Sym)] request method
69
+ # [action (Sym)] controller and action
70
+ # [params (Hash)] request params
71
+ #
72
+ # === Example
73
+ #
74
+ # setup_request(:get, :show, :id => 1)
75
+ #
76
+ def setup_request_data(method, action, params={})
77
+ scenario.method = method
78
+ scenario.action = action
79
+ scenario.params = params
80
+ end
81
+
82
+ end # ScenarioDSL
83
+ end # Alfred