Skip to content

Commit

Permalink
Add content navigation multivariate test
Browse files Browse the repository at this point in the history
Start with 4 variants:
original, no nav, taxonomy nav, mainstream nav

* Follow “concern” pattern setup in #513 for task list AB test
* Only content with the document types listed are part of the test
* The content must also be tagged to a taxon
* Use a “universal_navigation” variant for all multivariate tests
except original – they are largely the same, significant differences
with original shouldn’t be repeated
  • Loading branch information
fofr committed Nov 8, 2017
1 parent 11f224d commit 4efe167
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 5 deletions.
86 changes: 86 additions & 0 deletions app/controllers/concerns/content_navigation_ab_testable.rb
@@ -0,0 +1,86 @@
module ContentNavigationABTestable
CONTENT_NAVIGATION_DIMENSION = 67
CONTENT_NAVIGATION_ORIGINAL = "Original".freeze
CONTENT_NAVIGATION_UNIVERSAL_NO_NAVIGATION = "UniversalNoNav".freeze
CONTENT_NAVIGATION_UNIVERSAL_MAINSTREAM_NAVIGATION = "UniversalMainstreamNav".freeze
CONTENT_NAVIGATION_UNIVERSAL_TAXON_NAVIGATION = "UniversalTaxonNav".freeze

CONTENT_NAVIGATION_ALLOWED_VARIANTS = [
CONTENT_NAVIGATION_ORIGINAL,
CONTENT_NAVIGATION_UNIVERSAL_NO_NAVIGATION,
CONTENT_NAVIGATION_UNIVERSAL_MAINSTREAM_NAVIGATION,
CONTENT_NAVIGATION_UNIVERSAL_TAXON_NAVIGATION
].freeze

GUIDANCE_DOCUMENT_TYPES = %w(
answer
guide
detailed_guide
statutory_guidance
).freeze

def self.included(base)
base.helper_method(
:content_navigation_variant,
:content_navigation_ab_test_applies?,
:content_navigation_test_original_variant?,
:universal_navigation_without_nav?,
:universal_navigation_with_taxon_nav?,
:universal_navigation_with_mainstream_nav?
)

base.after_action :set_content_navigation_response_header
end

def content_navigation_ab_test
@content_navigation_ab_test ||=
GovukAbTesting::AbTest.new(
"ContentNavigation",
dimension: CONTENT_NAVIGATION_DIMENSION,
allowed_variants: CONTENT_NAVIGATION_ALLOWED_VARIANTS
)
end

# Universal navigation:
# https://gov-uk.atlassian.net/wiki/spaces/GFED/pages/186351726/Sprint+1+designs
#
# Universal navigation must only be shown when:
# * in the multivariate test
# * not showing the original variant
def should_present_universal_navigation?
content_navigation_ab_test_applies? && !content_navigation_test_original_variant?
end

def content_navigation_ab_test_applies?
@content_item.tagged_to_a_taxon? && content_document_type_is_guidance?
end

def content_document_type_is_guidance?
GUIDANCE_DOCUMENT_TYPES.include? @content_item.document_type
end

def content_navigation_test_original_variant?
content_navigation_variant.variant?(CONTENT_NAVIGATION_ORIGINAL)
end

def universal_navigation_without_nav?
content_navigation_variant.variant?(CONTENT_NAVIGATION_UNIVERSAL_NO_NAVIGATION)
end

def universal_navigation_with_taxon_nav?
content_navigation_variant.variant?(CONTENT_NAVIGATION_UNIVERSAL_TAXON_NAVIGATION)
end

def universal_navigation_with_mainstream_nav?
content_navigation_variant.variant?(CONTENT_NAVIGATION_UNIVERSAL_MAINSTREAM_NAVIGATION)
end

def content_navigation_variant
@content_navigation_variant ||=
content_navigation_ab_test.requested_variant(request.headers)
end

def set_content_navigation_response_header
content_navigation_variant.configure_response(response) if content_navigation_ab_test_applies?
end
end
19 changes: 14 additions & 5 deletions app/controllers/content_items_controller.rb
Expand Up @@ -2,6 +2,7 @@ class ContentItemsController < ApplicationController
class SpecialRouteReturned < StandardError; end

include TasklistABTestable
include ContentNavigationABTestable

rescue_from GdsApi::HTTPForbidden, with: :error_403
rescue_from GdsApi::HTTPNotFound, with: :error_notfound
Expand All @@ -14,8 +15,9 @@ class SpecialRouteReturned < StandardError; end

