govuk_ab_testing 0.2.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3fd5d31f02d60fa9d23dc37c87747ad8ad3dfb4a
4
- data.tar.gz: 0f3521e417baebb222969d59b3214d4ca094c88c
3
+ metadata.gz: 74c9eed0d845a4d1139c618e74bbc6cab109f2c6
4
+ data.tar.gz: bca89588653315d83e4a3a8387695685bd21558d
5
5
  SHA512:
6
- metadata.gz: 2b11005c795f0f63ec5a4b9443448b4952355a167ef21cb7f3d27671016cdb6cf011a8748bc587b362d1d5553b8abe83adf8f323bfbc80198dbaef51b4f40fed
7
- data.tar.gz: 65b2c4e8462261800bcb707983853b104b5cf9fa53fbbdc5f85a63d6f4af02e24dfcba7ab20cf5346064b20446bb47383845f48960b198832ec9256d60e3739d
6
+ metadata.gz: 694cddcacc3320548b0d558dfc7b10dd5f14f4dabc559e2edc006e14e33ce718acdaa7b4bc8c0db859ffaf3bcb78f8d71bc67e6b4ddcc79c88da33e59e7ba8a8
7
+ data.tar.gz: f9a25ff78213c7012fd5ef5e5145b3ff3db28fa8b34f0e89b9654560bb5b60a789a0fc4cc309f49a0549a68ff4d02e5cd558716d0bdafc11ea47918e30df2e5f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 1.0.0
2
+
3
+ * Pass in request headers instead of the actual request to RequestedVariant.
4
+ This is a breaking change.
5
+ * Slit testing framework helpers from acceptance test frameworks. This means we
6
+ can now use a combination of RSpec/Minitest and Capybara/ActiveSupport test
7
+ cases.
8
+
1
9
  ## 0.2.0
2
10
 
3
11
  * Include RSpec + Capybara helper class
data/README.md CHANGED
@@ -33,7 +33,21 @@ To enable testing in the app, your Rails app needs:
33
33
  the dimension to use in Google Analytics
34
34
  3. A response HTTP header that tells Fastly you're doing an A/B test
35
35
 
36
- Let's say you have this controller:
36
+ Start by defining which acceptance testing framework you will use. This gem
37
+ supports both Capybara and ActiveSupport. In order to configure it, add this to
38
+ your test helper file:
39
+
40
+ ```
41
+ GovukAbTesting.configure do |config|
42
+ config.acceptance_test_framework = :capybara # or :active_support
43
+ end
44
+ ```
45
+
46
+ If we use capybara, the gem expects `page` to be defined in the scope of the
47
+ test cases. If we use ActiveSupport, the gem expects `@request` to be defined in
48
+ the scope of the test cases.
49
+
50
+ Now, let's say you have this controller:
37
51
 
38
52
  ```ruby
39
53
  # app/controllers/party_controller.rb
@@ -123,15 +137,15 @@ class PartyControllerTest < ActionController::TestCase
123
137
  end
124
138
  ```
125
139
 
126
- ##### RSpec + Capybara
140
+ ##### RSpec
127
141
 
128
- It is also possible to use `with_variant` in RSpec tests that use Capybara. Here
129
- is an example of a spec file:
142
+ It is also possible to use `with_variant` in RSpec tests. Here is an example of
143
+ a spec file:
130
144
 
131
145
  ```ruby
132
146
  # spec/features/ab_testing_spec.rb
133
147
  feature "Viewing a page with an A/B test" do
134
- include GovukAbTesting::RspecCapybaraHelpers
148
+ include GovukAbTesting::RspecHelpers
135
149
 
136
150
  scenario "viewing the B version of the page" do
137
151
  with_variant your_ab_test_name: 'B' do
@@ -144,15 +158,18 @@ feature "Viewing a page with an A/B test" do
144
158
  end
145
159
  ```
146
160
 
147
- Please note that `with_variant` in `GovukAbTesting::RspecCapybaraHelpers`
148
- expects both `page` (Capybara session) and RSpec expectations to be available.
149
-
150
161
  As with the `minitest` version, you can also pass in the following options to
151
162
  `with_variant`:
152
163
 
153
164
  - `assert_meta_tag: false`
154
165
  - `dimension: <number>`
155
166
 
167
+ ### Current limitations
168
+
169
+ This library assumes we are only using one A/B test per page. The acceptance
170
+ test classes look for only one analytics' meta tag and will fail in the presence
171
+ of more than one.
172
+
156
173
  ### Running the test suite
