Skip to content

Commit 71c686d

Browse files
authored
Add @pytest.mark.portal marker support (#37) (#42)
* Add @pytest.mark.portal marker and supporting fixtures (#37) Introduce a portal marker that lets tests declare GenericSetup profiles, content, and roles inline — without overriding the portal fixture. New session-scoped fixtures: apply_profiles, create_content, grant_roles. Also: bump Plone to 6.1.4, add plone-stubs to test deps, update mx.ini. * Update VS Code settings for plone-stubs and ruff * Fix CI: bump GH Actions, replace manual cache, fix venv conflict - actions/checkout v4 → v6, astral-sh/setup-uv v5 → v8.0.0 - Use setup-uv built-in caching instead of actions/cache - Skip venv creation in Makefile when .venv already exists (setup-uv) - Run mypy via uvx to avoid full install in lint job - Add fail-fast: false to test matrix - Fix cookiecutter template variable left in Makefile * Restrict plone-stubs to Python >= 3.12 * Fix plone-stubs install: use git URL with Python >= 3.12 marker plone-stubs is not published on PyPI, so reference it directly from GitHub. Remove it from mx.ini (no marker support) and use a PEP 508 direct reference in pyproject.toml instead.
1 parent 988d255 commit 71c686d

24 files changed

Lines changed: 471 additions & 44 deletions

.github/workflows/changelog.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ jobs:
1313
name: "Check for change log entries"
1414
runs-on: ubuntu-latest
1515
steps:
16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v6
1717
with:
1818
# Fetch all history
1919
fetch-depth: '0'
2020

2121
- name: Install the latest version of uv
22-
uses: astral-sh/setup-uv@v5
22+
uses: astral-sh/setup-uv@v8.0.0
2323
with:
2424
python-version: ${{ env.python-version }}
2525

.github/workflows/ci.yml

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55

66
env:
77
PYTHON_VERSION: "3.12"
8-
PLONE_VERSION: "6.1.1"
8+
PLONE_VERSION: "6.1.4"
99

1010
jobs:
1111

@@ -14,10 +14,10 @@ jobs:
1414
steps:
1515

1616
- name: Checkout
17-
uses: actions/checkout@v4
17+
uses: actions/checkout@v6
1818

1919
- name: Install the latest version of uv
20-
uses: astral-sh/setup-uv@v5
20+
uses: astral-sh/setup-uv@v8.0.0
2121
with:
2222
python-version: ${{ env.PYTHON_VERSION }}
2323
enable-cache: true
@@ -51,8 +51,7 @@ jobs:
5151
if: ${{ success() || failure() }}
5252
id: typing
5353
run: |
54-
make install
55-
uv run mypy src
54+
uvx mypy src
5655
5756
- name: Report
5857
if: ${{ success() || failure() }}
@@ -70,6 +69,7 @@ jobs:
7069
test:
7170
runs-on: ubuntu-latest
7271
strategy:
72+
fail-fast: false
7373
matrix:
7474
python-version: ['3.10', '3.11', '3.12', '3.13']
7575
plone-version: ['6.1-latest', '6.0-latest']
@@ -79,22 +79,17 @@ jobs:
7979
steps:
8080

8181
- name: Checkout
82-
uses: actions/checkout@v4
82+
uses: actions/checkout@v6
8383

8484
- name: Install the latest version of uv
85-
uses: astral-sh/setup-uv@v5
85+
uses: astral-sh/setup-uv@v8.0.0
8686
with:
8787
python-version: ${{ env.PYTHON_VERSION }}
88-
enable-cache: false
89-
90-
- name: Restore uv cache
91-
uses: actions/cache@v4
92-
with:
93-
path: ${{ env.UV_CACHE_DIR }}
94-
key: uv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.PLONE_VERSION }}-${{ hashFiles('pyproject.toml') }}
95-
restore-keys: |
96-
uv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.PLONE_VERSION }}-${{ hashFiles('pyproject.toml') }}
97-
uv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.PLONE_VERSION }}
88+
cache-suffix: ${{ env.PLONE_VERSION }}-${{ env.PYTHON_VERSION }}
89+
enable-cache: true
90+
cache-dependency-glob: |
91+
pyproject.toml
92+
mx.ini
9893
9994
- name: Install Plone and package
10095
run: make install
@@ -108,22 +103,17 @@ jobs:
108103
- test
109104
steps:
110105
- name: Checkout
111-
uses: actions/checkout@v4
106+
uses: actions/checkout@v6
112107

