gaq 0.2.0

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 (70) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +15 -0
  3. data/Guardfile +23 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +102 -0
  6. data/Rakefile +1 -0
  7. data/gaq.gemspec +22 -0
  8. data/lib/gaq.rb +3 -0
  9. data/lib/gaq/class_cache.rb +32 -0
  10. data/lib/gaq/command_language.rb +145 -0
  11. data/lib/gaq/configuration.rb +159 -0
  12. data/lib/gaq/controller_facade.rb +15 -0
  13. data/lib/gaq/controller_handle.rb +93 -0
  14. data/lib/gaq/dsl_target.rb +51 -0
  15. data/lib/gaq/dsl_target_factory.rb +64 -0
  16. data/lib/gaq/flash_commands_adapter.rb +48 -0
  17. data/lib/gaq/interprets_config.rb +13 -0
  18. data/lib/gaq/railtie.rb +40 -0
  19. data/lib/gaq/snippet_renderer.rb +44 -0
  20. data/lib/gaq/version.rb +3 -0
  21. data/spec-dummy/.rspec +1 -0
  22. data/spec-dummy/README.rdoc +261 -0
  23. data/spec-dummy/Rakefile +7 -0
  24. data/spec-dummy/app/assets/images/rails.png +0 -0
  25. data/spec-dummy/app/assets/javascripts/application.js +13 -0
  26. data/spec-dummy/app/assets/stylesheets/application.css +13 -0
  27. data/spec-dummy/app/controllers/application_controller.rb +3 -0
  28. data/spec-dummy/app/controllers/integration_spec_controller.rb +22 -0
  29. data/spec-dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec-dummy/app/views/integration_spec/view.erb +0 -0
  31. data/spec-dummy/app/views/layouts/application.html.erb +16 -0
  32. data/spec-dummy/config.ru +4 -0
  33. data/spec-dummy/config/application.rb +64 -0
  34. data/spec-dummy/config/boot.rb +6 -0
  35. data/spec-dummy/config/environment.rb +5 -0
  36. data/spec-dummy/config/environments/development.rb +26 -0
  37. data/spec-dummy/config/environments/production.rb +51 -0
  38. data/spec-dummy/config/environments/test_dynamic.rb +39 -0
  39. data/spec-dummy/config/environments/test_static.rb +38 -0
  40. data/spec-dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/spec-dummy/config/initializers/inflections.rb +15 -0
  42. data/spec-dummy/config/initializers/mime_types.rb +5 -0
  43. data/spec-dummy/config/initializers/secret_token.rb +7 -0
  44. data/spec-dummy/config/initializers/session_store.rb +8 -0
  45. data/spec-dummy/config/initializers/wrap_parameters.rb +10 -0
  46. data/spec-dummy/config/locales/en.yml +5 -0
  47. data/spec-dummy/config/routes.rb +8 -0
  48. data/spec-dummy/db/seeds.rb +7 -0
  49. data/spec-dummy/public/404.html +26 -0
  50. data/spec-dummy/public/422.html +26 -0
  51. data/spec-dummy/public/500.html +25 -0
  52. data/spec-dummy/public/favicon.ico +0 -0
  53. data/spec-dummy/public/robots.txt +5 -0
  54. data/spec-dummy/script/rails +6 -0
  55. data/spec-dummy/spec/common_spec_methods.rb +88 -0
  56. data/spec-dummy/spec/features/dynamic_config_spec.rb +21 -0
  57. data/spec-dummy/spec/features/next_request_spec.rb +27 -0
  58. data/spec-dummy/spec/features/presence_spec.rb +64 -0
  59. data/spec-dummy/spec/spec_helper.rb +41 -0
  60. data/spec/lib/gaq/class_cache_spec.rb +62 -0
  61. data/spec/lib/gaq/command_language_spec.rb +267 -0
  62. data/spec/lib/gaq/configuration_spec.rb +233 -0
  63. data/spec/lib/gaq/controller_facade_spec.rb +29 -0
  64. data/spec/lib/gaq/controller_handle_spec.rb +510 -0
  65. data/spec/lib/gaq/dsl_target_factory_spec.rb +163 -0
  66. data/spec/lib/gaq/dsl_target_spec.rb +87 -0
  67. data/spec/lib/gaq/flash_commands_adapter_spec.rb +116 -0
  68. data/spec/lib/gaq/interprets_config_spec.rb +37 -0
  69. data/spec/lib/gaq/snippet_renderer_spec.rb +60 -0
  70. metadata +159 -0