157
174
 
158
175
  `bundle exec rake`
@@ -10,10 +10,10 @@ module GovukAbTesting
10
10
  @dimension = dimension
11
11
  end
12
12
 
13
- # @param request [ApplicationController::Request] the `request` in the
14
- # controller.
15
- def requested_variant(request)
16
- RequestedVariant.new(self, request, @dimension)
13
+ # @param request [ActionDispatch::Http::Headers] the `request.headers` in
14
+ # the controller.
15
+ def requested_variant(request_headers)
16
+ RequestedVariant.new(self, request_headers, @dimension)
17
17
  end
18
18
 
19
19
  # Internal name of the header
@@ -0,0 +1,41 @@
1
+ module GovukAbTesting
2
+ module AcceptanceTests
3
+ class ActiveSupport
4
+ attr_reader :request, :request_headers, :scope
5
+
6
+ def initialize(scope)
7
+ @request = scope.instance_variable_get(:@request)
8
+ if @request.nil?
9
+ raise "Couldn't find '@request' defined, are you using ActiveSupport test cases?"
10
+ end
11
+ @scope = scope
12
+ @request_headers = {}
13
+ end
14
+
15
+ def set_header(name, value)
16
+ request.headers[name] = value
17
+ @request_headers[name] = value
18
+ end
19
+
20
+ def vary_header(response)
21
+ response.headers['Vary']
22
+ end
23
+
24
+ def analytics_meta_tags
25
+ @analytics_meta_tags ||= scope.css_select(ANALYTICS_META_TAG_SELECTOR)
26
+ end
27
+
28
+ def analytics_meta_tag
29
+ analytics_meta_tags.first
30
+ end
31
+
32
+ def content
33
+ analytics_meta_tag.attributes['content'].value
34
+ end
35
+
36
+ def dimension
37
+ analytics_meta_tag.attributes['data-analytics-dimension'].value
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module GovukAbTesting
2
+ module AcceptanceTests
3
+ class Capybara
4
+ attr_reader :capybara_page, :request_headers
5
+
6
+ def initialize(scope)
7
+ unless scope.respond_to?(:page)
8
+ raise "Page is not defined, are you using capybara?"
9
+ end
10
+ @capybara_page = scope.page
11
+ @request_headers = {}
12
+ end
13
+
14
+ def request
15
+ @capybara_page
16
+ end
17
+
18
+ def set_header(name, value)
19
+ capybara_page.driver.options[:headers] = { name => value }
20
+ capybara_page.driver.header(name, value)
21
+ @request_headers[name] = value
22
+ end
23
+
24
+ def vary_header(*)
25
+ capybara_page.response_headers['Vary']
26
+ end
27
+
28
+ def analytics_meta_tags
29
+ @analytics_meta_tags ||=
30
+ capybara_page.all(ANALYTICS_META_TAG_SELECTOR, visible: :all)
31
+ end
32
+
33
+ def analytics_meta_tag
34
+ analytics_meta_tags.first
35
+ end
36
+
37
+ def content
38
+ analytics_meta_tag['content']
39
+ end
40
+
41
+ def dimension
42
+ analytics_meta_tag['data-analytics-dimension']
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,36 @@
1
+ module GovukAbTesting
2
+ class Configuration
3
+ VALID_FRAMEWORKS = %i(capybara active_support).freeze
4
+ attr_accessor :config, :acceptance_test_framework
5
+
6
+ def initialize
7
+ @config = {}
8
+ end
9
+
10
+ def acceptance_test_framework
11
+ config[:acceptance_test_framework]
12
+ end
13
+
14
+ def acceptance_test_framework=(framework)
15
+ unless VALID_FRAMEWORKS.include?(framework)
16
+ raise "Invalid acceptance test framework '#{framework}'"
17
+ end
18
+
19
+ config[:acceptance_test_framework] = framework
20
+ @framework_class = nil
21
+ end
22
+
23
+ def framework_class
24
+ @framework_class ||= begin
25
+ case config[:acceptance_test_framework]
26
+ when :capybara
27
+ then GovukAbTesting::AcceptanceTests::Capybara
28
+ when :active_support
29
+ then GovukAbTesting::AcceptanceTests::ActiveSupport
30
+ else
31
+ raise "Invalid framework #{acceptance_test_framework}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,5 +1,10 @@
1
1
  module GovukAbTesting
