:navigation-title: Testing .. include:: /Includes.rst.txt .. _testing: ========================== Testing ========================== The extension ships an automated **cross-version test matrix**. It provisions one throwaway TYPO3 installation per supported major, wires the working tree in as a Composer path repository, and runs the test layers against each one. .. _testing-requirements: Requirements ============ * `DDEV `__ 1.24 or newer, and a running Docker daemon. * Roughly 6 GB of free disk — each lab is about 600–900 MB of :file:`vendor/` plus a database volume. * Git, because three of the labs test a different branch of this repository. * For the live checks: Node.js 18 or newer (the browser check installs ``playwright-core`` into :file:`Build/testing/browser/` on first use). .. _testing-running: Running the matrix ================== From the extension directory: .. code-block:: bash make test-matrix A cold run provisions six labs and takes roughly 30–60 minutes. Warm re-runs reuse the existing labs and take a few minutes per lab. Useful variants: .. code-block:: bash make test-matrix # all majors, offline layers only make test-matrix-live # additionally the live checks, see below make test-matrix-clean # delete all labs and worktrees make install-hooks # gate tag pushes on a green matrix Build/Scripts/runTests.sh --versions=13,14 # a subset Build/Scripts/runTests.sh --keep-labs # never delete, even when green Build/Scripts/runTests.sh --layers=unit # one layer only Build/Scripts/runTests.sh --status # what state is each lab in? The layer names are ``resolve``, ``install``, ``canary``, ``unit``, ``functional``, ``phpstan`` and ``cgl``. .. _testing-matrix: What is tested where ==================== The matrix is defined in :file:`Build/matrix.json`. Three of the six labs check out a **different branch**, because the extension is maintained as one release line per TYPO3 major — see :ref:`Version Compatibility `. .. list-table:: :header-rows: 1 :widths: 14 30 12 44 * - TYPO3 - Branch tested - PHP - Source wired into the lab * - 14.3 - ``main`` - 8.2 - the working tree * - 13.4 - ``main`` - 8.2 - the working tree * - 12.4 - ``main`` - 8.1 - the working tree * - 11.5 - ``feature-typo3-11`` - 8.1 - a :command:`git worktree` * - 10.4 - ``feature-typo3-10`` - 7.4 - a :command:`git worktree` * - 9.5 - ``feature-typo3-9`` - 7.4 - a :command:`git worktree` Coding standards are checked once per branch, in its newest lab: the older labs resolve an older ``typo3/coding-standards`` whose rules contradict the newer ones, and style is a property of the source, not of the TYPO3 version. .. _testing-layers: The test layers =============== Each lab runs these in order — cheapest and most likely to fail first: .. list-table:: :header-rows: 1 :widths: 24 76 * - Layer - What it proves * - Composer resolve - The declared constraints actually resolve against that TYPO3 major. A conflict here is a **finding**, not an error — it means the advertised compatibility is wrong. * - TYPO3 install - A real, installed TYPO3 site comes up on that major. * - Wiring canary - The lab is testing **your working tree** and not a copy fetched from Packagist. See the warning below. * - PHPUnit unit - Configuration precedence, the empty-value guard, the ``saveToSentItems`` exemption, credential validation, the sender resolution order, client/token reuse and error wrapping. On the 1.x and 2.x lines, the complete send path including retries runs against a mocked HTTP client. * - PHPUnit functional - The extension activates, and TYPO3 really selects this transport when ``MAIL.transport`` is set to the fully-qualified class name. * - PHPStan - Static analysis at level 8 against that major's core API. * - Coding standards - TYPO3 CGL via :command:`php-cs-fixer`. * - Live checks - Skipped unless explicitly enabled. See below. .. warning:: The **wiring canary** is not a formality. It writes a temporary file into the extension source on the host and checks that it appears inside the container. If the path repository is not wired correctly, Composer silently installs a release copy from Packagist instead, and every green result in that lab is meaningless. A failed canary marks the lab ``wiring`` and invalidates its results. .. note:: TYPO3 11 and 12 are **ELTS**. Every freely published patch of those majors carries security advisories, so Composer's audit would refuse to load any of them and the major could not be tested at all. The harness therefore sets ``policy.advisories.block=false`` *inside the lab*. That is safe for a throwaway installation, but it means a lab is **not** a security-current install — the report's environment header says so on every run. .. _testing-coverage-gaps: Known coverage gaps =================== .. important:: On the 3.x and 4.x lines, the call into the Microsoft Graph SDK itself is only executed by the live checks. Everything around it — configuration, sender resolution, client reuse and the error wrapping — has offline tests through the :php:`createGraphServiceClient()` seam. .. _testing-live: The live checks =============== With ``--live`` (``make test-matrix-live``), each lab additionally runs four checks against the real Microsoft Graph API. They use a lab-only fixture from :file:`Build/testing/` that is mounted into the lab and never shipped. .. list-table:: :header-rows: 1 :widths: 24 76 * - Check - What it proves * - ``live-cli`` - A real mail is accepted by Graph in **CLI context**, with the credentials in ``TYPO3_CONF_VARS``. * - ``browser`` - A headless Chromium logs into the backend, opens *System > Configuration* and finds the client secret **masked** — never in plain text. Screenshots are stored with the report. * - ``live-frontend`` - A real mail is accepted by Graph in **frontend context**, while ``TYPO3_CONF_VARS`` hold **no** credentials: they come only from ``:= getEnv(...)`` in the root template's setup and constants. This proves the documented :ref:`getEnv() configuration ` on that TYPO3 version. * - ``getenv-missing`` - A ``getEnv()`` of a variable that does not exist leaves the send failing cleanly with ``missing required field: clientSecret``. Every message has the subject ``[ex365-matrix] v ``, so a run can be traced in the mailbox. A full run sends two messages per lab. #. Create the credentials file **outside** the repository: .. code-block:: bash mkdir -p ~/.config/ok-ex365 cp Build/testing/.env.test.dist ~/.config/ok-ex365/test.env chmod 600 ~/.config/ok-ex365/test.env Fill in a test tenant. ``EXCHANGE365_TEST_RECIPIENT`` defaults to the sender address. Set ``OK_EX365_TEST_ENV`` to use a different file. #. Run the matrix with the flag: .. code-block:: bash make test-matrix-live The credentials are passed to the lab's web container through :file:`.ddev/.env.web`, so they are in the real process environment where :php:`getenv()` sees them, and that file is deleted again after the checks. No secret is written into a PHP or TypoScript file. .. note:: The live checks surfaced two network failure modes that production servers share: dead IPv6 routes to Microsoft (DNS returns IPv6 addresses the host cannot reach) and connections that stall after connecting. All transports therefore use a 10 s connect and 30 s total timeout — for the Graph call instead of the SDK's 100 s, and for the OAuth token request, which the SDK's OAuth library otherwise sends with **no timeout at all** (a stalled token request would block a scheduler run forever). A request that never connected is retried once; a request that stalled after connecting is **not** retried, because Graph may already have accepted the mail and a retry could send it twice. .. _testing-release-gate: Release gate ============ .. code-block:: bash make install-hooks enables :file:`.githooks/pre-push` for this clone and all its worktrees. Pushing a **tag** then runs the matrix for every TYPO3 major of the branch the tag is on — including the live checks when the credentials file exists — and refuses the push unless everything is green. The checkout being tested must be clean and at the tagged commit, so a green gate always means "this exact release was tested". Branch pushes are not affected. ``OK_EX365_SKIP_MATRIX=1 git push --tags`` bypasses the gate in an emergency.