govuk_ab_testing 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []