govuk_ab_testing 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a131dac8f3c6fe3c8bd613056c2c639790807519
4
+ data.tar.gz: 247f153ccd3d578a4340594198858c34faec0bbb
5
+ SHA512:
6
+ metadata.gz: da4a7338ea7be7c6535637bf7f8f0d9ab7e047bdd9a55786a6c7d90e2f7e00d7f907c2179ef2e25e85a914945f487054244eb470817c80c4ae0f3ba68af3a9ae
7
+ data.tar.gz: 074fdfce8d5d4a9dc749fae59c495cfb3a57d5f97561939b5704e1f62ca7bc90e80fb3360ec2bddb61f30335a566c6700d0a937ecf6b8b0a8321b42570a17fec
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/CHANGELOG.md ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in govuk_ab_testing.gemspec
4
+ gemspec
data/Jenkinsfile ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env groovy
2
+
3
+ node {
4
+ def govuk = load '/var/lib/jenkins/groovy_scripts/govuk_jenkinslib.groovy'
5
+
6
+ try {
7
+ stage('Checkout') {
8
+ checkout scm
9
+ }
10
+
11
+ stage('Clean') {
12
+ govuk.cleanupGit()
13
+ govuk.mergeMasterBranch()
14
+ }
15
+
16
+ stage('Bundle') {
17
+ echo 'Bundling'
18
+ sh("bundle install --path ${JENKINS_HOME}/bundles/${JOB_NAME}")
19
+ }
20
+
21
+ stage('Linter') {
22
+ govuk.rubyLinter()
23
+ }
24
+
25
+ stage('Tests') {
26
+ govuk.setEnvar('RAILS_ENV', 'test')
27
+ govuk.runTests()
28
+ }
29
+
30
+ if(env.BRANCH_NAME == "master") {
31
+ stage('Publish Gem') {
32
+ govuk.runRakeTask("publish_gem --trace")
33
+ }
34
+ }
35
+
36
+ } catch (e) {
37
+ currentBuild.result = 'FAILED'
38
+ step([$class: 'Mailer',
39
+ notifyEveryUnstableBuild: true,
40
+ recipients: 'govuk-ci-notifications@digital.cabinet-office.gov.uk',
41
+ sendToIndividuals: true])
42
+ throw e
43
+ }
44
+ }
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+ Copyright (C) 2017 Crown copyright (Government Digital Service)
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # GOV.UK A/B Testing
2
+
3
+ Gem to help with A/B testing on the GOV.UK platform.
4
+
5
+ ## Technical documentation
6
+
7
+ ### Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'govuk_ab_testing', '~> VERSION'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ### Usage
20
+
21
+ Before starting this, you'll need to
22
+
23
+ - get your cookie listed on [/help/cookies](https://www.gov.uk/help/cookies)
24
+ - configure the CDN [like we did for the Education Navigation test](https://github.com/alphagov/govuk-cdn-config/pull/17).
25
+ The cookie and header name in the CDN config must match the test name parameter
26
+ that you pass to the Gem. The cookie name is case-sensitive.
27
+ - configure Google Analytics (guidelines to follow)
28
+
29
+ To enable testing in the app, your Rails app needs:
30
+
31
+ 1. Some piece of logic to be A/B tested
32
+ 2. A HTML meta tag that will be used to measure the results
33
+ 3. A response HTTP header that tells Fastly you're doing an A/B test
34
+
35
+ Let's say you have this controller:
36
+
37
+ ```ruby
38
+ # app/controllers/party_controller.rb
39
+ class PartyController < ApplicationController
40
+ def show
41
+ ab_test = GovukAbTesting::AbTest.new("your_ab_test_name")
42
+ @requested_variant = ab_test.requested_variant(request)
43
+ @requested_variant.configure_response(response)
44
+
45
+ if @requested_variant.variant_b?
46
+ render "new_show_template_to_be_tested"
47
+ else
48
+ render "show"
49
+ end
50
+ end
51
+ end
52
+ ```
53
+
54
+ Add this to your layouts, so that we have a meta tag that can be picked up
55
+ by the extension and analytics.
56
+
57
+ ```html
58
+ <!-- application.html.erb -->
59
+ <head>
60
+ <%= @requested_variant.analytics_meta_tag.html_safe %>
61
+ </head>
62
+ ```
63
+
64
+ #### Test helpers
65
+
66
+ The most common usage of an A/B test is to serve two different variants of the
67
+ same page. In this situation, you can test the controller using `with_variant`.
68
+ It will configure the request and assert that the response is configured
69
+ correctly:
70
+
71
+ ```ruby
72
+ # test/controllers/party_controller_test.rb
73
+ class PartyControllerTest < ActionController::TestCase
74
+ include GovukAbTesting::MinitestHelpers
75
+
76
+ should "show the user the B version" do
77
+ with_variant your_ab_test_name: "B" do
78
+ get :show
79
+
80
+ # Optional assertions about page content of the B variant
81
+ end
82
+ end
83
+ end
84
+ ```
85
+
86
+ Pass the `assert_meta_tag: false` option to skip assertions about the `meta`
87
+ tag, for example because the variant returns a redirect response rather than
88
+ returning an HTML page.
89
+
90
+ ```ruby
91
+ # test/controllers/party_controller_test.rb
92
+ class PartyControllerTest < ActionController::TestCase
93
+ include GovukAbTesting::MinitestHelpers
94
+
95
+ should "redirect the user the B version" do
96
+ with_variant your_ab_test_name: "B", assert_meta_tag: false do
97
+ get :show
98
+
99
+ assert_response 302
100
+ assert_redirected_to { controller: "other_controller", action: "show" }
101
+ end
102
+ end
103
+ end
104
+ ```
105
+
106
+ To test the negative case in which a page is unaffected by the A/B test:
107
+
108
+ ```ruby
109
+ # test/controllers/party_controller_test.rb
110
+ class PartyControllerTest < ActionController::TestCase
111
+ include GovukAbTesting::MinitestHelpers
112
+
113
+ should "show the original " do
114
+ add_ab_test_header("your_ab_test_name", "B")
115
+
116
+ get :show
117
+
118
+ assert_unaffected_by_ab_test
119
+ end
120
+ end
121
+ ```
122
+
123
+ ### Running the test suite
124
+
125
+ `bundle exec rake`
126
+
127
+ ### Documentation
128
+
129
+ See [RubyDoc](http://www.rubydoc.info/gems/govuk_ab_testing) for some limited documentation.
130
+
131
+ To run a Yard server locally to preview documentation, run:
132
+
133
+ $ bundle exec yard server --reload
134
+
135
+ ## Licence
136
+
137
+ [MIT License](LICENCE.txt)
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "gem_publisher"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ desc "Publish gem to RubyGems"
10
+ task :publish_gem do |_t|
11
+ published_gem = GemPublisher.publish_if_updated("govuk_ab_testing.gemspec", :rubygems)
12
+ puts "Published #{published_gem}" if published_gem
13
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "govuk_ab_testing"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'govuk_ab_testing/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "govuk_ab_testing"
8
+ spec.version = GovukAbTesting::VERSION
9
+ spec.authors = ["GOV.UK Dev"]
10
+ spec.email = ["govuk-dev@digital.cabinet-office.gov.uk"]
11
+
12
+ spec.summary = %q{Gem to help with A/B testing on the GOV.UK platform}
13
+ spec.description = %q{Gem to help with A/B testing on the GOV.UK platform}
14
+ spec.homepage = "https://github.com/alphagov/govuk_ab_testing"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "yard", "~> 0.8"
27
+ spec.add_development_dependency "gem_publisher", "~> 1.5.0"
28
+ end
@@ -0,0 +1,28 @@
1
+ module GovukAbTesting
2
+ class AbTest
3
+ attr_reader :ab_test_name
4
+
5
+ def initialize(ab_test_name)
6
+ @ab_test_name = ab_test_name
7
+ end
8
+
9
+ # @param request [ApplicationController::Request] the `request` in the
10
+ # controller.
11
+ def requested_variant(request)
12
+ RequestedVariant.new(self, request)
13
+ end
14
+
15
+ # Internal name of the header
16
+ def request_header
17
+ "HTTP_GOVUK_ABTEST_#{ab_test_name.upcase}"
18
+ end
19
+
20
+ def response_header
21
+ "GOVUK-ABTest-#{meta_tag_name}"
22
+ end
23
+
24
+ def meta_tag_name
25
+ ab_test_name
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ module GovukAbTesting
2
+ module MinitestHelpers
3
+ def with_variant(args)
4
+ ab_test_name, variant = args.first
5
+
6
+ ab_test = GovukAbTesting::AbTest.new(ab_test_name.to_s)
7
+
8
+ @request.headers[ab_test.request_header] = variant
9
+ requested_variant = ab_test.requested_variant(@request)
10
+
11
+ yield
12
+
13
+ assert_equal ab_test.response_header, response.headers['Vary'], "You probably forgot to use `configure_response`"
14
+
15
+ unless args[:assert_meta_tag] == false
16
+ assert_meta_tag "govuk:ab-test",
17
+ ab_test.meta_tag_name + ':' + requested_variant.variant_name,
18
+ "You probably forgot to add the `analytics_meta_tag`"
19
+ end
20
+ end
21
+
22
+ def setup_ab_variant(ab_test_name, variant)
23
+ ab_test = GovukAbTesting::AbTest.new(ab_test_name)
24
+
25
+ @request.headers[ab_test.request_header] = variant
26
+ end
27
+
28
+ def assert_unaffected_by_ab_test
29
+ assert_nil response.headers['Vary'],
30
+ "`Vary` header is being added to a page which is outside of the A/B test"
31
+
32
+ assert_select "meta[name='govuk:ab-test']", false
33
+ end
34
+
35
+ private
36
+
37
+ def assert_meta_tag(name, content, message)
38
+ assert_select "meta[name='#{name}'][content='#{content}']", 1, message
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ module GovukAbTesting
2
+ class RequestedVariant
3
+ attr_reader :ab_test, :request
4
+
5
+ # @param ab_test [AbTest] the A/B test being performed
6
+ # @param request [ApplicationController::Request] the `request` in the
7
+ # controller.
8
+ def initialize(ab_test, request)
9
+ @ab_test = ab_test
10
+ @request = request
11
+ end
12
+
13
+ # Get the bucket this user is in
14
+ #
15
+ # @return [String] the current variant, "A" or "B"
16
+ def variant_name
17
+ request.headers[ab_test.request_header] == "B" ? "B" : "A"
18
+ end
19
+
20
+ # @return [Boolean] if the user is to be served variant A
21
+ def variant_a?
22
+ variant_name == "A"
23
+ end
24
+
25
+ # @return [Boolean] if the user is to be served variant B
26
+ def variant_b?
27
+ variant_name == "B"
28
+ end
29
+
30
+ # Configure the response
31
+ #
32
+ # @param [ApplicationController::Response] the `response` in the controller
33
+ def configure_response(response)
34
+ raise "We're trying to set the Vary header, but this would override the current header" if response.headers['Vary']
35
+ response.headers['Vary'] = ab_test.response_header
36
+ end
37
+
38
+ # HTML meta tag used to track the results of your experiment
39
+ #
40
+ # @return [String]
41
+ def analytics_meta_tag
42
+ '<meta name="govuk:ab-test" content="' + ab_test.meta_tag_name + ':' + variant_name + '">'
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module GovukAbTesting
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,7 @@
1
+ require "govuk_ab_testing/version"
2
+ require "govuk_ab_testing/requested_variant"
3
+ require "govuk_ab_testing/ab_test"
4
+ require "govuk_ab_testing/minitest_helpers"
5
+
6
+ module GovukAbTesting
7
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: govuk_ab_testing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - GOV.UK Dev
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-02-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '10.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: gem_publisher
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.5.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.5.0
69
+ description: Gem to help with A/B testing on the GOV.UK platform
70
+ email:
71
+ - govuk-dev@digital.cabinet-office.gov.uk
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".ruby-version"
79
+ - CHANGELOG.md
80
+ - Gemfile
81
+ - Jenkinsfile
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - bin/console
86
+ - bin/setup
87
+ - govuk_ab_testing.gemspec
88
+ - lib/govuk_ab_testing.rb
89
+ - lib/govuk_ab_testing/ab_test.rb
90
+ - lib/govuk_ab_testing/minitest_helpers.rb
91
+ - lib/govuk_ab_testing/requested_variant.rb
92
+ - lib/govuk_ab_testing/version.rb
93
+ homepage: https://github.com/alphagov/govuk_ab_testing
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.5.1
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Gem to help with A/B testing on the GOV.UK platform
117
+ test_files: []