@@ -0,0 +1,233 @@
1
+ require 'gaq/configuration'
2
+
3
+ require 'gaq/interprets_config'
4
+ require 'active_support/string_inquirer'
5
+
6
+ module Gaq
7
+ describe Configuration do
8
+ let(:rails) { subject.rails_config }
9
+
10
+ describe "rails exposed config object" do
11
+ describe ".declare_variable" do
12
+ describe "variable setup" do
13
+ let(:variable) do
14
+ subject.variables.should have(1).variable
15
+ subject.variables["my_variable"]
16
+ end
17
+
18
+ it "sets up variable name and slot correctly" do
19
+ rails.declare_variable("my_variable", slot: 2)
20
+
21
+ variable.name.should be == "my_variable"
22
+ variable.slot.should be 2
23
+ end
24
+
25
+ it "default to scope code 3" do
26
+ rails.declare_variable("my_variable", slot: 1)
27
+
28
+ variable.scope.should be 3
29
+ end
30
+
31
+ it "correctly sets up scope, given as symbol" do
32
+ rails.declare_variable("my_variable", slot: 1, scope: :visitor)
33
+
34
+ variable.scope.should be 1
35
+ end
36
+
37
+ it "correctly sets up scope, given as Fixnum" do
38
+ rails.declare_variable("my_variable", slot: 1, scope: 1)
39
+
40
+ variable.scope.should be 1
41
+ end
42
+
43
+ it "complains about unknown scope" do
44
+ expect do
45
+ rails.declare_variable("my_variable", slot: 1, scope: //)
46
+ end.to raise_exception(Configuration::VariableException)
47
+ end
48
+ end
49
+
50
+ it "complains about an invalid slot"
51
+
52
+ it "complains about a taken slot" do
53
+ rails.declare_variable("my_variable", slot: 1)
54
+ expect do
55
+ rails.declare_variable("my_other_variable", slot: 1)
56
+ end.to raise_exception Configuration::VariableException
57
+ end
58
+
59
+ it "complains about a taken name" do
60
+ rails.declare_variable("my_variable", slot: 1)
61
+ expect do
62
+ rails.declare_variable("my_variable", slot: 2)
63
+ end.to raise_exception Configuration::VariableException
64
+ end
65
+ end
66
+
67
+ describe ".additional_trackers=" do
68
+ it "complains about bad tracker names" do
69
+ pending "could not find out about that in the docs"
70
+ # probably, leading underscore is bad
71
+ end
72
+
73
+ it "makes tracker configs available" do
74
+ rails.additional_trackers = [:foo, :bar]
75
+
76
+ rails.tracker(:foo).should_not be rails.tracker(:bar)
77
+ end
78
+
79
+ it "tolerates symbols as well as strings" do
80
+ rails.additional_trackers = [:foo, "bar"]
81
+
82
+ rails.tracker(:foo).should_not be rails.tracker(:bar)
83
+ end
84
+
85
+ it "complains about name collision" do
86
+ expect { rails.additional_trackers = ["foo", "foo"] }.to raise_exception
87
+ end
88
+
89
+ it "complains about name collision even if symbol and string is used" do
90
+ expect { rails.additional_trackers = [:foo, "foo"] }.to raise_exception
91
+ end
92
+ end
93
+
94
+ def find_tracker_config_by_name(name)
95
+ name = name.to_s unless name.nil?
96
+ result = subject.tracker_config(name)
97
+ result.should_not be_nil
98
+ result
99
+ end
100
+
101
+ describe ".tracker" do
102
+ it "complains about a non-existent tracker name" do
103
+ expect{ rails.tracker(:nonexistent) }.to raise_exception
104
+ end
105
+
106
+ it "returns something for a valid tracker name" do
107
+ rails.additional_trackers = [:foo]
108
+
109
+ rails.tracker(:foo).should_not be_nil
110
+ end
111
+
112
+ it "tolerates symbols as well as strings" do
113
+ rails.additional_trackers = [:foo]
114
+
115
+ rails.tracker(:foo).should be rails.tracker("foo")
116
+ end
117
+
118
+ it "delegates tracker setting setters to tracker configs" do
119
+ rails.additional_trackers = [:foo]
120
+
121
+ rails_tracker = rails.tracker(:foo)
122
+ rails_tracker.web_property_id = "web property id"
123
+ rails_tracker.track_pageview = :production
124
+
125
+ tracker_config = find_tracker_config_by_name(:foo)
126
+ tracker_config.web_property_id.should be == "web property id"
127
+ tracker_config.track_pageview.should be :production
128
+ end
129
+ end
130
+
131
+ it "delegates tracker setting setters to default tracker rails config object" do
132
+ rails.web_property_id = "bla"
133
+
134
+ default_tracker_config = find_tracker_config_by_name(nil)
135
+
136
+ default_tracker_config.web_property_id.should be == "bla"
137
+ end
138
+ end
139
+
140
+ describe "tracker_config" do
141
+ it "returns nil when no tracker config by given name" do
142
+ subject.tracker_config('bogus').should be_nil
143
+ end
144
+
145
+ it "returns a different object per tracker name" do
146
+ rails.additional_trackers = [:foo, :bar]
147
+
148
+ subject.tracker_config('foo').should_not be subject.tracker_config('bar')
149
+ end
150
+
151
+ it "only accepts tracker names as strings" do
152
+ rails.additional_trackers = [:foo, :bar]
153
+
154
+ subject.tracker_config(:foo).should be_nil
155
+ end
156
+ end
157
+
158
+ describe "tracker_names" do
159
+ it "initially is [nil]" do
160
+ subject.tracker_names.should be == [nil]
161
+ end
162
+
163
+ context "after gaq.additional_trackers = [:foo, :bar]" do
164
+ before do
165
+ rails.additional_trackers = [:foo, :bar]
166
+ end
167
+
168
+ it "contains nil, 'foo' and 'bar'" do
169
+ subject.tracker_names.should have(3).tracker_names
170
+ subject.tracker_names.should include(nil)
171
+ subject.tracker_names.should include('foo')
172
+ subject.tracker_names.should include('bar')
173
+ end
174
+ end
175
+ end
176
+
177
+ describe "#render_ga_js?" do
178
+ let(:environment) do
179
+ ActiveSupport::StringInquirer.new(example.metadata[:env].to_s)
180
+ end
181
+
182
+ def result
183
+ subject.render_ga_js?(environment)
184
+ end
185
+
186
+
187
+ describe "this StringInquirer setup" do
188
+ it "works as expected", env: :development do
189
+ environment.should be_development
190
+ environment.should_not be_production
191
+ end
192
+ end
193
+
194
+ context "with rails_config.render_ga_js = true or false" do
195
+ it "reports those values " do
196
+ rails.render_ga_js = true
197
+ result.should be == true
198
+
199
+ rails.render_ga_js = false
200
+ result.should be == false
201
+ end
202
+ end
203
+
204
+ context "with rails_config.render_ga_ja = some symbol" do
205
+ it "compares with given environment", env: :production do
206
+ rails.render_ga_js = :production
207
+ result.should be == true
208
+
209
+ rails.render_ga_js = :development
210
+ result.should be == false
211
+ end
212
+ end
213
+
214
+ context "with rails_config.render_ga_ja = Array of symbols" do
215
+ it "compares with given environment", env: :production do
216
+ rails.render_ga_js = [:production, :test]
217
+ result.should be == true
218
+
219
+ rails.render_ga_js = [:development, :test]
220
+ result.should be == false
221
+ end
222
+ end
223
+
224
+ context "with rails_config.render_ga_ja = callable object (for interpret_config)" do
225
+ it "passes it through" do
226
+ lmbda = ->{}
227
+ rails.render_ga_js = lmbda
228
+ result.should be lmbda
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,29 @@
1
+ require 'gaq/controller_facade'
2
+
3
+ module Gaq
4
+ describe ControllerFacade do
5
+ let(:flash) { Object.new }
6
+ let(:controller) do
7
+ Struct.new(:flash).new(flash)
8
+ end
9
+
10
+ subject do
11
+ described_class.new(controller)
12
+ end
13
+
14
+ describe '#flash' do
15
+ it "returns controller's flash" do
16
+ subject.flash.should be(flash)
17
+ end
18
+ end
19
+
20
+ describe '#evaluate_config_lambda' do
21
+ it "calls the lambda, passing controller, returning lambda result" do
22
+ lmbda = ->(*args) { args }
23
+ result = subject.evaluate_config_lambda(lmbda)
24
+ result.should have(1).item
25
+ result.first.should be(controller)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,510 @@
1
+ require 'gaq/controller_handle'
2
+ require 'gaq/configuration'
3
+ require 'gaq/class_cache'
4
+
5
+ RSpec::Matchers.define :command_segments do
6
+ match do |segments|
7
+ next false unless segments.is_a?(Array) and segments.length >= 1
8
+ first_segment = segments.first
9
+ command, tracker = first_segment.split('.', 2).reverse
10
+
11
+ (!@first_segment || first_segment == @first_segment) &&
12
+ (!@tracker_name || tracker.to_s == @tracker_name)
13
+ end
14
+
15
+ chain :starting_with do |first_segment|
16
+ @first_segment = first_segment
17
+ end
18
+
19
+ chain :for_tracker do |tracker_name|
20
+ @tracker_name = tracker_name.to_s
21
+ end
22
+
23
+ chain :for_default_tracker do
24
+ @tracker_name = ''
25
+ end
26
+ end
27
+
28
+ describe "custom matcher" do
29
+ it "detects commands" do
30
+ [['foo']].should include(command_segments.starting_with('foo'))
31
+ [['foo']].should_not include(command_segments.starting_with('bar'))
32
+ [['tracker.foo']].should_not include(command_segments.starting_with('foo'))
33
+ [['tracker.foo']].should include(command_segments.starting_with('tracker.foo'))
34
+
35
+ [['foo']].should include(command_segments.for_default_tracker)
36
+ [['foo']].should_not include(command_segments.for_tracker('tracker'))
37
+ [['tracker.foo']].should include(command_segments.for_tracker('tracker'))
38
+ [['tracker.foo']].should_not include(command_segments.for_default_tracker)
39
+ end
40
+ end
41
+
42
+ module Gaq
43
+ describe ControllerHandle do
44
+ describe "#finalized_commands_as_segments" do
45
+ # This is more like an integration test. Many things are stubbed by real representatives,
46
+ # e.g. a real CommandLanguage object (because that's easier).
47
+ # The purpose of these examples is to assert what commands are rendered and what are
48
+ # placed in the flash, under different circumstances, namely,
49
+ # configurations and relevant data initially found in flash.
50
+
51
+ # Assertions are made against
52
+ # * #finalized_commands_as_segments results (see let(:result)) and
53
+ # * commands_pushed_to_flash
54
+ # Initial flash input is placed in
55
+ # * commands_from_flash
56
+ # For test convenience, all three use the same format, namely an array of commands
57
+ # represented as command segments. The language is used for the necessary conversion.
58
+ # Emptiness of commands_pushed_to_flash is automatically asserted unless the
59
+ # push_to_flash: true metadata is present.
60
+
61
+ # The result array is implicitly checked to comply to certain ordering assumptions (fex.
62
+ # a tracker must be initialized with _setAccount before anything else is done with it).
63
+ # See let(:result) for details.
64
+
65
+ let(:stubbed_controller_facade) { double "controller facade" }
66
+
67
+ let(:stubbed_language) do
68
+ # we use the actual implementation, given that this spec is at the highest level of all
69
+ result = CommandLanguage.new
70
+ CommandLanguage.declare_language_on(result)
71
+ CommandLanguage.define_transformations_on(result)
72
+ result
73
+ end
74
+
75
+ let(:stubbed_configuration) do
76
+ Configuration.new
77
+ end
78
+
79
+ # convenience. think "config.gaq", so rails_config.track_event would be config.gaq.track_event in the real world
80
+ let(:rails_config) { stubbed_configuration.rails_config }
81
+
82
+ let(:commands_from_flash) { [] }
83
+ let(:commands_pushed_to_flash) { [] }
84
+
85
+ let(:stubbed_flash_commands_adapter) do
86
+ result = double("flash_commands_adapter")
87
+
88
+ # for test convenience, convert between plain "segments" arrays and proper command objects
89
+ # this depends on features from language
90
+
91
+ result.stub(:commands_from_flash) do
92
+ stubbed_language.commands_from_flash_items(commands_from_flash)
93
+ end
94
+
95
+ result.stub(:<<) do |item|
96
+ item = stubbed_language.commands_to_flash_items([item]).first
97
+ commands_pushed_to_flash << item
98
+ end
99
+
100
+ result
101
+ end
102
+
103
+ after do
104
+ # automatically assert that nothing got pushed to flash storage unless metadata tagged
105
+ commands_pushed_to_flash.should be_empty \
106
+ unless example.metadata[:push_to_flash]
107
+ end
108
+
109
+ subject do
110
+ described_class.new(stubbed_controller_facade, stubbed_language, ClassCache.new, stubbed_configuration).tap do |result|
111
+ result.flash_commands_adapter = stubbed_flash_commands_adapter
112
+ end
113
+ end
114
+
115
+ let(:result) do
116
+ subject.finalized_commands_as_segments
117
+ end
118
+
119
+ let(:order_asserter_class) do
120
+ # We need to do a bunch of assertions that are hard to express in rspec proper.
121
+ # This class does the heavy lifting. It is tested below!
122
+ Class.new do
123
+ def initialize(result, context)
124
+ @result = result
125
+ @context = context
126
+ end
127
+
128
+ def do_the_assertions
129
+ ## overall order assumptions
130
+
131
+ # renders _gat._anonymizeIp before any _trackPageview, _setCustomVar or _trackEvent"
132
+ any_occurrence_of('_anonymizeIp').should \
133
+ precede(any_occurrence_of('_trackPageview'))
134
+ any_occurrence_of('_anonymizeIp').should \
135
+ precede(any_occurrence_of('_setCustomVar'))
136
+ any_occurrence_of('_anonymizeIp').should \
137
+ precede(any_occurrence_of('_trackEvent'))
138
+
139
+ ## per tracker order assumptions
140
+
141
+ # it rendes _setAccount before _trackPageview, _setCustomVar or _trackEvent
142
+ tracker_occurrences_of('_setAccount').should \
143
+ precede(tracker_occurrences_of('_trackPageview'))
144
+ tracker_occurrences_of('_setAccount').should \
145
+ precede(tracker_occurrences_of('_setCustomVar'))
146
+ tracker_occurrences_of('_setAccount').should \
147
+ precede(tracker_occurrences_of('_trackEvent'))
148
+
149
+ # it renders _setCustomVar before _trackEvent
150
+ tracker_occurrences_of('_setCustomVar').should \
151
+ precede(tracker_occurrences_of('_trackEvent'))
152
+ end
153
+
154
+ def self_test
155
+ @result = [
156
+ ['cmd1'], ['cmd2'], ['tracker.cmd1'], ['tracker.cmd2'],
157
+ ['cmd3'], ['cmd4'], ['tracker.cmd5']
158
+ ]
159
+
160
+ tracker_occurrences_of('cmd1').should \
161
+ precede(tracker_occurrences_of('cmd2'))
162
+
163
+ tracker_occurrences_of('cmd2').should_not \
164
+ precede(tracker_occurrences_of('cmd1'))
165
+
166
+ any_occurrence_of('cmd3').should \
167
+ precede(any_occurrence_of('cmd4'))
168
+
169
+ any_occurrence_of('cmd4').should_not \
170
+ precede(any_occurrence_of('cmd3'))
171
+
172
+ any_occurrence_of('cmd3').should \
173
+ precede(any_occurrence_of('cmd5'))
174
+
175
+ any_occurrence_of('cmd5').should_not \
176
+ precede(any_occurrence_of('cmd3'))
177
+ end
178
+
179
+ private
180
+
181
+ def precede(following)
182
+ @context.satisfy do |preceding|
183
+ preceding.all? do |tracker_name, indices|
184
+ following_indices = following[tracker_name]
185
+ [*indices, -1].max < [*following_indices, 2**31].min
186
+ end
187
+ end
188
+ end
189
+
190
+ def tracker_occurrences_of(command_name)
191
+ command_occurrences_with_matching_tracker_name(command_name) do |tracker_name|
192
+ tracker_name != :any
193
+ end
194
+ # preprocessed_result[command_name].select { |tracker_name, _| tracker_name != :any }
195
+ end
196
+
197
+ def any_occurrence_of(command_name)
198
+ command_occurrences_with_matching_tracker_name(command_name) do |tracker_name|
199
+ tracker_name == :any
200
+ end
201
+ # preprocessed_result[command_name].select { |tracker_name, _| tracker_name == :any }
202
+ end
203
+
204
+ def command_occurrences_with_matching_tracker_name(command_name)
205
+ analyzed_result[command_name].select { |tracker_name, _| yield tracker_name }
206
+ end
207
+
208
+ def analyzed_result
209
+ ar = Hash.new do |hash, command_name|
210
+ hash[command_name] = Hash.new { |h, tracker_name| h[tracker_name] = [] }
211
+ end
212
+
213
+ @result.map(&:first).each_with_index do |first_segment, index|
214
+ command_name, tracker_name = first_segment.split('.', 2).reverse
215
+
216
+ per_command = ar[command_name]
217
+ per_command[tracker_name] << index
218
+ per_command[:any] << index
219
+ end
220
+
221
+ ar
222
+ end
223
+ end
224
+ end
225
+
226
+ describe "order asserter mechanism" do
227
+ # the order_asserter_class does heavy lifting and deserves being tested!
228
+
229
+ it "does what we expect" do
230
+ order_asserter_class.new(nil, self).self_test
231
+ end
232
+ end
233
+
234
+ after do
235
+ # automatically assert order assumptions for each example
236
+ order_asserter_class.new(result, self).do_the_assertions
237
+ # this way we don't forget.
238
+ end
239
+
240
+ let(:root_target) { subject.root_target }
241
+
242
+ shared_context declare_var: true do
243
+ before do
244
+ rails_config.declare_variable :var, scope: 3, slot: 0
245
+ end
246
+ end
247
+
248
+ context "without further configuration" do
249
+ it "returns _setAccount (unset wpi) and _trackPageview for default tracker" do
250
+ result.should have(2).items
251
+ result.should include(["_setAccount", "UA-XUNSET-S"])
252
+ result.should include(["_trackPageview"])
253
+ end
254
+ end
255
+
256
+ context "with config.gaq.anonymize_ip = true" do
257
+ before do
258
+ rails_config.anonymize_ip = true
259
+ end
260
+
261
+ it "renders '_gat._anonymizeIp" do
262
+ result.should include(["_gat._anonymizeIp"])
263
+ end
264
+ end
265
+
266
+ describe "default tracker configuration effect" do
267
+ before do
268
+ rails_config.web_property_id = 'UA-TEST23-5'
269
+ end
270
+
271
+ it "renders a correct _setAccount" do
272
+ result.should include(["_setAccount", 'UA-TEST23-5'])
273
+ end
274
+
275
+ it "renders a _trackPageview by default" do
276
+ result.should include(["_trackPageview"])
277
+ end
278
+
279
+ context "config.gaq.track_pageview = false" do
280
+ before do
281
+ rails_config.track_pageview = false
282
+ end
283
+
284
+ it "does not render anything for default tracker", pending: true do
285
+ # Currently, the default tracker _setAccount is always rendered.
286
+ # I'm undecided about that.
287
+ # If the implementation stays this way, I should assert
288
+ # _setAccount presence here instead.
289
+ result.should_not include command_segments.for_default_tracker
290
+ end
291
+
292
+ context "with a tracker command" do
293
+ before do
294
+ # this is really an arbitrary tracker command.
295
+ root_target.track_event 'category', 'action', 'label'
296
+ end
297
+
298
+ it "renders the _setAccount, but not a _trackPageview" do
299
+ result.should include(["_setAccount", 'UA-TEST23-5'])
300
+ result.should_not include(command_segments.starting_with('_trackPageview'))
301
+ end
302
+ end
303
+ end
304
+ end
305
+
306
+ describe "effect of tracker commands issued on default tracker" do
307
+ describe "gaq.track_event 'category', 'action', 'label'" do
308
+ before do
309
+ root_target.track_event 'category', 'action', 'label'
310
+ end
311
+
312
+ it "renders the _trackEvent" do
313
+ result.should include(["_trackEvent", "category", "action", "label"])
314
+ end
315
+ end
316
+
317
+ # more here when implemented...
318
+ end
319
+
320
+ describe "effect of tracker commands issued on default tracker .next_request" do
321
+ context "gaq.next_request.track_event 'category', 'action', 'label'", push_to_flash: true do
322
+ before do
323
+ root_target.next_request.track_event 'category', 'action', 'label'
324
+ end
325
+
326
+ it "does not render the _trackEvent" do
327
+ result.should_not include command_segments.starting_with('_trackEvent')
328
+ end
329
+
330
+ it "pushes the _trackEvent to flash storage" do
331
+ commands_pushed_to_flash.should be == [
332
+ ["_trackEvent", "category", "action", "label"]
333
+ ]
334
+ end
335
+ end
336
+
337
+ # more here when implemented...
338
+ end
339
+
340
+ context "with a variable declared", declare_var: true do
341
+ it "returns nothing in addition" do
342
+ result.should have(2).items
343
+ result.should include(["_setAccount", "UA-XUNSET-S"])
344
+ result.should include(["_trackPageview"])
345
+ end
346
+
347
+ context "after assigning to variable" do
348
+ before do
349
+ root_target.var = "blah"
350
+ end
351
+
352
+ it "renders the _setCustomVar" do
353
+ result.should include(["_setCustomVar", 0, "var", "blah", 3])
354
+ end
355
+
356
+ context "gaq.track_event 'category', 'action', 'label'" do
357
+ before(:each) do
358
+ root_target.track_event 'category', 'action', 'label'
359
+ end
360
+
361
+ it "renders the _trackEvent in addition, maintaining correct order" do
362
+ # order assertion is not here, see preamble.
363
+ result.should include(["_setCustomVar", 0, "var", "blah", 3])
364
+ result.should include(["_trackEvent", "category", "action", "label"])
365
+ end
366
+ end
367
+ end
368
+
369
+ context "after assigning to variable on gaq.next_request", push_to_flash: true do
370
+ before do
371
+ root_target.next_request.var = "blah"
372
+ end
373
+
374
+ it "does not render a _setCustomVar" do
375
+ result.should_not include(command_segments.starting_with('_setCustomVar'))
376
+ end
377
+
378
+ it "pushes the _setCustomVar onto the flash storage" do
379
+ commands_pushed_to_flash.should be == [
380
+ ["_setCustomVar", 0, "var", "blah", 3]
381
+ ]
382
+ end
383
+ end
384
+ end
385
+
386
+ context "with commands stored in flash" do
387
+ before do
388
+ commands_from_flash << ["_trackEvent", "last_cat", "last_action", "last_label"]
389
+ commands_from_flash << ["_setCustomVar", 0, "var", "blah", 3]
390
+ end
391
+
392
+ it "renders these" do
393
+ result.should include(["_setCustomVar", 0, "var", "blah", 3])
394
+ result.should include(["_trackEvent", "last_cat", "last_action", "last_label"])
395
+ end
396
+
397
+ context "gaq.next_request.track_event 'category', 'action', 'label'", push_to_flash: true do
398
+ before(:each) do
399
+ root_target.next_request.track_event 'category', 'action', 'label'
400
+ end
401
+
402
+ it "does not render that in addition" do
403
+ result.should_not include(["_trackEvent", "category", "action", "label"])
404
+ end
405
+
406
+ it "pushes that on the flash store instead" do
407
+ commands_pushed_to_flash.should be == [
408
+ ["_trackEvent", "category", "action", "label"]
409
+ ]
410
+ end
411
+ end
412
+
413
+ context "with a variable declared", declare_var: true do
414
+ context "after assigning to same variable again" do
415
+ before do
416
+ root_target.var = "blubb"
417
+ end
418
+
419
+ it "renders both _setCustomVar, in order" do
420
+ first_set_custom_var = ["_setCustomVar", 0, "var", "blah", 3]
421
+ second_set_custom_var = ["_setCustomVar", 0, "var", "blubb", 3]
422
+
423
+ result.should include(first_set_custom_var)
424
+ result.should include(second_set_custom_var)
425
+ result.index(first_set_custom_var).should be <
426
+ result.index(second_set_custom_var)
427
+ end
428
+ end
429
+
430
+ end
431
+ end
432
+
433
+ context "with a custom tracker" do
434
+ before do
435
+ rails_config.additional_trackers = ["foo"]
436
+ end
437
+
438
+ context "configured not to track pageviews" do
439
+ before do
440
+ rails_config.tracker(:foo).track_pageview = false
441
+ end
442
+
443
+ it "does not render any command for the additional tracker" do
444
+ result.should_not include(command_segments.for_tracker('foo'))
445
+ end
446
+
447
+ context "after gaq[:foo].track_event 'category', 'action', 'label'" do
448
+ before do
449
+ root_target["foo"].track_event 'category', 'action', 'label'
450
+ end
451
+
452
+ it "renders the proper _setAccount" do
453
+ result.should include(["foo._setAccount", "UA-XUNSET-S"])
454
+ end
455
+
456
+ it "does not render a _trackPageview for the tracker" do
457
+ result.should_not include(["foo._trackPageview"])
458
+ end
459
+
460
+ it "renders the _trackEvent" do
461
+ result.should include(["foo._trackEvent", "category", "action", "label"])
462
+ end
463
+ end
464
+ end
465
+
466
+ it "renders a _setAccount for the additional tracker" do
467
+ result.should include(['foo._setAccount', "UA-XUNSET-S"])
468
+ end
469
+
470
+ it "renders a _trackPageview for the tracker" do
471
+ result.should include(["foo._trackPageview"])
472
+ end
473
+
474
+ context "after gaq[:foo].track_event 'category', 'action', 'label'" do
475
+ before do
476
+ root_target["foo"].track_event 'category', 'action', 'label'
477
+ end
478
+
479
+ it "renders a _setAccount for the additional tracker" do
480
+ result.should include(['foo._setAccount', "UA-XUNSET-S"])
481
+ end
482
+
483
+ it "renders a _trackPageview for the tracker" do
484
+ result.should include(["foo._trackPageview"])
485
+ end
486
+
487
+ it "renders the _trackEvent" do
488
+ result.should include(["foo._trackEvent", "category", "action", "label"])
489
+ end
490
+ end
491
+ end
492
+
493
+ it "fails when an undeclared tracker is accessed from a target like gaq[:bogus]" do
494
+ expect {
495
+ root_target[:bogus]
496
+ }.to raise_exception
497
+ end
498
+
499
+ context "with commands stored in flash referencing a nonexistend tracker" do
500
+ before do
501
+ commands_from_flash << ["nonexistent._trackEvent", "last_cat", "last_action", "last_label"]
502
+ end
503
+
504
+ it "does not raise an exception" do
505
+ result
506
+ end
507
+ end
508
+ end
509
+ end
510
+ end