2
2
  module MinitestHelpers
3
+ def acceptance_test_framework
4
+ @acceptance_test_framework ||=
5
+ GovukAbTesting.configuration.framework_class.new(self)
6
+ end
7
+
3
8
  def with_variant(args)
4
9
  ab_test_name, variant = args.first
5
10
  dimension = args[:dimension]
@@ -7,29 +12,28 @@ module GovukAbTesting
7
12
  ab_test =
8
13
  GovukAbTesting::AbTest.new(ab_test_name.to_s, dimension: dimension)
9
14
 
10
- @request.headers[ab_test.request_header] = variant
11
- requested_variant = ab_test.requested_variant(@request)
15
+ acceptance_test_framework.set_header(ab_test.request_header, variant)
16
+ requested_variant = ab_test.requested_variant(acceptance_test_framework.request_headers)
12
17
 
13
18
  yield
14
19
 
15
- assert_match ab_test.response_header, response.headers['Vary'],
20
+ vary_header_value = acceptance_test_framework.vary_header(response)
21
+ assert_match ab_test.response_header, vary_header_value,
16
22
  "You probably forgot to use `configure_response`"
17
23
 
18
24
  unless args[:assert_meta_tag] == false
19
25
  expected_content =
20
26
  ab_test.meta_tag_name + ':' + requested_variant.variant_name
21
27
  message = "You probably forgot to add the `analytics_meta_tag` to the views"
22
- meta_tags = css_select("meta[name='govuk:ab-test']")
28
+ meta_tags = acceptance_test_framework.analytics_meta_tags
23
29
 
24
30
  assert_equal(1, meta_tags.count, message)
25
31
 
26
- meta_tag = meta_tags.first
27
- content_value = meta_tag.attributes['content'].value
28
- dimension_value = meta_tag.attributes['data-analytics-dimension'].value
32
+ dimension_value = acceptance_test_framework.dimension
29
33
 
30
34
  assert_equal(
31
35
  expected_content,
32
- content_value,
36
+ acceptance_test_framework.content,
33
37
  "Meta tag's content doesn't match."
34
38
  )
35
39
 
@@ -48,7 +52,7 @@ module GovukAbTesting
48
52
  def setup_ab_variant(ab_test_name, variant, dimension = 300)
49
53
  ab_test = GovukAbTesting::AbTest.new(ab_test_name, dimension: dimension)
50
54
 
51
- @request.headers[ab_test.request_header] = variant
55
+ acceptance_test_framework.set_header(ab_test.request_header, variant)
52
56
  end
53
57
 
54
58
  def assert_response_not_modified_for_ab_test
@@ -1,15 +1,15 @@
1
1
  module GovukAbTesting
2
2
  class RequestedVariant
3
- attr_reader :ab_test, :request
3
+ attr_reader :ab_test, :request_headers
4
4
 
5
5
  # @param ab_test [AbTest] the A/B test being performed
6
- # @param request [ApplicationController::Request] the `request` in the
7
- # controller.
6
+ # @param request_headers [ActionDispatch::Http::Headers] the
7
+ # `request.headers` in the controller.
8
8
  # @param dimension [Integer] the dimension registered with Google Analytics
9
9
  # for this specific A/B test
10
- def initialize(ab_test, request, dimension)
10
+ def initialize(ab_test, request_headers, dimension)
11
11
  @ab_test = ab_test
12
- @request = request
12
+ @request_headers = request_headers
13
13
  @dimension = dimension
14
14
  end
15
15
 
@@ -17,7 +17,7 @@ module GovukAbTesting
17
17
  #
18
18
  # @return [String] the current variant, "A" or "B"
19
19
  def variant_name
20
- request.headers[ab_test.request_header] == "B" ? "B" : "A"
20
+ request_headers[ab_test.request_header] == "B" ? "B" : "A"
21
21
  end
22
22
 
23
23
  # @return [Boolean] if the user is to be served variant A
