Add PHPUnit test suite with 64 unit tests (v1.1.1)
Some checks failed
Create Release Package / PHP Lint (push) Successful in 1m6s
Create Release Package / PHPUnit Tests (push) Successful in 1m4s
Create Release Package / Build Release (push) Failing after 1m13s

PHPUnit 11 + Brain\Monkey for WordPress function mocking. Tests cover
BlockRenderer (28), WidgetRenderer (9), NavWalker (14), and
TemplateController (12). Includes functional WP_HTML_Tag_Processor stub,
CI test job between lint and build-release, prebuild hook gating npm
build on passing tests, and release package exclusions for test files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 00:08:34 +01:00
parent 3165e60639
commit e607382e11
18 changed files with 3234 additions and 12 deletions

View File

@@ -34,7 +34,7 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w
**Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file.
Current version is **v1.1.0**. See `PLAN.md` for details.
Current version is **v1.1.1**. See `PLAN.md` for details.
## Technical Stack
@@ -234,6 +234,57 @@ Build steps (in order):
## Session History
### Session 20 — v1.1.1 PHPUnit Test Suite (2026-02-28)
**Completed:** PHPUnit test suite with 64 unit tests and 107 assertions, CI integration, and build pipeline gating.
**What was built:**
- **PHPUnit 11 + Brain\Monkey 2.7**: Added as `require-dev` with PSR-4 `autoload-dev` mapping (`WPBootstrap\Tests\``tests/`).
- **WP_HTML_Tag_Processor stub** (`tests/Stubs/WpHtmlTagProcessor.php`): Functional DOMDocument-based replacement supporting `next_tag()` (by tag name or class_name), `add_class()` (idempotent), and `get_updated_html()`. Uses full HTML document wrapping for reliable body extraction.
- **BlockRendererTest** (28 tests): All 8 render methods — table classes, striped tables, button variants (default/bg/outline/gradient/unknown), button group flex, img-fluid, search input-group, blockquote+cite, pullquote, list-group, empty content returns.
- **WidgetRendererTest** (9 tests): Card structure, title heading, widget ID, type class extraction, generic filtering, h2→h4 regex, multiple h2 elements, empty content.
- **NavWalkerTest** (14 tests): Tree building (empty, single, flat, nested, multi-parent, orphans), node structure, classes, index reset, active detection (current-menu-item, ancestor, is_page, is_category, inactive).
- **TemplateControllerTest** (12 tests): Template resolution via ReflectionMethod for all page types (404, search, post default/full-width, page default/landing/full-width/hero/sidebar, archive, home, fallback).
- **Build pipeline**: `npm run test` and `prebuild` hook gate `npm run build` on passing tests.
- **CI workflow**: New `test` job between `lint` and `build-release` with PHP 8.3 + Composer.
- **Release exclusions**: `tests/`, `phpunit.xml.dist`, `.phpunit.cache/*` excluded from ZIP with verification step.
**Architecture decisions:**
- **Brain\Monkey over full WordPress bootstrap**: WordPress function mocking via `Functions\when()->justReturn()` and `Functions\when()->alias()` enables fast, isolated unit tests without a running WordPress installation.
- **DOMDocument stub over regex**: `WP_HTML_Tag_Processor` stub uses `DOMDocument`/`DOMXPath` for reliable HTML parsing. Full document wrapping (`<!DOCTYPE><html><body>...`) required because `LIBXML_HTML_NOIMPLIED` prevents `<body>` creation in PHP 8.4, breaking `getElementsByTagName('body')`.
- **`is_admin()=true` constructor bypass**: BlockRenderer/WidgetRenderer constructors register WordPress filters. Mocking `is_admin()` to return true causes early exit, enabling direct method testing.
- **ReflectionMethod for private methods**: `TemplateController::resolveTemplate()` is private. Testing via reflection avoids refactoring production code for testability.
- **ContextBuilder and TwigService skipped**: Too many WordPress dependencies for practical unit testing — better suited for integration tests.
**Key findings:**
- `LIBXML_HTML_NOIMPLIED` with `DOMDocument::loadHTML()` on PHP 8.4 does not create a `<body>` element, causing `getElementsByTagName('body')->item(0)` to return null. Solution: wrap input in full HTML document structure.
- Brain\Monkey's `Functions\when()->alias()` supports argument-dependent returns for functions like `is_singular()` that behave differently based on post type argument.
- `spl_object_id()` used in the stub's visited-node tracking enables sequential `next_tag()` advancement matching WordPress's forward-only API.
**Files created:**
- `phpunit.xml.dist` — PHPUnit configuration
- `tests/bootstrap.php` — Autoloader + stub loading
- `tests/Stubs/WpHtmlTagProcessor.php` — Functional DOMDocument-based stub
- `tests/Stubs/WpBlock.php` — Empty class stub
- `tests/Stubs/WpWidget.php` — Empty class stub
- `tests/Unit/Block/BlockRendererTest.php` — 28 tests
- `tests/Unit/Block/WidgetRendererTest.php` — 9 tests
- `tests/Unit/Template/NavWalkerTest.php` — 14 tests
- `tests/Unit/Template/TemplateControllerTest.php` — 12 tests
**Files modified:**
- `composer.json``require-dev`, `autoload-dev`
- `package.json``test`, `prebuild` scripts
- `.gitea/workflows/release.yml` — test job, exclusions, verification
- `.gitignore``.phpunit.cache/`
- `style.css` — version bump to 1.1.1
- `CHANGELOG.md`, `README.md`, `CLAUDE.md` — documentation
### Session 19 — v1.1.0 Block Renderer, Widget Renderer & Sidebar Post Layout (2026-02-28)
**Completed:** Bootstrap 5 class injection for core blocks, sidebar widget card wrappers, widget SCSS styling, and sidebar-default post template.