Skip to content

Commit b2dd3a4

Browse files
committed
TASK: Smaller footprint
1 parent 4a112fa commit b2dd3a4

53 files changed

Lines changed: 405 additions & 671 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
.git/
22
.idea/
33
node_modules/
4+
vendor/
5+
Packages
6+
.github
7+
.claude
8+
.idea
9+
composer.lock

.github/workflows/e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
run: npx playwright install --with-deps chromium
3434

3535
- name: Pre-build Docker image
36-
run: docker compose -f Tests/sytem_under_test/${{ matrix.neos }}/docker-compose.yaml build --pull
36+
run: docker compose -f Tests/system_under_test/${{ matrix.neos }}/docker-compose.yaml build --pull
3737

3838
- name: Test - defaults
3939
working-directory: Tests/E2E

Concept_Composer_Package.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Concept: Reusable E2E Infrastructure as a Composer Package
2+
3+
## Goal
4+
5+
Extract the E2E test infrastructure from this plugin into a standalone Composer package
6+
(`sandstorm/neos-e2e-testing`) that any Neos plugin can install to get a working
7+
end-to-end test scaffold with minimal effort.
8+
9+
**Scope:** Infrastructure only — Docker/SUT setup, Playwright project scaffold (config,
10+
package.json, tsconfig, teardown), Makefile, and GitHub Actions workflow. Step definitions,
11+
helpers (system, pages, totp, etc.), and feature files are entirely the plugin developer's
12+
responsibility.
13+
14+
---
15+
16+
## Package Structure
17+
18+
### Type: `library`
19+
20+
Not `neos-package` — this is a dev tool. It belongs in `vendor/`, not `Packages/`, and
21+
has no Flow/Neos runtime dependency.
22+
23+
```
24+
sandstorm/neos-e2e-testing/
25+
├── composer.json
26+
├── bin/
27+
│ └── neos-e2e-setup ← self-contained PHP CLI script
28+
└── templates/
29+
├── Tests/
30+
│ ├── E2E/
31+
│ │ ├── package.json
32+
│ │ ├── playwright.config.ts
33+
│ │ ├── tsconfig.json
34+
│ │ ├── global-teardown.ts
35+
│ │ └── .nvmrc
36+
│ └── system_under_test/
37+
│ ├── neos8/
38+
│ │ ├── Dockerfile
39+
│ │ ├── docker-compose.yaml
40+
│ │ └── sut-files/
41+
│ │ ├── entrypoint.sh
42+
│ │ ├── etc/caretakerd.yaml
43+
│ │ ├── etc/frankenphp/Caddyfile
44+
│ │ └── usr/local/etc/php/conf.d/php-ini-overrides.ini
45+
│ └── neos9/
46+
│ └── (same)
47+
├── .dockerignore
48+
├── Makefile
49+
└── .github/
50+
└── workflows/
51+
└── e2e.yml
52+
```
53+
54+
### `composer.json`
55+
56+
```json
57+
{
58+
"name": "sandstorm/neos-e2e-testing",
59+
"type": "library",
60+
"description": "Scaffolds E2E test infrastructure for Neos plugins",
61+
"require": { "php": "^8.1" },
62+
"bin": ["bin/neos-e2e-setup"]
63+
}
64+
```
65+
66+
---
67+
68+
## Usage
69+
70+
```sh
71+
composer require --dev sandstorm/neos-e2e-testing
72+
vendor/bin/neos-e2e-setup --plugin-package sandstorm/neostwofactorauthentication
73+
```
74+
75+
The script copies templates into the plugin root, substitutes tokens, and skips files that
76+
already exist (safe to re-run).
77+
78+
---
79+
80+
## Template Tokens
81+
82+
Only two things vary between plugins:
83+
84+
| Token | Example | Used in |
85+
|---|---|---|
86+
| `{{PLUGIN_PACKAGE}}` | `sandstorm/neostwofactorauthentication` | Dockerfile, docker-compose project name, Makefile, GH Actions |
87+
| `{{PLUGIN_SLUG}}` | `sandstorm-2fa` | Docker container/volume names |
88+
89+
The slug is derived automatically from the package name (everything after `/`, hyphens
90+
preserved), so the developer only needs to provide `--plugin-package`.
91+
92+
---
93+
94+
## The Dockerfile Template
95+
96+
The only plugin-specific lines in the Dockerfile are the `composer require` call. These
97+
are made generic via a build arg:
98+
99+
```dockerfile
100+
ARG PLUGIN_PACKAGE={{PLUGIN_PACKAGE}}
101+
102+
COPY . /tmp/plugin/
103+
RUN --mount=type=cache,target=/root/.composer \
104+
composer config repositories.plugin \
105+
'{"type":"path","url":"/tmp/plugin","options":{"symlink":false}}' \
106+
&& composer require ${PLUGIN_PACKAGE}:@dev
107+
```
108+
109+
Everything else (PHP extensions, caretakerd, FrankenPHP, Neos base distribution, config
110+
copy) is already generic across plugins.
111+
112+
---
113+
114+
## `.dockerignore` (generated at plugin root)
115+
116+
Without this, `COPY . /tmp/plugin/` in the Dockerfile would include the test
117+
infrastructure itself inside the image:
118+
119+
```
120+
Tests/E2E/node_modules
121+
Tests/E2E/.playwright
122+
Tests/system_under_test
123+
```
124+
125+
---
126+
127+
## The `bin/neos-e2e-setup` Script
128+
129+
A self-contained PHP script — no autoloading, no framework. It:
130+
131+
1. Parses `--plugin-package` from `$argv`
132+
2. Derives `{{PLUGIN_SLUG}}` from the package name
133+
3. Iterates over `templates/` recursively
134+
4. For each template file: substitutes tokens, copies to the target path
135+
5. Skips files that already exist (idempotent)
136+
137+
---
138+
139+
## What the Developer Adds After Scaffolding
140+
141+
The scaffolded layout has intentional empty directories (with `.gitkeep`) for the
142+
plugin-specific content:
143+
144+
```
145+
Tests/E2E/features/
146+
← write .feature files here
147+
148+
Tests/E2E/steps/
149+
← write step definitions here
150+
151+
Tests/system_under_test/neos8/sut-files/app/Configuration/Production/E2E-SUT/
152+
Tests/system_under_test/neos9/sut-files/app/Configuration/Production/E2E-SUT/
153+
← plugin-specific Settings.yaml, Policy.yaml, context subdirectories, etc.
154+
```
155+
156+
The scaffold writes the base `Configuration/Production/E2E-SUT/Settings.yaml` (DB + Redis
157+
connection) and `Caches.yaml`. The plugin only adds its own configuration on top.
158+
159+
---
160+
161+
## Open Question: Container Name Convention
162+
163+
The `SUT` environment variable (used in step definitions as `${SUT}-neos-1` to target
164+
`docker exec`) is a contract between the scaffolded `docker-compose.yaml` and the
165+
developer's step helpers. Since step helpers are entirely the plugin developer's business,
166+
this convention needs to be documented somewhere visible — either in a generated `README`
167+
in `Tests/E2E/`, or as a comment in the scaffolded `playwright.config.ts`.
168+
169+
A decision is needed on where this contract lives before the package is built.

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
NEOS8_COMPOSE = $(CURDIR)/Tests/sytem_under_test/neos8/docker-compose.yaml
2-
NEOS9_COMPOSE = $(CURDIR)/Tests/sytem_under_test/neos9/docker-compose.yaml
1+
NEOS8_COMPOSE = $(CURDIR)/Tests/system_under_test/neos8/docker-compose.yaml
2+
NEOS9_COMPOSE = $(CURDIR)/Tests/system_under_test/neos9/docker-compose.yaml
33
E2E_DIR = $(CURDIR)/Tests/E2E
44

