import json import pytest import sqlalchemy as sa from email_campaigns.adapters.db import DB from email_campaigns.api.schemas import CustomFont from email_campaigns.campaigns.enums import EmailCampaignStatus from email_campaigns.campaigns.exceptions import EmailCampaignAlreadySentError from email_campaigns.campaigns.handlers import UpdateCampaignFontsHandler from email_campaigns.campaigns.models import EmailCampaign from email_campaigns.emails.handlers.update_email_fonts import UpdateEmailFontsRequest from tests.unit.types import CreateModel def _font(name: str, css: str = "", url: str = "") -> CustomFont: return CustomFont(cssFontFamily=css, name=name, url=url) def _cached_font(name: str) -> CustomFont: return CustomFont( name=name, cssFontFamily=f"'{name}', Arial, sans-serif", url=f"https://fonts.googleapis.com/css2?family={name}", ) def _request( identity_id: str, campaign: EmailCampaign, font: CustomFont ) -> UpdateEmailFontsRequest: return UpdateEmailFontsRequest( identity_id=identity_id, email_id=campaign.id, font=font, ) class TestUpdateCampaignFontsHandler: @pytest.mark.db def test_adds_font_to_campaign_with_no_existing_fonts( self, handler: UpdateCampaignFontsHandler, create_model: CreateModel, identity_id: str, ) -> None: campaign = create_model(EmailCampaign, custom_fonts=None) handler.handle(_request(identity_id, campaign, _font("Roboto"))) assert campaign.custom_fonts == [_cached_font("Roboto")] @pytest.mark.db def test_new_font_appended_at_end( self, handler: UpdateCampaignFontsHandler, create_model: CreateModel, identity_id: str, ) -> None: roboto = _font("Roboto") campaign = create_model(EmailCampaign, custom_fonts=[roboto]) handler.handle(_request(identity_id, campaign, _font("Lato"))) assert campaign.custom_fonts == [roboto, _cached_font("Lato")] @pytest.mark.db def test_existing_font_replaced_with_cached_version( self, handler: UpdateCampaignFontsHandler, create_model: CreateModel, identity_id: str, ) -> None: lato = _font("Lato") campaign = create_model( EmailCampaign, custom_fonts=[_font("Roboto", css="old-css", url="old-url"), lato], ) handler.handle(_request(identity_id, campaign, _font("Roboto"))) assert campaign.custom_fonts is not None assert campaign.custom_fonts[0] == _cached_font("Roboto") assert campaign.custom_fonts[1] == lato @pytest.mark.db def test_custom_fonts_stored_as_snake_case_in_db( self, handler: UpdateCampaignFontsHandler, create_model: CreateModel, identity_id: str, db: DB, ) -> None: campaign = create_model(EmailCampaign, custom_fonts=None) handler.handle( _request( identity_id, campaign, _font("Roboto", css="'Roboto', Arial, sans-serif"), ) ) db.session.flush() row = db.session.execute( sa.text("SELECT custom_fonts FROM email_campaign WHERE id = :id"), {"id": campaign.id}, ).fetchone() assert row is not None raw = json.loads(row[0]) assert raw[0]["css_font_family"] == "'Roboto', Arial, sans-serif" assert "cssFontFamily" not in raw[0] @pytest.mark.db def test_raises_for_sent_campaign( self, handler: UpdateCampaignFontsHandler, create_model: CreateModel, identity_id: str, ) -> None: campaign = create_model(EmailCampaign, status=EmailCampaignStatus.SENT) with pytest.raises(EmailCampaignAlreadySentError): handler.handle(_request(identity_id, campaign, _font("Roboto")))