Skip to content

Add module-specific assertions (Doctrine, Environment, Security, Session)#218

Draft
TavoNiievez wants to merge 1 commit into
Codeception:mainfrom
TavoNiievez:new_asserts
Draft

Add module-specific assertions (Doctrine, Environment, Security, Session)#218
TavoNiievez wants to merge 1 commit into
Codeception:mainfrom
TavoNiievez:new_asserts

Conversation

@TavoNiievez

@TavoNiievez TavoNiievez commented Aug 17, 2025

Copy link
Copy Markdown
Member

What

Adds high-level, actor-style assertions that rely on Symfony kernel/container integration and have no pure-Symfony equivalent. These belong to the see* / dontSee* family of the naming convention documented in CONTRIBUTING.md (also extended here).

Methods

  • DoctrineAssertionsTrait: seeDoctrineDatabaseIsUp, seeDoctrineSchemaIsValid, seeDoctrineProxyDirIsWritable
  • EnvironmentAssertionsTrait (new trait): seeKernelEnvironmentIs, seeDebugModeEnabled, dontSeeDebugModeEnabled, seeSymfonyVersion, seeAppEnvAndDebugMatchKernel, seeAppCacheIsWritable, seeAppLogIsWritable, seeProjectStructureIsSane, seeEnvFileIsSynchronized, seeBundleIsEnabled, seeAssetManifestExists, seeKernelCharsetIs
  • SecurityAssertionsTrait: seeFirewallIsConfigured, seeRoleInHierarchy, seeSecretCanBeResolved
  • SessionAssertionsTrait: seeSessionSavePathIsWritable

Registers EnvironmentAssertionsTrait on the Symfony module facade and documents the see* / assert* naming convention in CONTRIBUTING.md.

Tests

Unit tests added for the methods exercisable against the test app (tests/_app): Doctrine checks, the firewall check, Symfony-version/env-debug/project-dir environment checks.

The remaining checks require a full real Symfony project layout that the mini unit-test app does not provide (seeProjectStructureIsSane, seeAssetManifestExists, seeEnvFileIsSynchronized, seeSecretCanBeResolved); per the two-test-layer setup these are best covered in the companion Codeception/symfony-module-tests functional suite.

Notes

Companion to #240, which contains the Symfony-mirroring assert* / get* assertions. The two PRs touch disjoint files and can be reviewed/merged independently.

@TavoNiievez

Copy link
Copy Markdown
Member Author

Hi @ThomasLandauer @xEdelweiss ,
I'm proposing adding some new assertions to the module.

Can you take a look at the PR and give me your opinion on the new methods, please?

* $I->seeDoctrineDatabaseIsUp('custom');
* ```
*
* @param non-empty-string $connectionName The name of the Doctrine connection to check.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the name of the entity manager (in case you have multiple)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point — in Doctrine these are two separate registries. The method now resolves the argument as a connection name first and, if none matches, falls back to treating it as an entity manager name and uses that manager's connection (see resolveDoctrineConnection()). I've updated the @param to spell this out, so both forms work.

* $I->seeDoctrineProxyDirIsWritable('custom');
* ```
*/
public function seeDoctrineProxyDirIsWritable(string $entityManagerName = 'default'): void

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you aware that Doctrine is moving away from their own proxy system, in favor of the new native PHP lazy objects? So (as far as I understand it), the proxy dir soon won't be needed anymore.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — with native PHP lazy objects there's no proxy dir, so the method now markTestSkipped()s when none is configured (the docblock notes this). It stays useful for apps still on the legacy proxy system, which is common on the Symfony 5.4 / 6.4 versions this module still supports. Happy to drop it entirely once those leave the support matrix.

*
* ```php
* <?php
* $I->assertSymfonyVersion('>=', '6.4');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also work with one and three digit versions?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — it delegates to PHP's version_compare, which accepts one-, two- and three-segment versions (7, 7.4, 7.4.8). That's now stated in the docblock and covered by a unit test (testSeeSymfonyVersionAcceptsOneTwoAndThreeSegments) exercising all three forms.

* $I->seeAppEnvAndDebugMatchKernel();
* ```
*/
public function seeAppEnvAndDebugMatchKernel(): void

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. How is it possible that they don't mach?
  2. Are you only looking at real environment variables or also at resolved .env variables?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. They can diverge when the runtime env var and the booted Kernel disagree — e.g. a shell or CI job exporting APP_ENV=dev while the test Kernel boots in test. This assertion is a guard against that drift (and only checks a variable when it's actually present). I've added this rationale to the docblock.
  2. Both. Values are now resolved $_SERVER$_ENVgetenv(), so it covers real OS variables and the values Symfony's Dotenv writes from .env* files.

/**
* Helper to get the project's root directory.
*/
protected function getProjectDir(): string

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually do it like this:

$kernel = $I->grabService('kernel');
$kernel->getContainer()->getParameter('foobar');

Is this just a shortcut? I'm asking cause if there's a shortcut for this one parameter, I always ask myself: What about all the others?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — a bespoke shortcut per parameter wouldn't scale. There's a generic grabParameter('any.parameter.name') in ParameterAssertionsTrait for exactly that. getProjectDir() here is only a protected internal helper shared by the other assertions in this trait, not a public per-parameter accessor.

}

