alfred_rails 0.0.1.alpha

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 (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