Skip to content

Use traits for methods that belong to the public API #94

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,156 changes: 25 additions & 1,131 deletions src/Codeception/Module/Symfony.php

Large diffs are not rendered by default.

107 changes: 107 additions & 0 deletions src/Codeception/Module/Symfony/BrowserAssertionsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace Codeception\Module\Symfony;

use Codeception\Lib\Connector\Symfony as SymfonyConnector;
use Symfony\Component\HttpFoundation\Response;
use function sprintf;

trait BrowserAssertionsTrait
{
/**
* Reboot client's kernel.
* Can be used to manually reboot kernel when 'rebootable_client' => false
*
* ``` php
* <?php
*
* // Perform some requests
*
* $I->rebootClientKernel();
*
* // Perform other requests
*
* ```
*
*/
public function rebootClientKernel(): void
{
if ($this->client instanceof SymfonyConnector) {
$this->client->rebootKernel();
}
}

/**
* Goes to a page and check that it can be accessed.
*
* ```php
* <?php
* $I->seePageIsAvailable('/dashboard');
* ```
*
* @param string $url
*/
public function seePageIsAvailable(string $url): void
{
$this->amOnPage($url);
$this->seeResponseCodeIsSuccessful();
$this->seeInCurrentUrl($url);
}

/**
* Goes to a page and check that it redirects to another.
*
* ```php
* <?php
* $I->seePageRedirectsTo('/admin', '/login');
* ```
*
* @param string $page
* @param string $redirectsTo
*/
public function seePageRedirectsTo(string $page, string $redirectsTo): void
{
$this->client->followRedirects(false);
$this->amOnPage($page);
/** @var Response $response */
$response = $this->client->getResponse();
$this->assertTrue(
$response->isRedirection()
);
$this->client->followRedirect();
$this->seeInCurrentUrl($redirectsTo);
}

/**
* Submit a form specifying the form name only once.
*
* Use this function instead of $I->submitForm() to avoid repeating the form name in the field selectors.
* If you customized the names of the field selectors use $I->submitForm() for full control.
*
* ```php
* <?php
* $I->submitSymfonyForm('login_form', [
* '[email]' => '[email protected]',
* '[password]' => 'secretForest'
* ]);
* ```
*
* @param string $name
* @param string[] $fields
*/
public function submitSymfonyForm(string $name, array $fields): void
{
$selector = sprintf('form[name=%s]', $name);

$params = [];
foreach ($fields as $key => $value) {
$fixedKey = sprintf('%s%s', $name, $key);
$params[$fixedKey] = $value;
}
$button = sprintf('%s_submit', $name);

$this->submitForm($selector, $params, $button);
}
}
49 changes: 49 additions & 0 deletions src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Codeception\Module\Symfony;

use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

trait ConsoleAssertionsTrait
{
/**
* Run Symfony console command, grab response and return as string.
* Recommended to use for integration or functional testing.
*
* ``` php
* <?php
* $result = $I->runSymfonyConsoleCommand('hello:world', ['arg' => 'argValue', 'opt1' => 'optValue'], ['input']);
* ```
*
* @param string $command The console command to execute
* @param array $parameters Parameters (arguments and options) to pass to the command
* @param array $consoleInputs Console inputs (e.g. used for interactive questions)
* @param int $expectedExitCode The expected exit code of the command
*
* @return string Returns the console output of the command
*/
public function runSymfonyConsoleCommand(string $command, array $parameters = [], array $consoleInputs = [], int $expectedExitCode = 0): string
{
$kernel = $this->grabService('kernel');
$application = new Application($kernel);
$consoleCommand = $application->find($command);
$commandTester = new CommandTester($consoleCommand);
$commandTester->setInputs($consoleInputs);

$parameters = ['command' => $command] + $parameters;
$exitCode = $commandTester->execute($parameters);
$output = $commandTester->getDisplay();

$this->assertEquals(
$expectedExitCode,
$exitCode,
'Command did not exit with code '.$expectedExitCode
.' but with '.$exitCode.': '.$output
);

return $output;
}
}
129 changes: 129 additions & 0 deletions src/Codeception/Module/Symfony/DoctrineAssertionsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

declare(strict_types=1);

namespace Codeception\Module\Symfony;
use function class_exists;
use function get_class;
use function interface_exists;
use function is_object;
use function is_string;
use function is_subclass_of;
use function json_encode;
use function sprintf;