/**
* Asserts that a security firewall is configured and active.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Active" in the sense that it was actually used for the current request? Or just generally up and running?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latter — "configured", not "matched the current request". I renamed it seeFirewallIsActiveseeFirewallIsConfigured, and the docblock now states it only checks that the firewall definition (or its context service) exists, not whether it matched the request.

@ThomasLandauer

Copy link
Copy Markdown
Member

Well, these are many... :-)

  1. Do you have a clear picture when Codeception usually uses see vs. assert? Or at least clearer than me? ;-)
  2. Is there a reason why you're putting those Doctrine assertions in the Symfony and not in the Doctrine module?
  3. For some assertions I don't get the idea, since the outcome usually differs between TEST and PROD environment, e.g. seeDoctrineDatabaseIsUp(), seeDebugModeEnabled(). What's your reasoning here?

@xEdelweiss

Copy link
Copy Markdown
Contributor

Hi @TavoNiievez
Thanks for looping me in! Sadly, I'm not really working with Codeception/Symfony at the moment, so I don't think I can give this PR the proper attention it deserves.

@TavoNiievez TavoNiievez force-pushed the new_asserts branch 6 times, most recently from 42f67c0 to afb9a63 Compare April 14, 2026 19:53
@TavoNiievez

TavoNiievez commented Jun 23, 2026

Copy link
Copy Markdown
Member Author

Thanks for the thorough review, @ThomasLandauer! Answers to your three higher-level questions:

  1. see vs assert — fair point. The module is uniformly see* / dontSee* / grab*, so I aligned the two outliers I'd introduced: assertSymfonyVersionseeSymfonyVersion and assertEnvFileIsSynchronizedseeEnvFileIsSynchronized. Everything new now follows the see* convention.

  2. Doctrine assertions in the Symfony module — this module already ships a DoctrineAssertionsTrait (grabRepository, seeNumRecords, grabNumRecords, …), since Symfony + Doctrine is the default stack and there's no hard dependency forcing module-doctrine. The new assertions just extend that existing trait rather than create a new home for them.

  3. Outcome differs between TEST and PROD — these assert the expected state for whatever environment the suite targets, instead of a fixed value. That's why both polarities exist (seeDebugModeEnabled / dontSeeDebugModeEnabled): you call the one that matches the environment under test. seeDoctrineDatabaseIsUp() is a connectivity smoke-check that's meaningful in any environment where the DB is expected to be reachable.

I've pushed a commit addressing the inline comments (naming + docblock clarifications) and replied in each thread.

…ion)

High-level actor-style checks (see*/dontSee* family) that rely on Symfony
kernel/container integration and have no pure-Symfony equivalent:

- DoctrineAssertionsTrait: seeDoctrineDatabaseIsUp, seeDoctrineSchemaIsValid,
  seeDoctrineProxyDirIsWritable
- EnvironmentAssertionsTrait (new): seeKernelEnvironmentIs, seeDebugModeEnabled,
  dontSeeDebugModeEnabled, seeSymfonyVersion, seeAppEnvAndDebugMatchKernel,
  seeAppCacheIsWritable, seeAppLogIsWritable, seeProjectStructureIsSane,
  seeEnvFileIsSynchronized, seeBundleIsEnabled, seeAssetManifestExists,
  seeKernelCharsetIs
- SecurityAssertionsTrait: seeFirewallIsConfigured, seeRoleInHierarchy,
  seeSecretCanBeResolved
- SessionAssertionsTrait: seeSessionSavePathIsWritable

Registers EnvironmentAssertionsTrait on the Symfony module facade and documents
the see*/assert* naming convention in CONTRIBUTING.md. Unit tests added for the
methods exercisable against the test app; project-structure/asset/env-sync/secret
checks are covered by the external functional suite.
@TavoNiievez TavoNiievez changed the title Add new assertions Add module-specific assertions (Doctrine, Environment, Security, Session) Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants