testapp/factories.py (107 lines of code) (raw):

import factory import factory.django import wagtail_factories from django.contrib.auth.hashers import make_password from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.db import models from django.utils import timezone from wagtail import blocks from wagtail.models import Locale, Site, TranslatableMixin from wagtail_localize.models import TranslatableObject, Translation, TranslationSource from .models import BodyBlock, InfoPage, InfoSnippet class UserFactory(factory.django.DjangoModelFactory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = User username = factory.Sequence(lambda n: f"user-{n}") password = factory.Transformer("password", transform=lambda p: make_password(p)) # https://github.com/nhsuk/wagtail-factories/blob/9f1d2221773282ac41e1c431edef01abc011a507/src/wagtail_factories/blocks.py#L161 class RichTextBlockFactory(factory.Factory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = blocks.RichTextBlock @classmethod def _build(cls, model_class, *args, value="", **kwargs): block = model_class() return block.to_python(value) @classmethod def _create(cls, model_class, *args, **kwargs): return cls._build(model_class, *args, **kwargs) class BodyBlockFactory(wagtail_factories.StreamBlockFactory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = BodyBlock heading = factory.SubFactory(wagtail_factories.CharBlockFactory) paragraph = factory.SubFactory(RichTextBlockFactory) document = factory.SubFactory(wagtail_factories.DocumentChooserBlockFactory) image = factory.SubFactory(wagtail_factories.ImageChooserBlockFactory) class InfoPageFactory(wagtail_factories.PageFactory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = InfoPage body = wagtail_factories.StreamFieldFactory(BodyBlockFactory) @factory.post_generation def site( obj: InfoPage, # pyright: ignore[reportGeneralTypeIssues] create: bool, extracted: Site | None, **kwargs, ): """ Post-generation hook for making sure a default site exists when creating InfoPage instances with this factory. If a Site object is passed in, its root page will be set to the just-created InfoPage. Otherwise, if no default Site exists and the just-created InfoPage is at the top level of the page tree, it will be set as the root page of a new default Site. Any kwargs passed in will be passed to the SiteFactory used to create the Site. """ if ( not create or obj.depth != 2 or Site.objects.filter(is_default_site=True).exists() ): return if extracted is not None: extracted.root_page = obj extracted.save() return extracted return wagtail_factories.SiteFactory( **{ "hostname": "testserver", "port": 80, "site_name": "wagtail-localize-smartling test site", "root_page": obj, "is_default_site": True, **kwargs, } ) class InfoSnippetFactory(factory.django.DjangoModelFactory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = InfoSnippet class TranslatablebObjectFactory(factory.django.DjangoModelFactory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = TranslatableObject class LocaleFactory(factory.django.DjangoModelFactory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = Locale def get_translatableobject_content_type(obj: TranslatableMixin) -> ContentType: for cls in type(obj).mro(): if issubclass(cls, models.Model): for field in cls._meta.get_fields(include_parents=False): if field.name == "translation_key": return ContentType.objects.get_for_model(cls) raise ValueError("obj must be a TranslatableMixin instance") class TranslationSourceFactory(factory.django.DjangoModelFactory): """ When calling this factory, you must pass in a source_instance kwarg that is an instance of TranslatableMixin. The translation key, locale and content types will be derived from this. """ class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = TranslationSource exclude = ( "source_instance", "translatableobject_content_type", ) object = factory.SubFactory( TranslatablebObjectFactory, translation_key=factory.SelfAttribute("..source_instance.translation_key"), content_type=factory.SelfAttribute("..translatableobject_content_type"), ) specific_content_type = factory.LazyAttribute( lambda obj: ContentType.objects.get_for_model(obj.source_instance) ) translatableobject_content_type = factory.LazyAttribute( lambda obj: get_translatableobject_content_type(obj.source_instance) ) locale = factory.SelfAttribute("source_instance.locale") last_updated_at = factory.LazyFunction(timezone.now) class TranslationFactory(factory.django.DjangoModelFactory): class Meta: # pyright: ignore[reportIncompatibleVariableOverride] model = Translation uuid = factory.Faker("uuid4") source = factory.SubFactory(TranslationSourceFactory) target_locale = factory.SubFactory(LocaleFactory)