trait DoctrineAssertionsTrait
{
/**
* Retrieves number of records from database
* 'id' is the default search parameter.
*
* ```php
* <?php
* $I->grabNumRecords('User::class', ['name' => 'davert']);
* ```
*
* @param string $entityClass The entity class
* @param array $criteria Optional query criteria
* @return int
*/
public function grabNumRecords(string $entityClass, array $criteria = []): int
{
$em = $this->_getEntityManager();
$repository = $em->getRepository($entityClass);

if (empty($criteria)) {
return (int)$repository->createQueryBuilder('a')
->select('count(a.id)')
->getQuery()
->getSingleScalarResult();
}
return $repository->count($criteria);
}

/**
* Grab a Doctrine entity repository.
* Works with objects, entities, repositories, and repository interfaces.
*
* ```php
* <?php
* $I->grabRepository($user);
* $I->grabRepository(User::class);
* $I->grabRepository(UserRepository::class);
* $I->grabRepository(UserRepositoryInterface::class);
* ```
*
* @param object|string $mixed
* @return \Doctrine\ORM\EntityRepository|null
*/
public function grabRepository($mixed)
{
$entityRepoClass = '\Doctrine\ORM\EntityRepository';
$isNotARepo = function () use ($mixed): void {
$this->fail(
sprintf("'%s' is not an entity repository", $mixed)
);
};
$getRepo = function () use ($mixed, $entityRepoClass, $isNotARepo) {
if (!$repo = $this->grabService($mixed)) return null;
if (!$repo instanceof $entityRepoClass) {
$isNotARepo();
return null;
}
return $repo;
};

if (is_object($mixed)) {
$mixed = get_class($mixed);
}

if (interface_exists($mixed)) {
return $getRepo();
}

if (!is_string($mixed) || !class_exists($mixed) ) {
$isNotARepo();
return null;
}

if (is_subclass_of($mixed, $entityRepoClass)){
return $getRepo();
}

$em = $this->_getEntityManager();
if ($em->getMetadataFactory()->isTransient($mixed)) {
$isNotARepo();
return null;
}

return $em->getRepository($mixed);
}

/**
* Checks that number of given records were found in database.
* 'id' is the default search parameter.
*
* ```php
* <?php
* $I->seeNumRecords(1, User::class, ['name' => 'davert']);
* $I->seeNumRecords(80, User::class);
* ```
*
* @param int $expectedNum Expected number of records
* @param string $className A doctrine entity
* @param array $criteria Optional query criteria
*/
public function seeNumRecords(int $expectedNum, string $className, array $criteria = []): void
{
$currentNum = $this->grabNumRecords($className, $criteria);

$this->assertEquals(
$expectedNum,
$currentNum,
sprintf(
'The number of found %s (%d) does not match expected number %d with %s',
$className, $currentNum, $expectedNum, json_encode($criteria)
)
);
}
}
89 changes: 89 additions & 0 deletions src/Codeception/Module/Symfony/EventsAssertionsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace Codeception\Module\Symfony;

use Symfony\Component\HttpKernel\DataCollector\EventDataCollector;
use Symfony\Component\VarDumper\Cloner\Data;
use function get_class;
use function is_array;
use function is_object;
use function strpos;

trait EventsAssertionsTrait
{
/**
* Make sure events did not fire during the test.
*
* ``` php
* <?php
* $I->dontSeeEventTriggered('App\MyEvent');
* $I->dontSeeEventTriggered(new App\Events\MyEvent());
* $I->dontSeeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
* ```
* @param string|object|string[] $expected
*/
public function dontSeeEventTriggered($expected): void
{
/** @var EventDataCollector $eventCollector */
$eventCollector = $this->grabCollector('events', __FUNCTION__);

/** @var Data $data */
$data = $eventCollector->getNotCalledListeners();

$actual = $data->getValue(true);
$expected = is_array($expected) ? $expected : [$expected];

foreach ($expected as $expectedEvent) {
$notTriggered = false;
$expectedEvent = is_object($expectedEvent) ? get_class($expectedEvent) : $expectedEvent;

foreach ($actual as $actualEvent) {
if (strpos($actualEvent['pretty'], $expectedEvent) === 0) {
$notTriggered = true;
}
}
$this->assertTrue($notTriggered, "The '$expectedEvent' event triggered");
}
}

/**
* Make sure events fired during the test.
*
* ``` php
* <?php
* $I->seeEventTriggered('App\MyEvent');
* $I->seeEventTriggered(new App\Events\MyEvent());
* $I->seeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
* ```
* @param string|object|string[] $expected
*/
public function seeEventTriggered($expected): void
{
/** @var EventDataCollector $eventCollector */
$eventCollector = $this->grabCollector('events', __FUNCTION__);

/** @var Data $data */
$data = $eventCollector->getCalledListeners();

if ($data->count() === 0) {
$this->fail('No event was triggered');
}

$actual = $data->getValue(true);
$expected = is_array($expected) ? $expected : [$expected];

foreach ($expected as $expectedEvent) {
$triggered = false;
$expectedEvent = is_object($expectedEvent) ? get_class($expectedEvent) : $expectedEvent;

foreach ($actual as $actualEvent) {
if (strpos($actualEvent['pretty'], $expectedEvent) === 0) {
$triggered = true;
}
}
$this->assertTrue($triggered, "The '$expectedEvent' event did not trigger");
}
}
}
Loading