diff --git a/springfield/firefox/templatetags/misc.py b/springfield/firefox/templatetags/misc.py
index fa6c70f39..8165ae01e 100644
--- a/springfield/firefox/templatetags/misc.py
+++ b/springfield/firefox/templatetags/misc.py
@@ -21,6 +21,8 @@
from product_details import product_details
from springfield.base.templatetags.helpers import static, urlparams
+from springfield.base.urlresolvers import reverse
+from springfield.base.waffle import switch
ALL_FX_PLATFORMS = ("windows", "linux", "mac", "android", "ios")
@@ -718,3 +720,182 @@ def fxa_button(
return _fxa_product_button(
product_url, entrypoint, button_text, class_name, is_button_class, include_metrics, optional_parameters, optional_attributes
)
+
+# VPN ==================================================================
+
+
+VPN_12_MONTH_PLAN = "12-month"
+
+
+def _vpn_get_available_plans(country_code, lang, bundle_monitor_relay=False):
+ """
+ Get subscription plan IDs using country_code and page language.
+ Defaults to "US" if no matching country code is found.
+ Each country also has a default language if no match is found.
+ """
+
+ if bundle_monitor_relay:
+ country_plans = settings.VPN_MONITOR_RELAY_BUNDLE_PRICING.get(country_code, settings.VPN_MONITOR_RELAY_BUNDLE_PRICING["US"])
+ else:
+ country_plans = settings.VPN_VARIABLE_PRICING.get(country_code, settings.VPN_VARIABLE_PRICING["US"])
+
+ return country_plans.get(lang, country_plans.get("default"))
+
+
+def _vpn_get_ga_data(selected_plan):
+ id = selected_plan.get("id")
+ analytics = selected_plan.get("analytics")
+
+ ga_data = (
+ f"{{"
+ f"'id' : '{id}',"
+ f"'brand' : '{analytics.get('brand')}',"
+ f"'plan' : '{analytics.get('plan')}',"
+ f"'period' : '{analytics.get('period')}',"
+ f"'price' : '{analytics.get('price')}',"
+ f"'discount' : '{analytics.get('discount')}',"
+ f"'currency' : '{analytics.get('currency')}'"
+ f"}}"
+ )
+
+ return ga_data
+
+
+@library.global_function
+@jinja2.pass_context
+def vpn_subscribe_link(
+ ctx,
+ entrypoint,
+ link_text,
+ plan=VPN_12_MONTH_PLAN,
+ class_name=None,
+ country_code=None,
+ lang=None,
+ optional_parameters=None,
+ optional_attributes=None,
+ bundle_monitor_relay=False,
+):
+ """
+ Render a vpn.mozilla.org subscribe link with required params for FxA authentication.
+
+ Examples
+ ========
+
+ In Template
+ -----------
+
+ {{ vpn_subscribe_link(entrypoint='www.mozilla.org-vpn-product-page',
+ link_text='Get Mozilla VPN',
+ country_code=country_code,
+ lang=LANG) }}
+ """
+
+ if bundle_monitor_relay:
+ product_id = settings.VPN_MONITOR_RELAY_BUNDLE_PRODUCT_ID
+ else:
+ product_id = settings.VPN_PRODUCT_ID
+
+ available_plans = _vpn_get_available_plans(country_code, lang, bundle_monitor_relay)
+ selected_plan = available_plans.get(plan, VPN_12_MONTH_PLAN)
+ plan_id = selected_plan.get("id")
+
+ if switch("vpn-subplat-next"):
+ product_id = settings.VPN_PRODUCT_ID_NEXT
+ plan_slug = "yearly" if plan == VPN_12_MONTH_PLAN else "monthly"
+
+ # For testing/QA we support a test 'daily' API endpoint on the staging API only
+ # We only want to override the monthly VPN option when in QA mode; annual remains unchanged
+ # https://mozilla-hub.atlassian.net/browse/VPN-6985
+ if plan_slug == "monthly" and settings.VPN_SUBSCRIPTION_USE_DAILY_MODE__QA_ONLY:
+ plan_slug = "daily"
+
+ if bundle_monitor_relay:
+ product_id = "privacyprotectionplan"
+ plan_slug = "yearly"
+
+ product_url = f"{settings.VPN_SUBSCRIPTION_URL_NEXT}{product_id}/{plan_slug}/landing/"
+ else:
+ product_url = f"{settings.VPN_SUBSCRIPTION_URL}subscriptions/products/{product_id}?plan={plan_id}"
+
+ if "analytics" in selected_plan:
+ if class_name is None:
+ class_name = ""
+ class_name += " ga-begin-checkout"
+ if optional_attributes is None:
+ optional_attributes = {}
+ optional_attributes["data-ga-item"] = _vpn_get_ga_data(selected_plan)
+
+ return _vpn_product_link(product_url, entrypoint, link_text, class_name, optional_parameters, optional_attributes)
+
+
+def _vpn_product_link(product_url, entrypoint, link_text, class_name=None, optional_parameters=None, optional_attributes=None):
+ separator = "&" if "?" in product_url else "?"
+ client_id = settings.VPN_CLIENT_ID
+ href = f"{product_url}{separator}entrypoint={entrypoint}&form_type=button&service={client_id}&utm_source={entrypoint}&utm_medium=referral"
+
+ if optional_parameters:
+ params = "&".join(f"{param}={val}" for param, val in optional_parameters.items())
+ href += f"&{params}"
+
+ css_class = "js-fxa-product-cta-link js-fxa-product-button"
+ attrs = ""
+
+ if optional_attributes:
+ attrs += " ".join(f'{attr}="{val}"' for attr, val in optional_attributes.items())
+
+ # If there's a `data-cta-position` attribute for GA, also pass that as a query param to vpn.m.o.
+ position = optional_attributes.get("data-cta-position", None)
+
+ if position:
+ href += f"&data_cta_position={position}"
+
+ if class_name:
+ css_class += f" {class_name}"
+
+ markup = f'{link_text}'
+
+ return Markup(markup)
+
+
+@library.global_function
+@jinja2.pass_context
+def vpn_product_referral_link(
+ ctx,
+ referral_id="",
+ link_to_pricing_page=False,
+ page_anchor="",
+ link_text=None,
+ is_cta_button_styled=True,
+ class_name=None,
+ optional_attributes=None,
+ optional_parameters=None,
+):
+ """
+ Render link to the /products/vpn/ landing page with referral attribution markup
+
+ Examples
+ ========
+
+ In Template
+ -----------
+
+ {{ vpn_product_referral_link(referral_id='navigation', link_text='Get Mozilla VPN') }}
+ """
+
+ href = reverse("products.vpn.pricing") if link_to_pricing_page else reverse("products.vpn.landing")
+ css_class = "mzp-c-button js-fxa-product-referral-link" if is_cta_button_styled else "js-fxa-product-referral-link"
+ attrs = f'data-referral-id="{referral_id}" '
+
+ if optional_attributes:
+ attrs += " ".join(f'{attr}="{val}"' for attr, val in optional_attributes.items())
+
+ if optional_parameters:
+ params = "&".join(f"{param}={val}" for param, val in optional_parameters.items())
+ href += f"?{params}"
+
+ if class_name:
+ css_class += f" {class_name}"
+
+ markup = f'{link_text}'
+
+ return Markup(markup)
diff --git a/springfield/firefox/tests/test_helper_misc.py b/springfield/firefox/tests/test_helper_misc.py
index d989860b0..ffd0d754d 100644
--- a/springfield/firefox/tests/test_helper_misc.py
+++ b/springfield/firefox/tests/test_helper_misc.py
@@ -26,6 +26,121 @@
TEST_FXA_ENDPOINT = "https://accounts.firefox.com/"
+TEST_VPN_ENDPOINT = "https://vpn.mozilla.org/"
+TEST_VPN_PRODUCT_ID = "prod_FvnsFHIfezy3ZI"
+TEST_VPN_SUBSCRIPTION_URL = "https://accounts.firefox.com/"
+
+TEST_VPN_PLAN_ID_MATRIX = {
+ "chf": {
+ "de": {
+ "12-month": {"id": "price_1J5JssJNcmPzuWtR616BH4aU", "price": "CHF 5.99", "total": "CHF 71.88", "saving": 45},
+ "6-month": {"id": "price_1J5JtWJNcmPzuWtRMd2siphH", "price": "CHF 7.99", "total": "CHF 47.94", "saving": 27},
+ "monthly": {"id": "price_1J5Ju3JNcmPzuWtR3GpNYSWj", "price": "CHF 10.99", "total": None, "saving": None},
+ },
+ "fr": {
+ "12-month": {"id": "price_1J5JunJNcmPzuWtRo9dLxn6M", "price": "CHF 5.99", "total": "CHF 71.88", "saving": 45},
+ "6-month": {"id": "price_1J5JvLJNcmPzuWtRayB4d7Ij", "price": "CHF 7.99", "total": "CHF 47.94", "saving": 27},
+ "monthly": {"id": "price_1J5JvjJNcmPzuWtR3wwy1dcR", "price": "CHF 10.99", "total": None, "saving": None},
+ },
+ "it": {
+ "12-month": {"id": "price_1J5JwWJNcmPzuWtRgrx5fjOc", "price": "CHF 5.99", "total": "CHF 71.88", "saving": 45},
+ "6-month": {"id": "price_1J5JwvJNcmPzuWtRH2HuhWM5", "price": "CHF 7.99", "total": "CHF 47.94", "saving": 27},
+ "monthly": {"id": "price_1J5JxGJNcmPzuWtRrp5e1SUB", "price": "CHF 10.99", "total": None, "saving": None},
+ },
+ },
+ "euro": {
+ "de": {
+ "12-month": {"id": "price_1IgwblJNcmPzuWtRynC7dqQa", "price": "4,99 €", "total": "59,88 €", "saving": 50},
+ "6-month": {"id": "price_1IgwaHJNcmPzuWtRuUfSR4l7", "price": "6,99 €", "total": "41,94 €", "saving": 30},
+ "monthly": {"id": "price_1IgwZVJNcmPzuWtRg9Wssh2y", "price": "9,99 €", "total": None, "saving": None},
+ },
+ "en": {
+ "12-month": {
+ "id": "price_1JcdvBJNcmPzuWtROLbEH9d2",
+ "price": "4,99 €",
+ "total": "59,88 €",
+ "saving": 50,
+ },
+ "6-month": {
+ "id": "price_1Jcdu8JNcmPzuWtRK6u5TUoZ",
+ "price": "6,99 €",
+ "total": "41,94 €",
+ "saving": 30,
+ },
+ "monthly": {
+ "id": "price_1JcdsSJNcmPzuWtRGF9Y5TMJ",
+ "price": "9,99 €",
+ "total": None,
+ "saving": None,
+ },
+ },
+ "es": {
+ "12-month": {"id": "price_1J5JCdJNcmPzuWtRrvQMFLlP", "price": "4,99 €", "total": "59,88 €", "saving": 50},
+ "6-month": {"id": "price_1J5JDFJNcmPzuWtRrC4IeXTs", "price": "6,99 €", "total": "41,94 €", "saving": 30},
+ "monthly": {"id": "price_1J5JDgJNcmPzuWtRqQtIbktk", "price": "9,99 €", "total": None, "saving": None},
+ },
+ "fr": {
+ "12-month": {"id": "price_1IgnlcJNcmPzuWtRjrNa39W4", "price": "4,99 €", "total": "59,88 €", "saving": 50},
+ "6-month": {"id": "price_1IgoxGJNcmPzuWtRG7l48EoV", "price": "6,99 €", "total": "41,94 €", "saving": 30},
+ "monthly": {"id": "price_1IgowHJNcmPzuWtRzD7SgAYb", "price": "9,99 €", "total": None, "saving": None},
+ },
+ "it": {
+ "12-month": {"id": "price_1J4owvJNcmPzuWtRomVhWQFq", "price": "4,99 €", "total": "59,88 €", "saving": 50},
+ "6-month": {"id": "price_1J5J7eJNcmPzuWtRKdQi4Tkk", "price": "6,99 €", "total": "41,94 €", "saving": 30},
+ "monthly": {"id": "price_1J5J6iJNcmPzuWtRK5zfoguV", "price": "9,99 €", "total": None, "saving": None},
+ },
+ "nl": {
+ "12-month": {"id": "price_1J5JRGJNcmPzuWtRXwXA84cm", "price": "4,99 €", "total": "59,88 €", "saving": 50},
+ "6-month": {"id": "price_1J5JRmJNcmPzuWtRyFGj0tkN", "price": "6,99 €", "total": "41,94 €", "saving": 30},
+ "monthly": {"id": "price_1J5JSkJNcmPzuWtR54LPH2zi", "price": "9,99 €", "total": None, "saving": None},
+ },
+ },
+ "usd": {
+ "en": {
+ "12-month": {"id": "price_1Iw85dJNcmPzuWtRyhMDdtM7", "price": "US$4.99", "total": "US$59.88", "saving": 50},
+ "6-month": {"id": "price_1Iw87cJNcmPzuWtRefuyqsOd", "price": "US$7.99", "total": "US$47.94", "saving": 20},
+ "monthly": {"id": "price_1Iw7qSJNcmPzuWtRMUZpOwLm", "price": "US$9.99", "total": None, "saving": None},
+ }
+ },
+}
+
+TEST_VPN_VARIABLE_PRICING = {
+ "AT": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["de"],
+ },
+ "BE": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["nl"],
+ "de": TEST_VPN_PLAN_ID_MATRIX["euro"]["de"],
+ "fr": TEST_VPN_PLAN_ID_MATRIX["euro"]["fr"],
+ },
+ "CH": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["chf"]["de"],
+ "fr": TEST_VPN_PLAN_ID_MATRIX["chf"]["fr"],
+ "it": TEST_VPN_PLAN_ID_MATRIX["chf"]["it"],
+ },
+ "DE": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["de"],
+ },
+ "ES": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["es"],
+ },
+ "FR": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["fr"],
+ },
+ "IE": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["en"],
+ },
+ "IT": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["it"],
+ },
+ "NL": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["euro"]["nl"],
+ },
+ "US": {
+ "default": TEST_VPN_PLAN_ID_MATRIX["usd"]["en"],
+ },
+}
+
jinja_env = Jinja2.get_default()
@@ -1090,3 +1205,564 @@ def test_fxa_button_email(self):
def test_needs_data_consent(country_code, expected):
template = "{{ needs_data_consent('%s') }}" % country_code
assert render(template) == expected
+
+@override_settings(
+ FXA_ENDPOINT=TEST_FXA_ENDPOINT,
+ VPN_PRODUCT_ID=TEST_VPN_PRODUCT_ID,
+ VPN_SUBSCRIPTION_URL=TEST_VPN_SUBSCRIPTION_URL,
+ VPN_VARIABLE_PRICING=TEST_VPN_VARIABLE_PRICING,
+)
+class TestVPNSubscribeLink(TestCase):
+ rf = RequestFactory()
+
+ def _render(
+ self,
+ entrypoint="www.mozilla.org-vpn-product-page",
+ link_text="Get Mozilla VPN",
+ plan="12-month",
+ class_name="mzp-c-button",
+ country_code=None,
+ lang=None,
+ optional_parameters=None,
+ optional_attributes=None,
+ ):
+ req = self.rf.get("/")
+ req.locale = "en-US"
+ return render(
+ f"""{{{{ vpn_subscribe_link('{entrypoint}', '{link_text}', '{plan}', '{class_name}', '{country_code}',
+ '{lang}', {optional_parameters}, {optional_attributes}) }}}}""",
+ {"request": req},
+ )
+
+ def test_vpn_subscribe_link_variable_12_month(self):
+ """Should return expected markup for variable 12-month plan link"""
+ markup = self._render(
+ plan="12-month",
+ country_code="US",
+ lang="en-US",
+ optional_parameters={"utm_campaign": "vpn-product-page"},
+ optional_attributes={"data-cta-text": "Get Mozilla VPN monthly", "data-cta-type": "fxa-vpn", "data-cta-position": "primary"},
+ )
+ expected = (
+ 'Get Mozilla VPN'
+ )
+ self.assertEqual(markup, expected)
+
+ def test_vpn_subscribe_link_variable_6_month(self):
+ """Should return expected markup for variable 6-month plan link"""
+ markup = self._render(
+ plan="6-month",
+ country_code="US",
+ lang="en-US",
+ optional_parameters={"utm_campaign": "vpn-product-page"},
+ optional_attributes={"data-cta-text": "Get Mozilla VPN monthly", "data-cta-type": "fxa-vpn", "data-cta-position": "primary"},
+ )
+ expected = (
+ 'Get Mozilla VPN'
+ )
+ self.assertEqual(markup, expected)
+
+ def test_vpn_subscribe_link_variable_monthly(self):
+ """Should return expected markup for variable monthly plan link"""
+ markup = self._render(
+ plan="monthly",
+ country_code="US",
+ lang="en-US",
+ optional_parameters={"utm_campaign": "vpn-product-page"},
+ optional_attributes={"data-cta-text": "Get Mozilla VPN monthly", "data-cta-type": "fxa-vpn", "data-cta-position": "primary"},
+ )
+ expected = (
+ 'Get Mozilla VPN'
+ )
+ self.assertEqual(markup, expected)
+
+ def test_vpn_subscribe_link_variable_12_month_us_en(self):
+ """Should contain expected 12-month plan ID (US / en-US)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="US",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1Iw85dJNcmPzuWtRyhMDdtM7", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_us_en(self):
+ """Should contain expected 6-month plan ID (US / en-US)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="US",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1Iw87cJNcmPzuWtRefuyqsOd", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_us_en(self):
+ """Should contain expected monthly plan ID (US / en-US)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="US",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1Iw7qSJNcmPzuWtRMUZpOwLm", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_ca_en(self):
+ """Should contain expected 12-month plan ID (CA / en-CA)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="CA",
+ lang="en-CA",
+ )
+ self.assertIn("?plan=price_1Iw85dJNcmPzuWtRyhMDdtM7", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_ca_en(self):
+ """Should contain expected 6-month plan ID (CA / en-CA)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="CA",
+ lang="en-CA",
+ )
+ self.assertIn("?plan=price_1Iw87cJNcmPzuWtRefuyqsOd", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_ca_en(self):
+ """Should contain expected monthly plan ID in (CA / en-CA)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="CA",
+ lang="en-CA",
+ )
+ self.assertIn("?plan=price_1Iw7qSJNcmPzuWtRMUZpOwLm", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_gb_en(self):
+ """Should contain expected 12-month plan ID (GB / en-GB)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="GB",
+ lang="en-GB",
+ )
+ self.assertIn("?plan=price_1Iw85dJNcmPzuWtRyhMDdtM7", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_gb_en(self):
+ """Should contain expected 6-month plan ID (GB / en-GB)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="GB",
+ lang="en-GB",
+ )
+ self.assertIn("?plan=price_1Iw87cJNcmPzuWtRefuyqsOd", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_gb_en(self):
+ """Should contain expected monthly plan ID (GB / en-GB)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="GB",
+ lang="en-GB",
+ )
+ self.assertIn("?plan=price_1Iw7qSJNcmPzuWtRMUZpOwLm", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_at_de(self):
+ """Should contain expected 12-month plan ID (AT / de)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="AT",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwblJNcmPzuWtRynC7dqQa", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_at_de(self):
+ """Should contain expected 6-month plan ID (AT / de)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="AT",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwaHJNcmPzuWtRuUfSR4l7", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_at_de(self):
+ """Should contain expected monthly plan ID (AT / de)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="AT",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwZVJNcmPzuWtRg9Wssh2y", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_be_nl(self):
+ """Should contain expected 12-month plan ID (BE / nl)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="BE",
+ lang="nl",
+ )
+ self.assertIn("?plan=price_1J5JRGJNcmPzuWtRXwXA84cm", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_be_nl(self):
+ """Should contain expected 6-month plan ID (BE / nl)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="BE",
+ lang="nl",
+ )
+ self.assertIn("?plan=price_1J5JRmJNcmPzuWtRyFGj0tkN", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_be_nl(self):
+ """Should contain expected monthly plan ID (BE / nl)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="BE",
+ lang="nl",
+ )
+ self.assertIn("?plan=price_1J5JSkJNcmPzuWtR54LPH2zi", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_be_de(self):
+ """Should contain expected 12-month plan ID (BE / de)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="BE",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwblJNcmPzuWtRynC7dqQa", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_be_de(self):
+ """Should contain expected 6-month plan ID (BE / de)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="BE",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwaHJNcmPzuWtRuUfSR4l7", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_be_de(self):
+ """Should contain expected monthly plan ID (BE / de)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="BE",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwZVJNcmPzuWtRg9Wssh2y", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_be_fr(self):
+ """Should contain expected 12-month plan ID (BE / fr)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="BE",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1IgnlcJNcmPzuWtRjrNa39W4", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_be_fr(self):
+ """Should contain expected 6-month plan ID (BE / fr)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="BE",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1IgoxGJNcmPzuWtRG7l48EoV", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_be_fr(self):
+ """Should contain expected monthly plan ID (BE / fr)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="BE",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1IgowHJNcmPzuWtRzD7SgAYb", markup)
+
+ def test_vpn_default_language_selection_be_en(self):
+ """Should should select default language if no match is found (BE / en)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="BE",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1J5JSkJNcmPzuWtR54LPH2zi", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_ch_de(self):
+ """Should contain expected 12-month plan ID (CH / de)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="CH",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1J5JssJNcmPzuWtR616BH4aU", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_ch_de(self):
+ """Should contain expected 6-month plan ID (CH / de)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="CH",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1J5JtWJNcmPzuWtRMd2siphH", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_ch_de(self):
+ """Should contain expected monthly plan ID (CH / de)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="CH",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1J5Ju3JNcmPzuWtR3GpNYSWj", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_ch_fr(self):
+ """Should contain expected 12-month plan ID (CH / fr)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="CH",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1J5JunJNcmPzuWtRo9dLxn6M", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_ch_fr(self):
+ """Should contain expected 6-month plan ID (CH / fr)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="CH",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1J5JvLJNcmPzuWtRayB4d7Ij", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_ch_fr(self):
+ """Should contain expected monthly plan ID (CH / fr)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="CH",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1J5JvjJNcmPzuWtR3wwy1dcR", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_ch_it(self):
+ """Should contain expected 12-month plan ID (CH / it)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="CH",
+ lang="it",
+ )
+ self.assertIn("?plan=price_1J5JwWJNcmPzuWtRgrx5fjOc", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_ch_it(self):
+ """Should contain expected 6-month plan ID (CH / it)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="CH",
+ lang="it",
+ )
+ self.assertIn("?plan=price_1J5JwvJNcmPzuWtRH2HuhWM5", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_ch_it(self):
+ """Should contain expected monthly plan ID (CH / it)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="CH",
+ lang="it",
+ )
+ self.assertIn("?plan=price_1J5JxGJNcmPzuWtRrp5e1SUB", markup)
+
+ def test_vpn_default_language_selection_ch_en(self):
+ """Should should select default language if no match is found (CH / en)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="CH",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1J5Ju3JNcmPzuWtR3GpNYSWj", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_de_de(self):
+ """Should contain expected 12-month plan ID (DE / de)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="DE",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwblJNcmPzuWtRynC7dqQa", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_de_de(self):
+ """Should contain expected 6-month plan ID (DE / de)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="DE",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwaHJNcmPzuWtRuUfSR4l7", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_de_de(self):
+ """Should contain expected monthly plan ID (DE / de)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="DE",
+ lang="de",
+ )
+ self.assertIn("?plan=price_1IgwZVJNcmPzuWtRg9Wssh2y", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_fr_fr(self):
+ """Should contain expected 12-month plan ID (FR / fr)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="FR",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1IgnlcJNcmPzuWtRjrNa39W4", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_fr_fr(self):
+ """Should contain expected 6-month plan ID (FR / fr)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="FR",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1IgoxGJNcmPzuWtRG7l48EoV", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_fr_fr(self):
+ """Should contain expected monthly plan ID (FR / fr)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="FR",
+ lang="fr",
+ )
+ self.assertIn("?plan=price_1IgowHJNcmPzuWtRzD7SgAYb", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_es_es(self):
+ """Should contain expected 12-month plan ID (ES / es-ES)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="ES",
+ lang="es-ES",
+ )
+ self.assertIn("?plan=price_1J5JCdJNcmPzuWtRrvQMFLlP", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_es_es(self):
+ """Should contain expected 6-month plan ID (ES / es-ES)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="ES",
+ lang="es-ES",
+ )
+ self.assertIn("?plan=price_1J5JDFJNcmPzuWtRrC4IeXTs", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_es_es(self):
+ """Should contain expected monthly plan ID (ES / es-ES)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="ES",
+ lang="es-ES",
+ )
+ self.assertIn("?plan=price_1J5JDgJNcmPzuWtRqQtIbktk", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_it_it(self):
+ """Should contain expected 12-month plan ID (IT / it)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="IT",
+ lang="it",
+ )
+ self.assertIn("?plan=price_1J4owvJNcmPzuWtRomVhWQFq", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_it_it(self):
+ """Should contain expected 6-month plan ID (IT / it)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="IT",
+ lang="it",
+ )
+ self.assertIn("?plan=price_1J5J7eJNcmPzuWtRKdQi4Tkk", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_it_it(self):
+ """Should contain expected monthly plan ID (IT / it)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="IT",
+ lang="it",
+ )
+ self.assertIn("?plan=price_1J5J6iJNcmPzuWtRK5zfoguV", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_ie_en(self):
+ """Should contain expected 12-month plan ID (IE / en-US)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="IE",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1JcdvBJNcmPzuWtROLbEH9d2", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_ie_en(self):
+ """Should contain expected 6-month plan ID (IE / en-US)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="IE",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1Jcdu8JNcmPzuWtRK6u5TUoZ", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_ie_en(self):
+ """Should contain expected monthly plan ID (IE / en-US)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="IE",
+ lang="en-US",
+ )
+ self.assertIn("?plan=price_1JcdsSJNcmPzuWtRGF9Y5TMJ", markup)
+
+ def test_vpn_subscribe_link_variable_12_month_nl_nl(self):
+ """Should contain expected 12-month plan ID (NL / nl)"""
+ markup = self._render(
+ plan="12-month",
+ country_code="NL",
+ lang="nl",
+ )
+ self.assertIn("?plan=price_1J5JRGJNcmPzuWtRXwXA84cm", markup)
+
+ def test_vpn_subscribe_link_variable_6_month_nl_nl(self):
+ """Should contain expected 16-month plan ID (NL / nl)"""
+ markup = self._render(
+ plan="6-month",
+ country_code="NL",
+ lang="nl",
+ )
+ self.assertIn("?plan=price_1J5JRmJNcmPzuWtRyFGj0tkN", markup)
+
+ def test_vpn_subscribe_link_variable_monthly_nl_nl(self):
+ """Should contain expected monthly plan ID (NL / nl)"""
+ markup = self._render(
+ plan="monthly",
+ country_code="NL",
+ lang="nl",
+ )
+ self.assertIn("?plan=price_1J5JSkJNcmPzuWtR54LPH2zi", markup)
+
+
+class TestVPNProductReferralLink(TestCase):
+ rf = RequestFactory()
+
+ def _render(self, referral_id, page_anchor, link_text, class_name, optional_attributes):
+ with self.activate_locale("en-US"):
+ req = self.rf.get("/")
+ req.locale = "en-US"
+ return render(
+ f"{{{{ vpn_product_referral_link('{referral_id}', '{page_anchor}', '{link_text}', '{class_name}', {optional_attributes}) }}}}",
+ {"request": req},
+ )
+
+ def test_vpn_product_referral_link(self):
+ """Should return expected markup"""
+ markup = self._render(
+ referral_id="navigation",
+ page_anchor="#pricing",
+ link_text="Get Mozilla VPN",
+ class_name="mzp-t-secondary mzp-t-md",
+ optional_attributes={"data-cta-text": "Get Mozilla VPN", "data-cta-type": "button"},
+ )
+ expected = (
+ 'Get Mozilla VPN'
+ )
+ self.assertEqual(markup, expected)