def show
load_content_item
set_up_navigation
setup_tasklist_ab_testing
setup_content_navigation_ab_testing
set_up_navigation
set_expiry
set_access_control_allow_origin_header if request.format.atom?
set_guide_draft_access_token if @content_item.is_a?(GuidePresenter)
Expand Down Expand Up @@ -89,17 +91,20 @@ def set_expiry
end

def set_up_navigation
@navigation = NavigationType.new(@content_item.content_item)

# Setting a variant on a request is a type of Rails Dark Magic that will
# use a convention to automagically load an alternative partial, view or
# layout. For example, if I set a variant of :taxonomy_navigation and we render
# a partial called _breadcrumbs.html.erb then Rails will attempt to load
# _breadcrumbs.html+taxonomy_navigation.erb instead. If this file doesn't exist,
# then it falls back to _breadcrumbs.html.erb. See:
# http://edgeguides.rubyonrails.org/4_1_release_notes.html#action-pack-variants
if @navigation.should_present_taxonomy_navigation?
request.variant = :taxonomy_navigation
if should_present_universal_navigation?
request.variant = :universal_navigation
else
@navigation = NavigationType.new(@content_item.content_item)
if @navigation.should_present_taxonomy_navigation?
request.variant = :taxonomy_navigation
end
end
end

Expand All @@ -111,6 +116,10 @@ def setup_tasklist_ab_testing
set_tasklist_response_header
end

def setup_content_navigation_ab_testing
set_content_navigation_response_header
end

def content_item_path
path_and_optional_locale = params
.values_at(:path, :locale)
Expand Down
4 changes: 4 additions & 0 deletions app/presenters/content_item_presenter.rb
Expand Up @@ -62,6 +62,10 @@ def related_items
@nav_helper.related_items
end

def tagged_to_a_taxon?
content_item.dig("links", "taxons").present?
end

private

def display_date(timestamp, format = "%-d %B %Y")
Expand Down
1 change: 1 addition & 0 deletions app/views/layouts/application.html.erb
Expand Up @@ -25,6 +25,7 @@
<% end %>
<meta name="govuk:content-id" content="<%= @content_item.content_id %>" />
<%= tasklist_variant.analytics_meta_tag.html_safe if tasklist_ab_test_applies? %>
<%= content_navigation_variant.analytics_meta_tag.html_safe if content_navigation_ab_test_applies? %>
<%= yield :extra_head_content %>
</head>
<body>
Expand Down
@@ -0,0 +1,69 @@
require 'test_helper'

class ContentItemsControllerTest < ActionController::TestCase
include GdsApi::TestHelpers::ContentStore
include GovukAbTesting::MinitestHelpers

ContentItemsController::GUIDANCE_DOCUMENT_TYPES.each do |document_type|
schema_name = document_type == 'statutory_guidance' ? 'publication' : document_type

test "does not show universal navigation when no taxons are tagged to #{document_type}" do
content_item = content_store_has_schema_example(schema_name, schema_name)
path = "government/abtest/#{schema_name}"
content_item['base_path'] = "/#{path}"
content_item['links'] = {}

content_store_has_item(content_item['base_path'], content_item)

setup_ab_variant('ContentNavigation', ContentItemsController::CONTENT_NAVIGATION_ORIGINAL)
get :show, params: { path: path }
assert_equal [], @request.variant
assert_response_not_modified_for_ab_test('ContentNavigation')
end

test "#{document_type} honours content navigation AB Testing cookie" do
content_item = content_store_has_schema_example(schema_name, schema_name)
path = "government/abtest/#{schema_name}"
content_item['document_type'] = document_type
content_item['base_path'] = "/#{path}"
content_item['links'] = {
'taxons' => [
{
'title' => 'A Taxon',
'base_path' => '/a-taxon',
}
]
}

content_store_has_item(content_item['base_path'], content_item)

ContentItemsController::CONTENT_NAVIGATION_ALLOWED_VARIANTS.each do |variant|
with_variant ContentNavigation: variant do
get :show, params: { path: path }
requested = @controller.content_navigation_ab_test.requested_variant(request.headers)
assert_response 200
assert requested.variant?(variant)

if variant == ContentItemsController::CONTENT_NAVIGATION_ORIGINAL
assert_equal [:taxonomy_navigation], @request.variant
else
assert_equal [:universal_navigation], @request.variant
end
end
end
end

test "defaults to original view without AB testing cookie for #{document_type}" do
content_item = content_store_has_schema_example(schema_name, schema_name)
path = "government/abtest/#{schema_name}"
content_item['document_type'] = document_type
content_item['base_path'] = "/#{path}"
content_item['links'] = {}
content_store_has_item(content_item['base_path'], content_item)

get :show, params: { path: path }
assert_response 200
assert_equal [], @request.variant
end
end
end

0 comments on commit 4efe167

Please sign in to comment.