55
.SILENT:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ If you just want to see the test running in the browser just `npm run test:neos8
228228

229229
#### System under test (SUT)
230230

231-
There are two docker compose environments in `Tests/sytem_under_test/`:
231+
There are two docker compose environments in `Tests/system_under_test/`:
232232

233233
- `neos8/` — Neos with PHP 8.2
234234
- `neos9/` — Neos with PHP 8.5

Tests/E2E/.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v24.14.0
1+
v24.14.1

Tests/E2E/global-teardown.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { dirname } from 'node:path';
44
export default async function globalTeardown() {
55
const sut = process.env.SUT || 'neos8';
66
execSync(
7-
`docker compose -f ../sytem_under_test/${sut}/docker-compose.yaml down -v`,
7+
`docker compose -f ../system_under_test/${sut}/docker-compose.yaml down -v`,
88
{ stdio: 'inherit', cwd: dirname('.') }
99
);
1010
}
Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
11
import type { Page } from '@playwright/test';
22
import { generateOtp } from './totp.js';
33

4-
export class NeosLoginPage {
5-
constructor(private readonly page: Page) {}
6-
7-
async goto() {
8-
await this.page.goto('/neos/login');
9-
}
10-
11-
async login(username: string, password: string) {
12-
await this.page.locator('input[type="text"]').fill(username);
13-
await this.page.locator('input[type="password"]').fill(password);
14-
await this.page.locator('.neos-login-btn:not(.neos-disabled):not(.neos-hidden)').click();
15-
}
16-
}
17-
184
export class SecondFactorLoginPage {
195
constructor(private readonly page: Page) {}
206

Tests/E2E/helpers/general-pages.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { Page } from '@playwright/test';
2+
3+
export class NeosLoginPage {
4+
constructor(private readonly page: Page) {}
5+
6+
async goto() {
7+
await this.page.goto('/neos/login');
8+
}
9+
10+
async login(username: string, password: string) {
11+
await this.page.locator('input[type="text"]').fill(username);
12+
await this.page.locator('input[type="password"]').fill(password);
13+
await this.page.locator('.neos-login-btn:not(.neos-disabled):not(.neos-hidden)').click();
14+
}
15+
}
16+
17+
export class NeosContentPage {
18+
public readonly URL_REGEX = /neos\/content/;
19+
20+
constructor(private readonly page: Page) {}
21+
22+
async goto() {
23+
await this.page.goto('/neos/content');
24+
}
25+
}

Tests/E2E/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
"private": true,
44
"type": "module",
55
"scripts": {
6-
"generate-tests": "npx bddgen",
6+
"generate-tests": "SUT=notRelevantForBddgen FLOW_CONTEXT=notRelevantForBddgen npx bddgen",
77

8-
"test:neos8:defaults": "npm run generate-tests && SUT=neos8 npx playwright test --grep @default-context",
8+
"test:neos8:defaults": "npm run generate-tests && SUT=neos8 FLOW_CONTEXT=Production/E2E-SUT npx playwright test --grep @default-context",
99
"test:neos8:enforce-all": "npm run generate-tests && SUT=neos8 FLOW_CONTEXT=Production/E2E-SUT/EnforceForAll npx playwright test --grep @enforce-for-all",
1010
"test:neos8:enforce-role": "npm run generate-tests && SUT=neos8 FLOW_CONTEXT=Production/E2E-SUT/EnforceForRole npx playwright test --grep @enforce-for-role",
1111
"test:neos8:enforce-provider": "npm run generate-tests && SUT=neos8 FLOW_CONTEXT=Production/E2E-SUT/EnforceForProvider npx playwright test --grep @enforce-for-provider",
1212
"test:neos8:issuer-name": "npm run generate-tests && SUT=neos8 FLOW_CONTEXT=Production/E2E-SUT/IssuerNameChange npx playwright test --grep @issuer-name-change",
1313

14-
"test:neos9:defaults": "npm run generate-tests && SUT=neos9 npx playwright test --grep @default-context",
14+
"test:neos9:defaults": "npm run generate-tests && SUT=neos9 FLOW_CONTEXT=Production/E2E-SUT npx playwright test --grep @default-context",
1515
"test:neos9:enforce-all": "npm run generate-tests && SUT=neos9 FLOW_CONTEXT=Production/E2E-SUT/EnforceForAll npx playwright test --grep @enforce-for-all",
1616
"test:neos9:enforce-role": "npm run generate-tests && SUT=neos9 FLOW_CONTEXT=Production/E2E-SUT/EnforceForRole npx playwright test --grep @enforce-for-role",
1717
"test:neos9:enforce-provider": "npm run generate-tests && SUT=neos9 FLOW_CONTEXT=Production/E2E-SUT/EnforceForProvider npx playwright test --grep @enforce-for-provider",

0 commit comments

Comments
 (0)