Files

51 lines
1.7 KiB
CMake
Raw Permalink Normal View History

v0.2.0 (13/N): qmltestrunner harness + CI wiring + close out v0.2.0 plan Closes the testing-strategy row of PLAN.md §13 v0.2.0 and parks the two remaining items with rationales. Shipped: - framework/qml/tests/{CMakeLists.txt, main.cpp, tst_smoke.qml} Qt Quick Test scaffold: QUICK_TEST_MAIN bootstrap + one smoke test proving the harness loads. New tests land as tst_<feature>.qml in the same dir; qmltestrunner auto-discovers them. Built only when -DBUILD_TESTING=ON (production AppImages stay clean). - skeleton + example/todo Makefiles: `make qmltest` target invokes the configure → build → ctest dance. `make quality` now depends on qmltest. - .gitea/workflows/ci.yml: `QML unit tests` step after qmllint in the Quality job. Out-of-tree build dir (build-tests) so the CTest run doesn't pollute the cached release build. Verified locally: configure + build + ctest pass, both smoke assertions pass, runs in 0.5s. Closed in PLAN.md §13 v0.2.0 with rationale (no code change): - Build-time Symfony cache warmup → moved to v0.3.0. The obvious approach (cache:warmup at build, copy at first launch) doesn't save any time because Symfony bakes absolute kernel.project_dir into the compiled cache, and the AppImage's FUSE mount path changes every launch — every cached path is stale on launch N+1. Doing it properly requires virtualising getProjectDir(), symlink fix-up, multi-app namespacing — its own minor's worth of design. - ReactiveObject cursor pagination → closed N/A. ReactiveObject already has pending / invoke() / Idempotency-Key correlation / version-gap detection at parity with ReactiveListModel; the only feature it lacks is *pagination*, which is meaningless for a single-entity model. That fully closes the v0.2.0 plan as documented. Remaining v0.2.0 items in PLAN.md §13 are the audit-ends already shipped earlier in the cycle (interfaces / BridgeOp / BridgeBundleInfo / Maker DRY / --with-dto / port negotiation / pre-migration backup / bridge:export / periodic auto-update / native-dialogs doc / event maker / read-model maker / qmltestrunner) plus the two parked items documented above. Ready to tag when the user gives the word. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 21:02:30 +02:00
# QML unit tests — opt-in, only built when BUILD_TESTING is on (CTest's
# convention). Wired from ../CMakeLists.txt under the same guard.
#
# Run via:
# cmake -S . -B build -DBUILD_TESTING=ON
# cmake --build build --target qml_unit_tests
# ctest --test-dir build --output-on-failure -R qml_unit_tests
#
# Or from the skeleton / example Makefiles via `make qmltest`.
qml: defer ReactiveListModel/ReactiveObject initial fetch to componentComplete() setBaseUrl() and setSource() used to fire refresh() inline as soon as both `baseUrl` and `source` were populated — but setToken() never triggered a refresh. QML evaluates literal property assignments before bindings to other objects' properties, so a model declared with literal `source` plus bindings to `BackendConnection.url` / `BackendConnection.token` (the exact shape of make:bridge:window's output) could fire its GET *before* the `token` binding had landed. The unauthenticated request hit Symfony's SessionAuthenticator, came back 401, and the model parked at `ready === false` with an empty list. Mercure subscribed anonymously (the model explicitly clears the SSE client's bearer), so subsequent server-side mutations propagated fine — masking the initial-fetch failure as "list is empty until something changes". Hit by the second window in examples/todo. Both classes now implement QQmlParserStatus and trigger the initial refresh from componentComplete(), where every binding (literal *and* singleton-derived) is guaranteed to have landed. After completion, individual setter changes still trigger refresh inline — so token rotation / URL reassignment after first load behave unchanged. Regression test under framework/qml/tests/tst_reactive_list_model.qml using the v0.2.0 qmltestrunner harness. Adds a TestHttpServer helper that mimics SessionAuthenticator's 401-on-no-bearer behaviour so the regression is observable; verified the test fails against the unfixed production code (`Actual: ""` vs `Expected: "Bearer testtoken"` on the captured Authorization header). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 19:19:56 +02:00
find_package(Qt6 6.5 REQUIRED COMPONENTS QuickTest Network)
# A tiny PhpQml.Bridge.Tests QML module that exposes the in-process
# stub HTTP server used by tst_reactive_list_model.qml. Static so it
# links into the test exe alongside the production bridge module.
qt_add_qml_module(php_qml_bridge_tests
URI PhpQml.Bridge.Tests
VERSION 1.0
STATIC
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/PhpQml/Bridge/Tests
SOURCES
TestHttpServer.h
TestHttpServer.cpp
)
target_link_libraries(php_qml_bridge_tests PUBLIC
Qt6::Core
Qt6::Network
Qt6::Qml
)
v0.2.0 (13/N): qmltestrunner harness + CI wiring + close out v0.2.0 plan Closes the testing-strategy row of PLAN.md §13 v0.2.0 and parks the two remaining items with rationales. Shipped: - framework/qml/tests/{CMakeLists.txt, main.cpp, tst_smoke.qml} Qt Quick Test scaffold: QUICK_TEST_MAIN bootstrap + one smoke test proving the harness loads. New tests land as tst_<feature>.qml in the same dir; qmltestrunner auto-discovers them. Built only when -DBUILD_TESTING=ON (production AppImages stay clean). - skeleton + example/todo Makefiles: `make qmltest` target invokes the configure → build → ctest dance. `make quality` now depends on qmltest. - .gitea/workflows/ci.yml: `QML unit tests` step after qmllint in the Quality job. Out-of-tree build dir (build-tests) so the CTest run doesn't pollute the cached release build. Verified locally: configure + build + ctest pass, both smoke assertions pass, runs in 0.5s. Closed in PLAN.md §13 v0.2.0 with rationale (no code change): - Build-time Symfony cache warmup → moved to v0.3.0. The obvious approach (cache:warmup at build, copy at first launch) doesn't save any time because Symfony bakes absolute kernel.project_dir into the compiled cache, and the AppImage's FUSE mount path changes every launch — every cached path is stale on launch N+1. Doing it properly requires virtualising getProjectDir(), symlink fix-up, multi-app namespacing — its own minor's worth of design. - ReactiveObject cursor pagination → closed N/A. ReactiveObject already has pending / invoke() / Idempotency-Key correlation / version-gap detection at parity with ReactiveListModel; the only feature it lacks is *pagination*, which is meaningless for a single-entity model. That fully closes the v0.2.0 plan as documented. Remaining v0.2.0 items in PLAN.md §13 are the audit-ends already shipped earlier in the cycle (interfaces / BridgeOp / BridgeBundleInfo / Maker DRY / --with-dto / port negotiation / pre-migration backup / bridge:export / periodic auto-update / native-dialogs doc / event maker / read-model maker / qmltestrunner) plus the two parked items documented above. Ready to tag when the user gives the word. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 21:02:30 +02:00
qt_add_executable(qml_unit_tests main.cpp)
target_link_libraries(qml_unit_tests PRIVATE
Qt6::QuickTest
Qt6::Qml
Qt6::Quick
qml: defer ReactiveListModel/ReactiveObject initial fetch to componentComplete() setBaseUrl() and setSource() used to fire refresh() inline as soon as both `baseUrl` and `source` were populated — but setToken() never triggered a refresh. QML evaluates literal property assignments before bindings to other objects' properties, so a model declared with literal `source` plus bindings to `BackendConnection.url` / `BackendConnection.token` (the exact shape of make:bridge:window's output) could fire its GET *before* the `token` binding had landed. The unauthenticated request hit Symfony's SessionAuthenticator, came back 401, and the model parked at `ready === false` with an empty list. Mercure subscribed anonymously (the model explicitly clears the SSE client's bearer), so subsequent server-side mutations propagated fine — masking the initial-fetch failure as "list is empty until something changes". Hit by the second window in examples/todo. Both classes now implement QQmlParserStatus and trigger the initial refresh from componentComplete(), where every binding (literal *and* singleton-derived) is guaranteed to have landed. After completion, individual setter changes still trigger refresh inline — so token rotation / URL reassignment after first load behave unchanged. Regression test under framework/qml/tests/tst_reactive_list_model.qml using the v0.2.0 qmltestrunner harness. Adds a TestHttpServer helper that mimics SessionAuthenticator's 401-on-no-bearer behaviour so the regression is observable; verified the test fails against the unfixed production code (`Actual: ""` vs `Expected: "Bearer testtoken"` on the captured Authorization header). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 19:19:56 +02:00
php_qml_bridge # production module — type implementations
php_qml_bridgeplugin # …and its auto-generated QQmlEngineExtensionPlugin
php_qml_bridge_tests # in-process HTTP stub
php_qml_bridge_testsplugin # …and its plugin
v0.2.0 (13/N): qmltestrunner harness + CI wiring + close out v0.2.0 plan Closes the testing-strategy row of PLAN.md §13 v0.2.0 and parks the two remaining items with rationales. Shipped: - framework/qml/tests/{CMakeLists.txt, main.cpp, tst_smoke.qml} Qt Quick Test scaffold: QUICK_TEST_MAIN bootstrap + one smoke test proving the harness loads. New tests land as tst_<feature>.qml in the same dir; qmltestrunner auto-discovers them. Built only when -DBUILD_TESTING=ON (production AppImages stay clean). - skeleton + example/todo Makefiles: `make qmltest` target invokes the configure → build → ctest dance. `make quality` now depends on qmltest. - .gitea/workflows/ci.yml: `QML unit tests` step after qmllint in the Quality job. Out-of-tree build dir (build-tests) so the CTest run doesn't pollute the cached release build. Verified locally: configure + build + ctest pass, both smoke assertions pass, runs in 0.5s. Closed in PLAN.md §13 v0.2.0 with rationale (no code change): - Build-time Symfony cache warmup → moved to v0.3.0. The obvious approach (cache:warmup at build, copy at first launch) doesn't save any time because Symfony bakes absolute kernel.project_dir into the compiled cache, and the AppImage's FUSE mount path changes every launch — every cached path is stale on launch N+1. Doing it properly requires virtualising getProjectDir(), symlink fix-up, multi-app namespacing — its own minor's worth of design. - ReactiveObject cursor pagination → closed N/A. ReactiveObject already has pending / invoke() / Idempotency-Key correlation / version-gap detection at parity with ReactiveListModel; the only feature it lacks is *pagination*, which is meaningless for a single-entity model. That fully closes the v0.2.0 plan as documented. Remaining v0.2.0 items in PLAN.md §13 are the audit-ends already shipped earlier in the cycle (interfaces / BridgeOp / BridgeBundleInfo / Maker DRY / --with-dto / port negotiation / pre-migration backup / bridge:export / periodic auto-update / native-dialogs doc / event maker / read-model maker / qmltestrunner) plus the two parked items documented above. Ready to tag when the user gives the word. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 21:02:30 +02:00
)
# QUICK_TEST_MAIN reads QUICK_TEST_SOURCE_DIR from the macro definition
# at compile time. Point it at this directory so qmltestrunner finds
# the tst_*.qml files regardless of where the binary runs.
target_compile_definitions(qml_unit_tests PRIVATE
QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
)
add_test(NAME qml_unit_tests COMMAND qml_unit_tests)