113108
- name: Install the latest version of uv
114-
uses: astral-sh/setup-uv@v5
109+
uses: astral-sh/setup-uv@v8.0.0
115110
with:
116111
python-version: ${{ env.PYTHON_VERSION }}
117-
enable-cache: false
118-
119-
- name: Restore uv cache
120-
uses: actions/cache@v4
121-
with:
122-
path: /tmp/.uv-cache
123-
key: uv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.PLONE_VERSION }}-${{ hashFiles('pyproject.toml') }}
124-
restore-keys: |
125-
uv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.PLONE_VERSION }}-${{ hashFiles('pyproject.toml') }}
126-
uv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.PLONE_VERSION }}
112+
cache-suffix: ${{ env.PLONE_VERSION }}-${{ env.PYTHON_VERSION }}
113+
enable-cache: true
114+
cache-dependency-glob: |
115+
pyproject.toml
116+
mx.ini
127117
128118
- name: Install Plone and package
129119
run: make install

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@ var/
4343
constraints*.txt
4444
requirements*.txt
4545
.coverage*
46+
.*_cache/
47+
48+
# Local Claude context (not for sharing)
49+
.claude/*.local.*

.vscode/settings.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
{
2-
"flake8.args": ["--config=pyproject.toml"],
32
"ruff.organizeImports": true,
43
"python.terminal.activateEnvironment": true,
54
"python.testing.pytestArgs": [
65
"tests"
76
],
87
"python.testing.unittestEnabled": false,
98
"python.testing.pytestEnabled": true,
9+
"python.analysis.extraPaths": [
10+
"sources/plone-stubs/src"
11+
],
1012
"[markdown]": {
1113
"editor.formatOnSave": false
12-
}
14+
}
1315
}

Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,17 @@ BACKEND_FOLDER=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
2828
ifdef PLONE_VERSION
2929
PLONE_VERSION := $(PLONE_VERSION)
3030
else
31-
PLONE_VERSION := 6.1.1
31+
PLONE_VERSION := 6.1.4
32+
endif
33+
34+
ifdef CI
35+
UV_VENV_ARGS :=
36+
else
37+
UV_VENV_ARGS := --python=3.12
3238
endif
3339

3440
VENV_FOLDER=$(BACKEND_FOLDER)/.venv
41+
export VIRTUAL_ENV=$(VENV_FOLDER)
3542
BIN_FOLDER=$(VENV_FOLDER)/bin
3643

3744
# Environment variables to be exported
@@ -67,7 +74,7 @@ requirements-mxdev.txt: ## Generate constraints file
6774

6875
$(VENV_FOLDER): requirements-mxdev.txt ## Install dependencies
6976
@echo "$(GREEN)==> Install environment$(RESET)"
70-
@uv venv $(VENV_FOLDER)
77+
@if [[ -d "$(VENV_FOLDER)" ]]; then echo "$(YELLOW)==> Environment already exists at $(VENV_FOLDER)$(RESET)"; else uv venv $(UV_VENV_ARGS) $(VENV_FOLDER); fi
7178
@uv pip install -r requirements-mxdev.txt
7279

7380
.PHONY: sync

README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,83 @@ def test_last_version(profile_last_version):
316316
assert version == "1000"
317317

318318
```
319+
320+
### apply_profiles
321+
322+
| | |
323+
| --- | --- |
324+
| Description | Function to apply GenericSetup profiles to a Plone site. |
325+
| Required Fixture | **integration** |
326+
| Scope | **Session** |
327+
328+
```python
329+
def test_with_profile(portal, apply_profiles):
330+
"""Test that a profile can be applied."""
331+
apply_profiles(portal, ["my.addon:testing"])
332+
```
333+
334+
### create_content
335+
336+
| | |
337+
| --- | --- |
338+
| Description | Function to create content items in a Plone site as the site owner. |
339+
| Required Fixture | **integration** |
340+
| Scope | **Session** |
341+
342+
```python
343+
def test_with_content(portal, create_content):
344+
"""Test that content is created."""
345+
create_content(portal, [
346+
{"type": "Document", "id": "doc1", "title": "A Document"},
347+
])
348+
assert "doc1" in portal
349+
```
350+
351+
### grant_roles
352+
353+
| | |
354+
| --- | --- |
355+
| Description | Function to grant local roles to the test user on a given context. |
356+
| Required Fixture | **integration** |
357+
| Scope | **Session** |
358+
359+
```python
360+
def test_manager_action(portal, grant_roles):
361+
"""Test an action that requires Manager role."""
362+
grant_roles(portal, ["Manager"])
363+
# test user now has Manager role on portal
364+
```
365+
366+
## Markers
367+
368+
### @pytest.mark.portal
369+
370+
Configure the `portal` fixture with GenericSetup profiles, pre-created content, and/or user roles — without overriding the fixture.
371+
372+
| Parameter | Type | Description |
373+
| --- | --- | --- |
374+
| `profiles` | `list[str]` | GenericSetup profile IDs to apply (e.g. `["my.addon:testing"]`) |
375+
| `content` | `list[dict]` | Dicts passed as keyword arguments to `plone.api.content.create` |
376+
| `roles` | `list[str]` | Roles granted to the test user via `plone.api.user.grant_roles` |
377+
378+
Setup is applied in order: **profiles → content → roles**.
379+
380+
```python
381+
import pytest
382+
383+
384+
@pytest.mark.portal(
385+
profiles=["my.addon:testing"],
386+
content=[{"type": "Document", "id": "doc1", "title": "Doc 1"}],
387+
roles=["Manager"],
388+
)
389+
def test_something(portal):
390+
"""Test with custom portal setup."""
391+
assert "doc1" in portal
392+
```
393+
394+
Tests without the marker see no behavior change — fully backwards-compatible.
395+
319396
## Plugin Development
320397

321398
You need a working `python` environment (system, virtualenv, pyenv, etc) version 3.8 or superior.

mx.ini

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,3 @@ version-overrides =
1111
pytest-plone>=1.0.0a1
1212
zope.pytestlayer>=8.3
1313
pytest>=8.4.0
14-
15-
; example section to use packages from git
16-
; [example.contenttype]
17-
; url = https://github.com/collective/example.contenttype.git
18-
; pushurl = git@github.com:collective/example.contenttype.git
19-
; extras = test
20-
; branch = feature-7

news/+apply_profiles.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `apply_profiles` session-scoped fixture to apply GenericSetup profiles to a Plone site. @ericof

news/+ci.internal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Updated CI workflows: bumped actions/checkout to v6 and astral-sh/setup-uv to v8.0.0, replaced manual cache with setup-uv built-in caching, fixed Makefile venv creation conflict with setup-uv, and added fail-fast: false to test matrix. @ericof

news/+create_content.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `create_content` session-scoped fixture to create content items in a Plone site as the site owner. @ericof

0 commit comments

Comments
 (0)