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)