Fixtures#
Every fixture pytest-plone registers, grouped by what it gives you.
The integration and functional fixtures these depend on are generated from your testing layers by fixtures_factory.
For what the two layers mean and when to choose which, see About testing layers, scopes, and isolation.
Overview#
Fixture |
Scope |
Requires |
|---|---|---|
|
Function |
|
|
Function |
|
|
Class |
|
|
Class |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Class |
|
|
Class |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Function |
|
|
Session |
— |
|
Function |
|
|
Function |
|
|
Session |
— |
|
Session |
— |
|
Session |
— |
|
Session |
|
|
Session |
— |
|
Session |
|
|
Session |
— |
|
Session |
— |
|
Session |
— |
|
Session |
— |
Portal and app#
The Plone site and the Zope root, on either testing layer.
The functional_ variants are bound to the functional layer, which uses a real transaction and a running server rather than the integration layer’s stacked DemoStorage.
Use them for REST API and browser tests.
The class-scoped variants share one portal across every test method in a class.
They honor @pytest.mark.portal only when it is applied to the class; a class-scoped fixture cannot see method-level markers.
The app_class and functional_app_class fixtures return the Zope root at class scope.
Each one drives the single per-class setup and teardown that its portal counterpart depends on, so a class can ask for both the app and the portal without setting the layer up twice.
- pytest_plone.fixtures.base.app(integration: plone.testing.layer.Layer) OFS.Application.Application#
Returns the root of a Zope application for an integration Layer.
Example usage:
def test_app(app): assert app.title == "Zope"
- pytest_plone.fixtures.base.portal(integration: plone.testing.layer.Layer, request: pytest.FixtureRequest) Products.CMFPlone.Portal.PloneSite#
Returns the default Plone Site for an integration Layer.
Supports
@pytest.mark.portalto apply GenericSetup profiles, create content, and grant roles before the test runs.Example usage:
def test_portal(portal): assert portal.title == "Plone site" @pytest.mark.portal( profiles=["my.addon:testing"], content=[{"type": "Document", "id": "doc1", "title": "A document"}], roles=["Manager"], ) def test_portal_with_marker(portal): assert "doc1" in portal
- pytest_plone.fixtures.base.app_class(integration_class: plone.testing.layer.Layer) collections.abc.Generator[OFS.Application.Application, None, None]#
Returns the root of a Zope application for an integration Layer, class-scoped.
Class-scoped counterpart to :func:
app.zope.pytestlayeronly invokestestSetUpfor function-scoped fixtures, so this fixture drives the per-classtestSetUp/testTearDownlifecycle itself. :func:portal_classbuilds on it, so a test class can request bothapp_classandportal_classwithout setting the layer up twice.Example usage:
class TestApp: def test_app(self, app_class): assert app_class.title == "Zope"
- pytest_plone.fixtures.base.portal_class(app_class: OFS.Application.Application, integration_class: plone.testing.layer.Layer, request: pytest.FixtureRequest) Products.CMFPlone.Portal.PloneSite#
Returns the default Plone Site for an integration Layer, class-scoped.
Class-scoped counterpart to :func:
portal. The same portal instance is shared across every test method in the class, so setup runs once per class instead of once per test. The per-classtestSetUp/testTearDownlifecycle is driven by :func:app_class, on which this fixture depends.Honors
@pytest.mark.portalapplied at the class level — method-level markers are not visible to a class-scoped fixture and are ignored.Example usage:
@pytest.mark.portal( content=[{"type": "Document", "id": "doc1", "title": "Doc"}], roles=["Manager"], ) class TestSomething: def test_one(self, portal_class): assert "doc1" in portal_class def test_two(self, portal_class): assert "doc1" in portal_class
- pytest_plone.fixtures.base.functional_app(functional: plone.testing.layer.Layer) OFS.Application.Application#
Returns the root of a Zope application for a functional Layer.
Mirrors :func:
appbut bound to thefunctionallayer. Use this in REST API, browser, or other tests that require transaction-level isolation instead of the integration-layer stacked-DemoStorage.Example usage:
def test_functional_app(functional_app): assert functional_app.title == "Zope"
- pytest_plone.fixtures.base.functional_portal(functional: plone.testing.layer.Layer, request: pytest.FixtureRequest) Products.CMFPlone.Portal.PloneSite#
Returns the default Plone Site for a functional Layer.
Mirrors :func:
portalbut bound to thefunctionallayer and also honors@pytest.mark.portalfor GenericSetup profiles, pre-created content, and test-user roles.Example usage:
def test_functional_portal(functional_portal): assert functional_portal.title == "Plone site"
- pytest_plone.fixtures.base.functional_app_class(functional_class: plone.testing.layer.Layer) collections.abc.Generator[OFS.Application.Application, None, None]#
Returns the root of a Zope application for a functional Layer, class-scoped.
Class-scoped counterpart to :func:
functional_app.zope.pytestlayeronly invokestestSetUpfor function-scoped fixtures, so this fixture drives the per-classtestSetUp/testTearDownlifecycle itself.- Func:
functional_portal_classbuilds on it, so a test class can request both without setting the layer up twice.
Example usage:
class TestFunctionalApp: def test_app(self, functional_app_class): assert functional_app_class.title == "Zope"
- pytest_plone.fixtures.base.functional_portal_class(functional_app_class: OFS.Application.Application, functional_class: plone.testing.layer.Layer, request: pytest.FixtureRequest) Products.CMFPlone.Portal.PloneSite#
Returns the default Plone Site for a functional Layer, class-scoped.
Class-scoped counterpart to :func:
functional_portal. The same portal instance is shared across every test method in the class — the typical pattern for REST API / service test suites that need a persistent portal. The per-classtestSetUp/testTearDownlifecycle is driven by- Func:
functional_app_class, on which this fixture depends.
Honors
@pytest.mark.portalapplied at the class level — method-level markers are not visible to a class-scoped fixture and are ignored.Example usage:
@pytest.mark.portal(roles=["Manager"]) class TestRESTService: def test_one(self, functional_portal_class): assert functional_portal_class.title == "Plone site" def test_two(self, functional_portal_class): assert "plone" in functional_portal_class.absolute_url()
Requests#
http_request and functional_http_request return the request object bound to the layer.
request_factory is different in kind: it builds authenticated HTTP sessions that talk to a running Plone over the network, which is what REST API tests need.
manager_request and anon_request are shorthands for the two common identities.
- pytest_plone.fixtures.base.http_request(integration: plone.testing.layer.Layer) ZPublisher.HTTPRequest.HTTPRequest#
Returns the current request object.
Example usage:
def test_http_request(http_request): assert http_request.method == "GET"
- pytest_plone.fixtures.base.functional_http_request(functional: plone.testing.layer.Layer) ZPublisher.HTTPRequest.HTTPRequest#
Returns the current request object for a functional Layer.
Mirrors :func:
http_requestbut bound to thefunctionallayer.Example usage:
def test_functional_http_request(functional_http_request): assert functional_http_request.method == "GET"
- pytest_plone.fixtures.requests.request_factory(functional_portal: Products.CMFPlone.Portal.PloneSite, request: pytest.FixtureRequest) pytest_plone._types.RequestFactory#
Builder fixture for HTTP request sessions against the functional portal.
Returns a callable that produces a :class:
RelativeSessionbound to the portal URL. The session is closed automatically at the end of the test.Parameters accepted by the returned callable:
role—"Manager"or"Anonymous"(default). Maps to predefined test credentials. Unknown roles raiseValueError— usebasic_authfor other identities.basic_auth—(username, password)tuple; takes precedence overrolewhen provided.api— whenTrue(default), the base URL is suffixed with++api++so relative requests hit the REST API traverser.
Example usage:
def test_list_content(request_factory): session = request_factory(role="Manager") response = session.get("/") assert response.status_code == 200
- pytest_plone.fixtures.requests.manager_request(request_factory: pytest_plone._types.RequestFactory) pytest_plone.fixtures.requests.RelativeSession#
A
RelativeSessionauthenticated as the portal owner (Manager).Example usage:
def test_admin_endpoint(manager_request): response = manager_request.get("/@controlpanels") assert response.status_code == 200
- pytest_plone.fixtures.requests.anon_request(request_factory: pytest_plone._types.RequestFactory) pytest_plone.fixtures.requests.RelativeSession#
A
RelativeSessionwith no authentication (Anonymous).Example usage:
def test_public_endpoint(anon_request): response = anon_request.get("/") assert response.status_code == 200
- class RelativeSession(base_url: str)#
Bases:
requests.Sessionrequests.Sessionthat resolves relative URLs against a base URL.Minimal standalone equivalent of
plone.restapi.testing.RelativeSession— avoids pulling the fullplone.restapi[test]import chain into pytest-plone’s runtime.Initialization
- request(method: str, url: str, **kwargs)#
Add-ons#
Fixtures for the canonical add-on test suite: is the product installed, are its browser layers registered, is its control panel there, is its profile at the expected version.
- pytest_plone.fixtures.addons.installer(portal: Products.CMFPlone.Portal.PloneSite) Products.CMFPlone.controlpanel.browser.quickinstaller.InstallerView#
Portal helper for managing add-ons using GenericSetup.
Example usage:
PACKAGE_NAME = "collective.person" class TestSetupUninstall: @pytest.fixture(autouse=True) def uninstalled(self, installer): installer.uninstall_product(PACKAGE_NAME)
- pytest_plone.fixtures.addons.uninstalled(installer: Products.CMFPlone.controlpanel.browser.quickinstaller.InstallerView, package_name: str) None#
Uninstall the add-on under test from the current portal.
Requires a
package_namefixture defined in yourconftest.pythat returns the distribution name of the add-on being tested.Example usage:
# conftest.py import pytest @pytest.fixture def package_name() -> str: return "collective.person" # tests/test_setup.py class TestSetupUninstall: @pytest.fixture(autouse=True) def uninstalled(self, uninstalled): # add-on is now uninstalled for every test in this class pass def test_product_uninstalled(self, installer, package_name): assert installer.is_product_installed(package_name) is False
- pytest_plone.fixtures.addons.browser_layers(portal: Products.CMFPlone.Portal.PloneSite) list[zope.interface.interface.InterfaceClass]#
List of browser layers registered in a portal.
Example usage:
def test_browserlayer(browser_layers): from collective.person.interfaces import IBrowserLayer assert IBrowserLayer in browser_layers
- pytest_plone.fixtures.addons.controlpanel_actions(portal: Products.CMFPlone.Portal.PloneSite) list[str]#
List of identifiers (id) of control panel actions.
Example usage:
def test_controlpanel_installed(controlpanel_actions): assert "MyControlPanel" in controlpanel_actions
- pytest_plone.fixtures.addons.setup_tool(portal: Products.CMFPlone.Portal.PloneSite) Products.GenericSetup.tool.SetupTool#
Return the portal_setup for the current portal.
Example usage:
def test_profile_version(setup_tool): name = "profile-collective.person:default" version = setup_tool.getLastVersionForProfile(name) assert version[0] == "1000"
- pytest_plone.fixtures.addons.profile_last_version(setup_tool: Products.GenericSetup.tool.SetupTool) pytest_plone._types.ProfileVersionGetter#
Provides a method to return the last version for a profile.
Example usage:
PACKAGE_NAME = "collective.person" def test_latest_version(profile_last_version): assert profile_last_version(f"{PACKAGE_NAME}:default") == "1000"
- pytest_plone.fixtures.addons.apply_profiles() pytest_plone._types.ProfilesApplier#
Apply GenericSetup profiles to a Plone site.
Example usage:
def test_with_profile(portal, apply_profiles): apply_profiles(portal, ["my.addon:testing"])
Content#
Inspect content types and create content items.
create_content is session-scoped and takes the container explicitly, so you can call it against any portal or folder.
- pytest_plone.fixtures.content.get_fti(portal: Products.CMFPlone.Portal.PloneSite) pytest_plone._types.FTIGetter#
Provides a method to get the Factory Type Information for a type by name.
Example usage:
def test_fti(get_fti): fti = get_fti("Person") assert IDexterityFTI.providedBy(fti) assert fti.title == "Person"
- pytest_plone.fixtures.content.get_behaviors(get_fti: pytest_plone._types.FTIGetter) pytest_plone._types.BehaviorsGetter#
Provides a method to get the list of behaviors for a type.
Example usage:
def test_behaviors(get_behaviors): behaviors = get_behaviors("Person") assert "plone.namefromtitle" in behaviors
- pytest_plone.fixtures.content.create_content() pytest_plone._types.ContentCreator#
Create content items in a Plone site as the site owner.
Example usage:
def test_with_content(portal, create_content): create_content(portal, [ {"type": "Document", "id": "doc1", "title": "A Document"}, ]) assert "doc1" in portal
Security#
- pytest_plone.fixtures.security.grant_roles() pytest_plone._types.RolesGranter#
Grant local roles to the test user on the portal.
Example usage:
def test_manager_action(portal, grant_roles): grant_roles(portal, ["Manager"]) # test user now has Manager role on portal
Vocabularies#
- pytest_plone.fixtures.vocabularies.get_vocabulary() pytest_plone._types.VocabularyGetter#
Provides a method to get a named vocabulary in a given context.
Example usage:
def test_vocabulary(portal, get_vocabulary): voc = get_vocabulary("plone.app.vocabularies.SupportedContentLanguages", portal) assert "en" in voc term = voc.getTerm("en") assert term.title == "English"
Distribution#
Create a Plone site from a plone.distribution distribution, the way a real deployment does.
create_site returns a callable that builds a new site in a Zope app from the distribution named by distribution_name, using the answers from answers, and sets it as the current site.
It first deletes any existing site with the same id, so each call starts from a clean state.
The distribution named by distribution_name must be registered, for example by loading the ZCML of a package that declares it with a plone:distribution directive.
The distribution_name, answers, and site_logo fixtures are meant to be overridden in your own conftest.py to point at your distribution and customize the site.
site_owner_name and site_owner_password expose the site owner credentials, so tests and fixtures can depend on them instead of importing the constants.
- pytest_plone.fixtures.distribution.create_site(distribution_name: str, site_owner_name: str) pytest_plone._types.SiteCreator#
Return a callable that creates a Plone site from a distribution.
The returned callable creates a new site in app from the distribution_name distribution, deleting any existing site with the same
site_idfirst to guarantee a clean state, and sets it as the current local site. The created site coexists with the site provided by the testing layer (a second site, by design).- Parameters:
distribution_name – distribution the site is created from.
site_owner_name – login of the site owner the site is created as.
- Returns:
a callable
func(app, answers) -> PloneSite.
- pytest_plone.fixtures.distribution.distribution_name() str#
Return the name of the distribution to create sites from.
Override this fixture on your tests to change the distribution used for creating Plone sites with the fixture
create_site.- Returns:
the distribution name.
- pytest_plone.fixtures.distribution.answers(site_logo: str) dict#
Return the default answers for creating a distribution site.
Override this fixture on your tests to change the answers for creating a Plone site from a distribution.
- Parameters:
site_logo – data-URI logo injected as the
site_logoanswer.- Returns:
a mapping of answers passed to the distribution site handler.
- pytest_plone.fixtures.distribution.site_logo() str#
Return a data-URI logo usable as the
site_logoanswer.- Returns:
an SVG image encoded as a
data:URI.
- pytest_plone.fixtures.base.site_owner_name() str#
Return the login name of the site owner (Manager) test user.
- Returns:
the
SITE_OWNER_NAMEfrom :mod:plone.app.testing.
- pytest_plone.fixtures.base.site_owner_password() str#
Return the password of the site owner (Manager) test user.
- Returns:
the
SITE_OWNER_PASSWORDfrom :mod:plone.app.testing.
Environment#
- pytest_plone.fixtures.env.generate_mo() collections.abc.Generator[None]#
Compile available .po files and generate .mo files.
This is a session fixture, as it needs to compile files just once.
generate_mo does nothing unless a test requests it.
To compile translations once for the whole suite, pull it in from an autouse session fixture in your conftest.py:
import pytest
@pytest.fixture(scope="session", autouse=True)
def session_initialization(generate_mo):
"""Force translation files to be compiled."""