Skip to content

Commit

Permalink
Move in-page script to tracker.js (#73)
Browse files Browse the repository at this point in the history
* Remove inline script

* Lint

* Add tests
  • Loading branch information
jhonatan-lopes authored Mar 20, 2024
1 parent 29a807f commit e42afe9
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 29 deletions.
8 changes: 8 additions & 0 deletions wagtail_ab_testing/static/wagtail_ab_testing/js/tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
}
}

// Read the tracking parameters from JSON script
let trackingParams = null;
if (document.getElementById('abtesting-tracking-params')) {
trackingParams = JSON.parse(document.getElementById('abtesting-tracking-params').textContent);
// Attach the wagtailAbTesting object to the window
window.wagtailAbTesting = trackingParams;
}

function getCookie(cookieName) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
Expand Down
26 changes: 1 addition & 25 deletions wagtail_ab_testing/templates/wagtail_ab_testing/script.html
Original file line number Diff line number Diff line change
@@ -1,30 +1,6 @@
{% load static %}

{% if track %}
<script>
window.wagtailAbTesting = {
{# Is this a Wagtail Page? #}
{# This value is used to check if a goal has been reached #}
{% if page %}
pageId: {{ page.id }},
{% endif %}

{# Is there a test running on the current page? #}
{% if test and version %}
testId: {{ test.id }},
version: '{{ version|escapejs }}',
goalEvent: '{{ test.goal_event|escapejs }}',
goalPageId: {% if test.goal_page %}{{ test.goal_page.id }}{% else %}null{% endif %},
{% endif %}

urls: {
{% url 'wagtail_ab_testing:register_participant' as register_participant_url %}
registerParticipant: '{{ register_participant_url|escapejs }}',
{% url 'wagtail_ab_testing:goal_reached' as goal_reached_url %}
goalReached: '{{ goal_reached_url|escapejs }}',
}
};
</script>

{{ tracking_parameters|json_script:"abtesting-tracking-params" }}
<script src="{% static 'wagtail_ab_testing/js/tracker.js' %}" defer async></script>
{% endif %}
38 changes: 34 additions & 4 deletions wagtail_ab_testing/templatetags/wagtail_ab_testing_tags.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django import template
from django.urls import reverse

from wagtail_ab_testing.models import AbTest
from wagtail_ab_testing.utils import request_is_trackable
Expand All @@ -11,9 +12,38 @@ def wagtail_ab_testing_script(context):
request = context['request']
serving_variant = getattr(request, 'wagtail_ab_testing_serving_variant', False)

track = request_is_trackable(request)
if not track:
return {
"track": False,
"tracking_parameters": None,
}

register_participant_url = reverse('wagtail_ab_testing:register_participant')
goal_reached_url = reverse('wagtail_ab_testing:goal_reached')

tracking_parameters = {
"urls": {
"registerParticipant": register_participant_url,
"goalReached": goal_reached_url,
},
}

page = context.get('page', None)
page_id = page.id if page else None
if page_id:
tracking_parameters["pageId"] = page_id

version = AbTest.VERSION_VARIANT if serving_variant else AbTest.VERSION_CONTROL
test = getattr(request, 'wagtail_ab_testing_test', None)

if (test and version):
tracking_parameters["testId"] = test.id
tracking_parameters["version"] = version
tracking_parameters["goalEvent"] = test.goal_event
tracking_parameters["goalPageId"] = test.goal_page.id if test.goal_page else None

return {
'track': request_is_trackable(request),
'page': context.get('page', None),
'test': getattr(request, 'wagtail_ab_testing_test', None),
'version': AbTest.VERSION_VARIANT if serving_variant else AbTest.VERSION_CONTROL,
'track': track,
'tracking_parameters': tracking_parameters,
}
184 changes: 184 additions & 0 deletions wagtail_ab_testing/test/tests/test_templatetags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
from unittest.mock import patch

from django.urls import reverse
from django.test import RequestFactory, TestCase

from wagtail.models import Page

from wagtail_ab_testing.models import AbTest
from wagtail_ab_testing.templatetags.wagtail_ab_testing_tags import (
wagtail_ab_testing_script,
)


@patch(
"wagtail_ab_testing.templatetags.wagtail_ab_testing_tags.request_is_trackable",
return_value=True,
)
class TestWagtailAbTestingScriptTemplateTag(TestCase):
def setUp(self):
# Create test page with a draft revision
self.page = Page.objects.get(id=2).add_child(
instance=Page(title="Test", slug="test")
)
self.page.title = "Changed title"
self.page.save_revision()

# Create an A/B test
self.ab_test = AbTest.objects.create(
page=self.page,
name="Test",
variant_revision=self.page.get_latest_revision(),
status=AbTest.STATUS_RUNNING,
goal_page_id=2,
goal_event="visit-page",
sample_size=100,
)

# Create a request factory:
self.factory = RequestFactory()

def test_ab_testing_script_tag_test_with_trackable_urls(
self, mock_request_is_callable
):
"""Test the tag for a page that is part of an A/B test serving a control version."""
# A/B test page url:
url = (reverse("wagtail_ab_testing:goal_reached", args=[]),)
# Create a request
request = self.factory.post(
url,
{
"test_id": self.ab_test.id,
"version": "control",
},
)

request.wagtail_ab_testing_test = self.ab_test
request.wagtail_ab_testing_serving_variant = False

context = {
"request": request,
"page": self.page,
}

result = wagtail_ab_testing_script(context)

expected_tracking_parameters = {
"urls": {
"registerParticipant": reverse(
"wagtail_ab_testing:register_participant"
),
"goalReached": reverse("wagtail_ab_testing:goal_reached"),
},
"pageId": self.page.id,
"testId": self.ab_test.id,
"version": AbTest.VERSION_CONTROL,
"goalEvent": self.ab_test.goal_event,
"goalPageId": self.ab_test.goal_page.id,
}

self.assertEqual(result["track"], True)
self.assertDictEqual(
result["tracking_parameters"], expected_tracking_parameters
)

def test_ab_testing_script_tag_test_serving_variant(self, mock_request_is_callable):
"""Test the tag for a page serving a variant in an A/B test."""
# A/B test page url:
url = (reverse("wagtail_ab_testing:goal_reached", args=[]),)
# Create a request
request = self.factory.post(
url,
{
"test_id": self.ab_test.id,
"version": "variant",
},
)

request.wagtail_ab_testing_test = self.ab_test
request.wagtail_ab_testing_serving_variant = True

context = {
"request": request,
"page": self.page,
}

result = wagtail_ab_testing_script(context)

expected_tracking_parameters = {
"urls": {
"registerParticipant": reverse(
"wagtail_ab_testing:register_participant"
),
"goalReached": reverse("wagtail_ab_testing:goal_reached"),
},
"pageId": self.page.id,
"testId": self.ab_test.id,
"version": AbTest.VERSION_VARIANT,
"goalEvent": self.ab_test.goal_event,
"goalPageId": self.ab_test.goal_page.id,
}

self.assertEqual(result["track"], True)
self.assertDictEqual(
result["tracking_parameters"], expected_tracking_parameters
)

def test_ab_testing_script_tag_without_test_in_request(
self, mock_request_is_callable
):
"""Test the tag for a page that is not part of an A/B test."""
# Create a request for a page that is not part of an A/B test
request = self.factory.get("/")

context = {
"request": request,
"page": self.page,
}

result = wagtail_ab_testing_script(context)

expected_tracking_parameters = {
"urls": {
"registerParticipant": reverse(
"wagtail_ab_testing:register_participant"
),
"goalReached": reverse("wagtail_ab_testing:goal_reached"),
},
"pageId": self.page.id,
}

# There is still a test running and this user is being tracked:
self.assertEqual(result["track"], True)
self.assertDictEqual(result["tracking_parameters"], expected_tracking_parameters)

def test_ab_testing_script_tag_request_without_tracking(
self, mock_request_is_callable
):
"""Test the tag for a request that should not be tracked."""
# A/B test page url:
url = (reverse("wagtail_ab_testing:goal_reached", args=[]),)
# Create a request
request = self.factory.get(
url,
{
"test_id": self.ab_test.id,
"version": "variant",
},
)

request.wagtail_ab_testing_test = self.ab_test
request.wagtail_ab_testing_serving_variant = True

context = {
"request": request,
"page": self.page,
}

# Mock a request from a bot or with a DNT
mock_request_is_callable.return_value = False

result = wagtail_ab_testing_script(context)

self.assertEqual(result["track"], False)
self.assertIsNone(result["tracking_parameters"])

0 comments on commit e42afe9

Please sign in to comment.