@@ -0,0 +1,40 @@
1
+ module GovukAbTesting
2
+ module RspecHelpers
3
+ def acceptance_test_framework
4
+ @acceptance_test_framework ||=
5
+ GovukAbTesting.configuration.framework_class.new(self)
6
+ end
7
+
8
+ def with_variant(args)
9
+ ab_test_name, variant = args.first
10
+ dimension = args[:dimension]
11
+
12
+ ab_test =
13
+ GovukAbTesting::AbTest.new(ab_test_name.to_s, dimension: dimension)
14
+
15
+ acceptance_test_framework.set_header(ab_test.request_header, variant)
16
+ requested_variant = ab_test.requested_variant(acceptance_test_framework.request_headers)
17
+
18
+ yield
19
+
20
+ vary_header_value = acceptance_test_framework.vary_header
21
+ expect(ab_test.response_header).to eq(vary_header_value)
22
+
23
+ unless args[:assert_meta_tag] == false
24
+ content = [ab_test.meta_tag_name, requested_variant.variant_name].join(':')
25
+ ab_test_metatags = acceptance_test_framework.analytics_meta_tags
26
+
27
+ expect(ab_test_metatags.count).to eq(1)
28
+
29
+ expect(acceptance_test_framework.content).to eq(content)
30
+ dimension = acceptance_test_framework.dimension
31
+
32
+ if dimension.nil?
33
+ expect(dimension).to_not be_nil
34
+ else
35
+ expect(dimension).to eq(dimension.to_s)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module GovukAbTesting
2
- VERSION = "0.2.0".freeze
2
+ VERSION = "1.0.0".freeze
3
3
  end
@@ -1,8 +1,20 @@
1
1
  require "govuk_ab_testing/version"
2
+ require 'govuk_ab_testing/configuration'
2
3
  require "govuk_ab_testing/requested_variant"
3
4
  require "govuk_ab_testing/ab_test"
4
5
  require "govuk_ab_testing/minitest_helpers"
5
- require "govuk_ab_testing/rspec_capybara_helpers"
6
+ require "govuk_ab_testing/rspec_helpers"
7
+ require 'govuk_ab_testing/acceptance_tests/capybara'
8
+ require 'govuk_ab_testing/acceptance_tests/active_support'
6
9
 
7
10
  module GovukAbTesting
11
+ ANALYTICS_META_TAG_SELECTOR = "meta[name='govuk:ab-test']".freeze
12
+
13
+ def self.configuration
14
+ @configuration ||= GovukAbTesting::Configuration.new
15
+ end
16
+
17
+ def self.configure
18
+ yield configuration if block_given?
19
+ end
8
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_ab_testing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GOV.UK Dev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-24 00:00:00.000000000 Z
11
+ date: 2017-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -102,9 +102,12 @@ files:
102
102
  - govuk_ab_testing.gemspec
103
103
  - lib/govuk_ab_testing.rb
104
104
  - lib/govuk_ab_testing/ab_test.rb
105
+ - lib/govuk_ab_testing/acceptance_tests/active_support.rb
106
+ - lib/govuk_ab_testing/acceptance_tests/capybara.rb
107
+ - lib/govuk_ab_testing/configuration.rb
105
108
  - lib/govuk_ab_testing/minitest_helpers.rb
106
109
  - lib/govuk_ab_testing/requested_variant.rb
107
- - lib/govuk_ab_testing/rspec_capybara_helpers.rb
110
+ - lib/govuk_ab_testing/rspec_helpers.rb
108
111
  - lib/govuk_ab_testing/version.rb
109
112
  homepage: https://github.com/alphagov/govuk_ab_testing
110
113
  licenses:
@@ -1,33 +0,0 @@
1
- module GovukAbTesting
2
- module RspecCapybaraHelpers
3
- def with_variant(args)
4
- unless defined?(page)
5
- raise "The variable 'page' is not defined, are you using capybara?"
6
- end
7
-
8
- ab_test_name, variant = args.first
9
- dimension = args[:dimension]
10
- ab_test =
11
- GovukAbTesting::AbTest.new(ab_test_name.to_s, dimension: dimension)
12
-
13
- page.driver.header(ab_test.response_header, variant)
14
-
15
- yield
16
-
17
- expect(ab_test.response_header).to eq(page.response_headers['Vary'])
18
-
19
- unless args[:assert_meta_tag] == false
20
- content = [ab_test.meta_tag_name, variant].join(':')
21
- ab_test_metatag = page.find("meta[name='govuk:ab-test']", visible: :all)
22
-
23
- expect(ab_test_metatag['content']).to eq(content)
24
-
25
- if dimension.nil?
26
- expect(ab_test_metatag['data-analytics-dimension']).to_not be_nil
27
- else
28
- expect(ab_test_metatag['data-analytics-dimension']).to eq(dimension.to_s)
29
- end
30
- end
31
- end
32
- end
33
- end