Commit 8466f078 authored by rlgy's avatar rlgy

composer update

parent 5e781b09
#### 2.4.2
* Added support for `extends` in the `codeception.yml` and `*.suite.yml` files; by @johannesschobel.
Allows to inherit current config from a provided file. See example for `functional.suite.yml`:
```yml
actor: FunctionalTester
extends: shared.functional.suite.yml
modules:
enabled:
- \App\Modules\X\Tests\Helper\Functional
```
* [Yii2] Restore null check for client in Yii2 by @wkritzinger. See #4940
* [Yii2] Resetting Yii application in `_after`. By @SamMousa. See #4928
* [Yii2] **Breaking** `$settings['configFile']` now supports absolute paths. In you have defined relative path to config in absolute manner
* [WebDriverIO] Added `deleteSessionSnapshot` by @vi4o
* [Symfony] Added support for custom kernel names with `kernel_class` config option. By @omnilight.
* [Asserts] Better exception message for `expectException` by @Slamdunk
* [REST] Decode all non-arrays to array. See #4946 by @Amunak, fixes #4944.
* [ZF2] Fixed compatibility with ZF2 ServiceManager by @omnilight.
* [Laravel5] Fixed memory leak when using Laravel factories inside Codeception. See #4971 by @AdrianSkierniewski
* [Db] Added support for `null` values in MSSQL driver by @philek
* Handle absolute paths in ParamsLoader by @SilverFire
* Fix error on single file test. See #4986 by @mikbox74
* Upgraded to Codeception/Stub 2.0 by @Naktibalda, fixed compatibility.
#### 2.4.1
* Fixed "Uncaught Error: Call to undefined method Codeception\Test\Descriptor::getTestDataSetIndex()" error when filtering tests.
* Better support of PHPUnit warning status by @edno:
* support PHPUnit addWarning()
* display 'W' instead of success for warning test cases
* Fixed Running test with invalid dataprovider by @okneloper. Fixed #4888 by @edno
* [Yii2] **Request flow and database transactions refactored** (by @sammousa):
* **Breaking** Application is no longer available in helpers via `$this->getModule('Yii2'')->app`, now you must use `\Yii::$app` everywhere
* Multiple databases are now supported
* More reliable application state before and during test execution
* Fixtures method is now configurable
* Subset of misconfigurations are now detected and informative messages created
* Fixed using `$settings['path']` in `Codeception\Configuration::suiteSettings()` on Windows by @olegpro
(starting with `/`), you must change it. @silverfire
* [Laravel5] Added Laravel 5.4+ (5.1+ backward compatible) support for `callArtisan` method in Laravel5 module. See #4860 by @mohamed-aiman
* Fixed #4854: unnecessary escaping in operation arguments logging by @nicholascus
* Fixed humanizing steps for utf8 strings by @nicholascus. See #4850
* Fixed parsing relative urls in `parse_url`. See #4853 by @quantum-x
#### 2.4.0
* **PHPUnit 7.x compatibility**
* **Dropped PHP 5.4 and PHP 5.5** support (PHP 5.5 still may work)
* Internal API refactored:
* Modern PHP class names used internally
* Moved PHPUnit related classes to [codeception/phpunit-wrapper](https://github.com/Codeception/phpunit-wrapper) package.
* Removed `shims` for underscore PHPUnit classes > namespaced PHP classes
* Cest hooks behavior changed (by @fffilimonov):
* `_failed` called when test fails
* `_passed` called when tests is successful
* `_after` is called for failing and successful tests
**Upgrade Notice**: If you face issues with underscore PHPUnit class names (like PHPUnit_Framework_Assert) you have two options:
* Lock version for PHPUnit in composer.json: "phpunit/phpunit":"^5.0.0"
* Update your codebase and replace underscore PHPUnit class names to namespaced (PHPUnit 6+ API)
<?php
/**
* This file allows for tests to be skipped.
* For now conditions are simple.
* We check if changes in the source with respect to the configured branch are limited to framework files,
* if that is the case and the current framework isn't one with changed files then we skip it.
*/
$branch ="2.4";
function stderr($message)
{
fwrite(STDERR, $message . "\n");
}
$currentFramework = getenv('FRAMEWORK');
if ($currentFramework === 'Codeception') {
stderr('Codeception tests are always executed');
die();
}
$files = [];
exec("git diff --name-only $branch", $files);
// Regexes for frameworks:
$regexes = [
'Yii2' => '/.*Yii2.*/',
'Lumen' => '/.*(Lumen|LaravelCommon).*/',
'Laravel' => '/.*Laravel.*/',
'Phalcon' => '/.*Phalcon.*/',
'Symfony' => '/.*Symfony.*/',
'Yii1' => '/.*Yii1.*/',
'ZendExpressive' => '/.*ZendExpressive.*/',
'Zend1' => '/.*ZF1.*/',
'Zend2' => '/.*ZF2.*/',
];
// First check if changes include files that are not framework files.
$frameworkOnly = true;
$frameworks = [];
foreach ($files as $file) {
$match = false;
foreach ($regexes as $framework => $regex) {
if (preg_match($regex, $file)) {
$match = true;
$frameworks[$framework] = $framework;
break;
}
}
if (!$match) {
$frameworkOnly = false;
break;
}
}
if ($frameworkOnly) {
stderr('Changes limited to frameworks: ' . implode(', ', $frameworks));
if (!isset($frameworks[$currentFramework])) {
stderr("Skipping test for framework: $currentFramework");
echo "export FRAMEWORK=\n";
echo "export PECL=\n";
echo "export FXP=\n";
echo "export CI_USER_TOKEN=\n";
}
}
# Mocks
Declare mocks inside `Codeception\Test\Unit` class.
If you want to use mocks outside it, check the reference for [Codeception/Stub](https://github.com/Codeception/Stub) library.
#### *public* make($class, $params = null)
Instantiates a class without executing a constructor.
Properties and methods can be set as a second parameter.
Even protected and private properties can be set.
``` php
<?php
$this->make('User');
$this->make('User', ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
$this->make(new User, ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
$this->make('User', ['save' => function () { return true; }]);
$this->make('User', ['save' => true]);
```
* `param mixed` $class - A class to be mocked
* `param array` $params - properties and methods to set
@return object - mock
@throws \RuntimeException when class does not exist
@throws \Exception
#### *public* makeEmpty($class, $params = null)
Instantiates class having all methods replaced with dummies.
Constructor is not triggered.
Properties and methods can be set as a second parameter.
Even protected and private properties can be set.
``` php
<?php
$this->makeEmpty('User');
$this->makeEmpty('User', ['name' => 'davert']);
```
Accepts either name of class or object of that class
``` php
<?php
$this->makeEmpty(new User, ['name' => 'davert']);
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
$this->makeEmpty('User', ['save' => function () { return true; }]);
$this->makeEmpty('User', ['save' => true));
```
* `param mixed` $class
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
@return object
@throws \Exception
#### *public* makeEmptyExcept($class, $method, $params = null)
Instantiates class having all methods replaced with dummies except one.
Constructor is not triggered.
Properties and methods can be replaced.
Even protected and private properties can be set.
``` php
<?php
$this->makeEmptyExcept('User', 'save');
$this->makeEmptyExcept('User', 'save', ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
* $this->makeEmptyExcept(new User, 'save');
?>
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
$this->makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
$this->makeEmptyExcept('User', 'save', ['isValid' => true]);
```
* `param mixed` $class
* `param string` $method
* `param array` $params
@return object
@throws \Exception
#### *public* construct($class, $constructorParams = null, $params = null)
Instantiates a class instance by running constructor.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
$this->construct('User', ['autosave' => false]);
$this->construct('User', ['autosave' => false], ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
$this->construct(new User, ['autosave' => false), ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
$this->construct('User', [], ['save' => function () { return true; }]);
$this->construct('User', [], ['save' => true]);
?>
```
* `param mixed` $class
* `param array` $constructorParams
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
@return object
@throws \Exception
#### *public* constructEmpty($class, $constructorParams = null, $params = null)
Instantiates a class instance by running constructor with all methods replaced with dummies.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
$this->constructEmpty('User', ['autosave' => false]);
$this->constructEmpty('User', ['autosave' => false), ['name' => 'davert']);
```
Accepts either name of class or object of that class
``` php
<?php
$this->constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
$this->constructEmpty('User', array(), array('save' => function () { return true; }));
$this->constructEmpty('User', array(), array('save' => true));
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
$this->constructEmpty('User', [], [
'save' => \Codeception\Stub\Expected::once()
]);
```
* `param mixed` $class
* `param array` $constructorParams
* `param array` $params
@return object
#### *public* constructEmptyExcept($class, $method, $constructorParams = null, $params = null)
Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
$this->constructEmptyExcept('User', 'save');
$this->constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
$this->constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
$this->constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
$this->constructEmptyExcept('User', 'save', [], ['save' => true]);
?>
```
* `param mixed` $class
* `param string` $method
* `param array` $constructorParams
* `param array` $params
@return object
#### *public static* never($params = null)
Checks if a method never has been invoked
If method invoked, it will immediately throw an
exception.
```php
<?php
use \Codeception\Stub\Expected;
$user = $this->make('User', [
'getName' => Expected::never(),
'someMethod' => function() {}
]);
$user->someMethod();
?>
```
* `param mixed` $params
@return StubMarshaler
#### *public static* once($params = null)
Checks if a method has been invoked exactly one
time.
If the number is less or greater it will later be checked in verify() and also throw an
exception.
```php
<?php
use \Codeception\Stub\Expected;
$user = $this->make(
'User',
array(
'getName' => Expected::once('Davert'),
'someMethod' => function() {}
)
);
$userName = $user->getName();
$this->assertEquals('Davert', $userName);
?>
```
Alternatively, a function can be passed as parameter:
```php
<?php
Expected::once(function() { return Faker::name(); });
```
* `param mixed` $params
@return StubMarshaler
#### *public static* atLeastOnce($params = null)
Checks if a method has been invoked at least one
time.
If the number of invocations is 0 it will throw an exception in verify.
```php
<?php
use \Codeception\Stub\Expected;
$user = $this->make(
'User',
array(
'getName' => Expected::atLeastOnce('Davert')),
'someMethod' => function() {}
)
);
$user->getName();
$userName = $user->getName();
$this->assertEquals('Davert', $userName);
?>
```
Alternatively, a function can be passed as parameter:
```php
<?php
Expected::atLeastOnce(function() { return Faker::name(); });
```
* `param mixed` $params
@return StubMarshaler
#### *public static* exactly($count, $params = null)
Checks if a method has been invoked a certain amount
of times.
If the number of invocations exceeds the value it will immediately throw an
exception,
If the number is less it will later be checked in verify() and also throw an
exception.
``` php
<?php
use \Codeception\Stub;
use \Codeception\Stub\Expected;
$user = $this->make(
'User',
array(
'getName' => Expected::exactly(3, 'Davert'),
'someMethod' => function() {}
)
);
$user->getName();
$user->getName();
$userName = $user->getName();
$this->assertEquals('Davert', $userName);
?>
```
Alternatively, a function can be passed as parameter:
```php
<?php
Expected::exactly(function() { return Faker::name() });
```
* `param int` $count
* `param mixed` $params
@return StubMarshaler
<?php
namespace Codeception\Command;
use Codeception\Configuration;
use Stecman\Component\Symfony\Console\BashCompletion\Completion as ConsoleCompletion;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionHandler;
use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion as ShellPathCompletion;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class CompletionFallback extends Command
{
protected function configure()
{
$this
->setName('_completion')
->setDescription('BASH completion hook.')
->setHelp(<<<END
To enable BASH completion, install optional stecman/symfony-console-completion first:
<comment>composer require stecman/symfony-console-completion</comment>
END
);
// Hide this command from listing if supported
// Command::setHidden() was not available before Symfony 3.2.0
if (method_exists($this, 'setHidden')) {
$this->setHidden(true);
}
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln("Install optional <comment>stecman/symfony-console-completion</comment>");
}
}
<?php
namespace Codeception\Step\Argument;
/**
* Implemented in Step arguments where literal values need to be modified in test execution output (e.g. passwords).
*/
interface FormattedOutput
{
/**
* Returns the argument's value formatted for output.
*
* @return string
*/
public function getOutput();
/**
* Returns the argument's literal value.
*
* @return string
*/
public function __toString();
}
<?php
namespace Codeception\Step\Argument;
class PasswordArgument implements FormattedOutput
{
/**
* @var string
*/
private $password;
public function __construct($password)
{
$this->password = $password;
}
/**
* {@inheritdoc}
*/
public function getOutput()
{
return '******';
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->password;
}
}
<?php
class CodeceptionYmlInTestsDirCest
{
/**
* @param CliGuy $I
*/
public function runTestPath(\CliGuy $I)
{
$I->amInPath('tests/data/codeception_yml_in_tests_dir');
$I->executeCommand('run unit/ExampleCest.php');
$I->seeResultCodeIs(0);
$I->dontSeeInShellOutput('RuntimeException');
$I->dontSeeInShellOutput('could not be found');
}
}
<?php
class ConfigWithPresetsCest
{
public function loadWithPresets(CliGuy $I)
{
$I->amInPath('tests/data/presets');
$I->executeCommand('run -c codeception.yml');
$I->seeInShellOutput('OK (1 test');
}
}
<?php
class RunSingleTestWithIncludeCest
{
public function run(\CliGuy $I)
{
$I->amInPath('tests/data/single_test_with_include');
$I->wantTo('execute one test with include in config');
$I->executeCommand('run unit/ExampleCest.php');
$I->seeResultCodeIs(0);
$I->dontSeeInShellOutput('RuntimeException');
$I->dontSeeInShellOutput('could not be found');
}
}
<?php
$I = new CoverGuy($scenario);
$I->wantTo('try generate remote codecoverage phpunit report');
$I->amInPath('tests/data/sandbox');
$I->executeCommand('run remote --coverage-phpunit');
$I->seeFileFound('index.xml', 'tests/_output/coverage-phpunit');
$I->seeCoverageStatsNotEmpty();
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head></head>
<body>
<form action="/form/password_argument" method="post">
<input type="password" id="password" name="password">
<button type="submit">Submit</button>
</form>
</body>
</html>
<?php
class PartialFailedCest
{
public function testCaseOne(ScenarioGuy $I)
{
$I->amInPath('.');
$I->seeFileFound('scenario.suite.yml');
}
public function testCaseTwo(ScenarioGuy $I)
{
$I->amInPath('.');
$I->seeFileFound('testcasetwo.txt');
}
public function testCaseThree(ScenarioGuy $I)
{
$I->amInPath('.');
$I->seeFileFound('testcasethree.txt');
}
}
<?php
class WarningTest extends \Codeception\Test\Unit
{
/**
* @dataProvider dependentProvider
*/
public function testWarningInvalidDataProvider($a)
{
$this->assertTrue(true);
}
public function dependentProvider()
{
throw new Exception;
}
}
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}
actor: Tester
paths:
tests: .
log: _output
data: _data
support: _support
settings:
bootstrap: _bootstrap.php
\ No newline at end of file
# Codeception Test Suite Configuration
#
# Suite for unit (internal) tests.
class_name: UnitTester
modules:
enabled:
- Asserts
\ No newline at end of file
<?php
class ExampleCest
{
public function successful(UnitTester $I)
{
$I->assertTrue(true);
}
}
<?php
// Here you can initialize variables that will be available to your tests
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
actor_suffix: Tester
extensions:
enabled:
- Codeception\Extension\RunFailed
modules:
enabled:
- \Helper\Dummy
\ No newline at end of file
extends: ./_presets/preset.codeception.yml
extends: ./_presets/missing.preset.codeception.yml
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class DummyTester extends \Codeception\Actor
{
use _generated\DummyTesterActions;
/**
* Define custom actions here
*/
}
<?php
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
use Codeception\TestInterface;
class Dummy extends \Codeception\Module
{
public function _before(TestInterface $test)
{
$this->debug($this->config);
}
public function seePathIsSet()
{
$this->assertNotEmpty($this->config['path']);
}
public function seeVarsAreSet()
{
$vars = $this->config['vars'];
$this->assertContains('val1', $vars);
$this->assertContains('val2', $vars);
}
}
presetfile: ./../_presets/preset.unit.suite.yml
class_name: DummyTester
\ No newline at end of file
<?php
class PresetTest extends \Codeception\Test\Unit
{
public function testSomeFeature()
{
$this->assertEquals(true, true);
$this->assertNotEquals(true, false);
}
}
\ No newline at end of file
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}
actor: Tester
paths:
tests: .
log: _output
data: _data
support: _support
settings:
bootstrap: _bootstrap.php
include:
- dummy/path
# Codeception Test Suite Configuration
#
# Suite for unit (internal) tests.
class_name: UnitTester
modules:
enabled:
- Asserts
<?php
class ExampleCest
{
public function successful(UnitTester $I)
{
$I->assertTrue(true);
}
}
<?php
// Here you can initialize variables that will be available to your tests
<?php
use \Codeception\Lib\Driver\Db;
use \Codeception\Test\Unit;
use \Codeception\Util\ReflectionHelper;
/**
* @group appveyor
* @group db
*/
class DbTest extends Unit
{
/**
* @dataProvider getWhereCriteria
*/
public function testGenerateWhereClause($criteria, $expectedResult)
{
$db = new Db('sqlite:tests/data/sqlite.db','root','');
$result = ReflectionHelper::invokePrivateMethod($db, 'generateWhereClause', [&$criteria]);
$this->assertEquals($expectedResult, $result);
}
public function getWhereCriteria()
{
return [
'like' => [['email like' => 'mail.ua'], 'WHERE "email" LIKE ? '],
'<=' => [['id <=' => '5'], 'WHERE "id" <= ? '],
'<' => [['id <' => '5'], 'WHERE "id" < ? '],
'>=' => [['id >=' => '5'], 'WHERE "id" >= ? '],
'>' => [['id >' => '5'], 'WHERE "id" > ? '],
'!=' => [['id !=' => '5'], 'WHERE "id" != ? '],
];
}
}
.idea
composer.lock
vendor
\ No newline at end of file
language: php
env:
CODECEPTION_VERSION: '2.4.x-dev'
php:
- 7.1
- 7.2
before_script:
- wget https://robo.li/robo.phar
- php robo.phar prepare
- composer update
script:
- php robo.phar test cli
- php robo.phar test "unit -g core"
\ No newline at end of file
# PHPUnit Wrapper
Builds:
* 6.0 [![Build Status](https://travis-ci.org/Codeception/phpunit-wrapper.svg?branch=6.0)](https://travis-ci.org/Codeception/phpunit-wrapper)
* 7.0 [![Build Status](https://travis-ci.org/Codeception/phpunit-wrapper.svg?branch=7.0)](https://travis-ci.org/Codeception/phpunit-wrapper)
Codeception heavily relies on PHPUnit for running and managing tests.
Not all PHPUnit classes fit the needs of Codeception, that's why they were extended or redefined.
Releases follow major PHPUnit versions.
<?php
/**
* This is project's console commands configuration for Robo task runner.
*
* @see http://robo.li/
*/
class RoboFile extends \Robo\Tasks
{
// define public methods as commands
public function prepare()
{
$config = json_decode(file_get_contents(__DIR__ . '/composer.json'), true);
$config['name'] = 'codeception/phpunit-wrapper-test';
$config['require-dev']['codeception/codeception'] = getenv('CODECEPTION_VERSION');
$config['replace'] = ['codeception/phpunit-wrapper' => '*'];
file_put_contents(__DIR__ . '/composer.json', json_encode($config));
}
public function test($params)
{
return $this->taskExec(__DIR__ . '/vendor/bin/codecept run ' . $params)
->dir(__DIR__ .'/vendor/codeception/codeception')
->run();
}
}
\ No newline at end of file
{
"name": "codeception/phpunit-wrapper",
"description": "PHPUnit classes used by Codeception",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Davert",
"email": "davert.php@resend.cc"
}
],
"require": {
"phpunit/phpunit": "^7.1",
"phpunit/php-code-coverage": "^6.0",
"sebastian/comparator": "^3.0",
"sebastian/diff": "^3.0"
},
"autoload":{
"psr-4":{
"Codeception\\PHPUnit\\": "src\\"
}
},
"require-dev": {
"vlucas/phpdotenv": "^2.4",
"codeception/specify": "*"
}
}
<?php
namespace Codeception\PHPUnit;
/**
* Printer implementing this interface prints output to console, thus should be marked as printer and not just a logger
*
* Interface ConsolePrinter
* @package Codeception\PHPUnit
*/
interface ConsolePrinter
{
public function write(string $buffer);
public function printResult(\PHPUnit\Framework\TestResult $result);
}
<?php
namespace Codeception\PHPUnit\Constraint;
use Codeception\Exception\ElementNotFound;
use Codeception\Lib\Console\Message;
use Symfony\Component\DomCrawler\Crawler as DomCrawler;
use SebastianBergmann\Comparator\ComparisonFailure;
class Crawler extends Page
{
protected function matches($nodes) : bool
{
/** @var $nodes DomCrawler * */
if (!$nodes->count()) {
return false;
}
if ($this->string === '') {
return true;
}
foreach ($nodes as $node) {
if (parent::matches($node->nodeValue)) {
return true;
}
}
return false;
}
protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null):void
{
/** @var $nodes DomCrawler * */
if (!$nodes->count()) {
throw new ElementNotFound($selector, 'Element located either by name, CSS or XPath');
}
$output = "Failed asserting that any element by '$selector'";
$output .= $this->uriMessage('on page');
$output .= " ";
if ($nodes->count() < 10) {
$output .= $this->nodesList($nodes);
} else {
$message = new Message("[total %s elements]");
$output .= $message->with($nodes->count())->getMessage();
}
$output .= "\ncontains text '{$this->string}'";
throw new \PHPUnit\Framework\ExpectationFailedException(
$output,
$comparisonFailure
);
}
protected function failureDescription($other) : string
{
$desc = '';
foreach ($other as $o) {
$desc .= parent::failureDescription($o->textContent);
}
return $desc;
}
protected function nodesList(DomCrawler $nodes, $contains = null)
{
$output = "";
foreach ($nodes as $node) {
if ($contains && strpos($node->nodeValue, $contains) === false) {
continue;
}
$output .= "\n+ " . $node->C14N();
}
return $output;
}
}
<?php
namespace Codeception\PHPUnit\Constraint;
use SebastianBergmann\Comparator\ComparisonFailure;
class CrawlerNot extends Crawler
{
protected function matches($nodes) : bool
{
return !parent::matches($nodes);
}
protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null) : void
{
if (!$this->string) {
throw new \PHPUnit\Framework\ExpectationFailedException(
"Element '$selector' was found",
$comparisonFailure
);
}
/** @var $nodes DomCrawler * */
$output = "There was '$selector' element";
$output .= $this->uriMessage('on page');
$output .= $this->nodesList($nodes, $this->string);
$output .= "\ncontaining '{$this->string}'";
throw new \PHPUnit\Framework\ExpectationFailedException(
$output,
$comparisonFailure
);
}
public function toString() : string
{
if ($this->string) {
return 'that contains text "' . $this->string . '"';
}
}
}
<?php
namespace Codeception\PHPUnit\Constraint;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\ArrayComparator;
use SebastianBergmann\Comparator\Factory;
use Codeception\Util\JsonArray;
class JsonContains extends \PHPUnit\Framework\Constraint\Constraint
{
/**
* @var
*/
protected $expected;
public function __construct(array $expected)
{
parent::__construct();
$this->expected = $expected;
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other Value or object to evaluate.
*
* @return bool
*/
protected function matches($other) : bool
{
$jsonResponseArray = new JsonArray($other);
if (!is_array($jsonResponseArray->toArray())) {
throw new \PHPUnit\Framework\AssertionFailedError('JSON response is not an array: ' . $other);
}
if ($jsonResponseArray->containsArray($this->expected)) {
return true;
}
$comparator = new ArrayComparator();
$comparator->setFactory(new Factory);
try {
$comparator->assertEquals($this->expected, $jsonResponseArray->toArray());
} catch (ComparisonFailure $failure) {
throw new \PHPUnit\Framework\ExpectationFailedException(
"Response JSON does not contain the provided JSON\n",
$failure
);
}
}
/**
* Returns a string representation of the constraint.
*
* @return string
*/
public function toString() : string
{
//unused
return '';
}
protected function failureDescription($other) : string
{
//unused
return '';
}
}
<?php
namespace Codeception\PHPUnit\Constraint;
use Codeception\Util\JsonType as JsonTypeUtil;
use Codeception\Util\JsonArray;
class JsonType extends \PHPUnit\Framework\Constraint\Constraint
{
protected $jsonType;
private $match;
public function __construct(array $jsonType, $match = true)
{
parent::__construct();
$this->jsonType = $jsonType;
$this->match = $match;
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $jsonArray Value or object to evaluate.
*
* @return bool
*/
protected function matches($jsonArray) : bool
{
if ($jsonArray instanceof JsonArray) {
$jsonArray = $jsonArray->toArray();
}
$matched = (new JsonTypeUtil($jsonArray))->matches($this->jsonType);
if ($this->match) {
if ($matched !== true) {
throw new \PHPUnit\Framework\ExpectationFailedException($matched);
}
} else {
if ($matched === true) {
throw new \PHPUnit\Framework\ExpectationFailedException('Unexpectedly response matched: ' . json_encode($jsonArray));
}
}
return true;
}
/**
* Returns a string representation of the constraint.
*
* @return string
*/
public function toString() : string
{
//unused
return '';
}
protected function failureDescription($other) : string
{
//unused
return '';
}
}
<?php
namespace Codeception\PHPUnit\Constraint;
use Codeception\Lib\Console\Message;
class Page extends \PHPUnit\Framework\Constraint\Constraint
{
protected $uri;
protected $string;
public function __construct($string, $uri = '')
{
parent::__construct();
$this->string = $this->normalizeText((string)$string);
$this->uri = $uri;
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other Value or object to evaluate.
*
* @return bool
*/
protected function matches($other) : bool
{
$other = $this->normalizeText($other);
return mb_stripos($other, $this->string, null, 'UTF-8') !== false;
}
/**
* @param $text
* @return string
*/
private function normalizeText($text)
{
$text = strtr($text, "\r\n", " ");
return trim(preg_replace('/\\s{2,}/', ' ', $text));
}
/**
* Returns a string representation of the constraint.
*
* @return string
*/
public function toString() : string
{
return sprintf(
'contains "%s"',
$this->string
);
}
protected function failureDescription($pageContent) : string
{
$message = $this->uriMessage('on page');
$message->append("\n--> ");
$message->append(substr($pageContent, 0, 300));
if (strlen($pageContent) > 300) {
$debugMessage = new Message(
"[Content too long to display. See complete response in '" . codecept_output_dir() . "' directory]"
);
$message->append("\n")->append($debugMessage);
}
$message->append("\n--> ");
return $message->getMessage() . $this->toString();
}
protected function uriMessage($onPage = "")
{
if (!$this->uri) {
return new Message('');
}
$message = new Message($this->uri);
$message->prepend(" $onPage ");
return $message;
}
}
<?php
namespace Codeception\PHPUnit\Constraint;
use Codeception\Exception\ElementNotFound;
use Codeception\Lib\Console\Message;
use Codeception\Util\Locator;
use SebastianBergmann\Comparator\ComparisonFailure;
class WebDriver extends Page
{
protected function matches($nodes) : bool
{
if (!count($nodes)) {
return false;
}
if ($this->string === '') {
return true;
}
foreach ($nodes as $node) {
/** @var $node \WebDriverElement * */
if (!$node->isDisplayed()) {
continue;
}
if (parent::matches(htmlspecialchars_decode($node->getText()))) {
return true;
}
}
return false;
}
protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null) : void
{
if (!count($nodes)) {
throw new ElementNotFound($selector, 'Element located either by name, CSS or XPath');
}
$output = "Failed asserting that any element by " . Locator::humanReadableString($selector);
$output .= $this->uriMessage('on page');
if (count($nodes) < 5) {
$output .= "\nElements: ";
$output .= $this->nodesList($nodes);
} else {
$message = new Message("[total %s elements]");
$output .= $message->with(count($nodes));
}
$output .= "\ncontains text '" . $this->string . "'";
throw new \PHPUnit\Framework\ExpectationFailedException(
$output,
$comparisonFailure
);
}
protected function failureDescription($nodes) : string
{
$desc = '';
foreach ($nodes as $node) {
$desc .= parent::failureDescription($node->getText());
}
return $desc;
}
protected function nodesList($nodes, $contains = null)
{
$output = "";
foreach ($nodes as $node) {
if ($contains && strpos($node->getText(), $contains) === false) {
continue;
}
/** @var $node \WebDriverElement * */
$message = new Message("\n+ <%s> %s");
$output .= $message->with($node->getTagName(), $node->getText());
}
return $output;
}
}
<?php
namespace Codeception\PHPUnit\Constraint;
use SebastianBergmann\Comparator\ComparisonFailure;
use Codeception\Util\Locator;
class WebDriverNot extends WebDriver
{
protected function matches($nodes) : bool
{
return !parent::matches($nodes);
}
protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null) : void
{
$selectorString = Locator::humanReadableString($selector);
if (!$this->string) {
throw new \PHPUnit\Framework\ExpectationFailedException(
"Element $selectorString was found",
$comparisonFailure
);
}
$output = "There was $selectorString element";
$output .= $this->uriMessage("on page");
$output .= $this->nodesList($nodes, $this->string);
$output .= "\ncontaining '{$this->string}'";
throw new \PHPUnit\Framework\ExpectationFailedException(
$output,
$comparisonFailure
);
}
public function toString() : string
{
if ($this->string) {
return 'that contains text "' . $this->string . '"';
}
}
}
<?php
namespace Codeception\PHPUnit;
use Codeception\Test\Descriptor;
/**
* Extended Filter Test from PHPUnit to use Codeception's Descriptor to locate tests.
*
* Class FilterTest
* @package Codeception\PHPUnit
*/
class FilterTest extends \PHPUnit\Runner\Filter\NameFilterIterator
{
public function accept():bool
{
$test = $this->getInnerIterator()->current();
if ($test instanceof \PHPUnit\Framework\TestSuite) {
return true;
}
$name = Descriptor::getTestSignature($test);
$index = Descriptor::getTestDataSetIndex($test);
if (!is_null($index)) {
$name .= " with data set #{$index}";
}
$accepted = preg_match($this->filter, $name, $matches);
// This fix the issue when an invalid dataprovider method generate a warning
// See issue https://github.com/Codeception/Codeception/issues/4888
if($test instanceof \PHPUnit\Framework\WarningTestCase) {
$message = $test->getMessage();
$accepted = preg_match($this->filter, $message, $matches);
}
if ($accepted && isset($this->filterMax)) {
$set = end($matches);
$accepted = $set >= $this->filterMin && $set <= $this->filterMax;
}
return $accepted;
}
}
<?php
namespace Codeception\PHPUnit;
class Init
{
/**
* @api
*/
public static function init()
{
require_once __DIR__ . DIRECTORY_SEPARATOR . 'phpunit7-interfaces.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . 'shim.php';
}
}
\ No newline at end of file
<?php
namespace Codeception\PHPUnit;
use Codeception\Event\FailEvent;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\TestInterface;
use Exception;
use PHPUnit\Framework\Test;
use Symfony\Component\EventDispatcher\EventDispatcher;
class Listener implements \PHPUnit\Framework\TestListener
{
/**
* @var \Symfony\Component\EventDispatcher\EventDispatcher
*/
protected $dispatcher;
protected $unsuccessfulTests = [];
protected $skippedTests = [];
protected $startedTests = [];
public function __construct(EventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Risky test.
*
* @param PHPUnit\Framework\Test $test
* @param \Throwable $e
* @param float $time
* @since Method available since Release 4.0.0
*/
public function addRiskyTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
}
public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
{
$this->unsuccessfulTests[] = spl_object_hash($test);
$this->fire(Events::TEST_FAIL, new FailEvent($test, $time, $e));
}
public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->unsuccessfulTests[] = spl_object_hash($test);
$this->fire(Events::TEST_ERROR, new FailEvent($test, $time, $e));
}
// This method was added in PHPUnit 6
public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time) : void
{
$this->unsuccessfulTests[] = spl_object_hash($test);
$this->fire(Events::TEST_WARNING, new FailEvent($test, $time, $e));
}
public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
if (in_array(spl_object_hash($test), $this->skippedTests)) {
return;
}
$this->unsuccessfulTests[] = spl_object_hash($test);
$this->fire(Events::TEST_INCOMPLETE, new FailEvent($test, $time, $e));
$this->skippedTests[] = spl_object_hash($test);
}
public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
if (in_array(spl_object_hash($test), $this->skippedTests)) {
return;
}
$this->unsuccessfulTests[] = spl_object_hash($test);
$this->fire(Events::TEST_SKIPPED, new FailEvent($test, $time, $e));
$this->skippedTests[] = spl_object_hash($test);
}
public function startTestSuite(\PHPUnit\Framework\TestSuite $suite) : void
{
$this->dispatcher->dispatch('suite.start', new SuiteEvent($suite));
}
public function endTestSuite(\PHPUnit\Framework\TestSuite $suite) : void
{
$this->dispatcher->dispatch('suite.end', new SuiteEvent($suite));
}
public function startTest(\PHPUnit\Framework\Test $test) : void
{
$this->dispatcher->dispatch(Events::TEST_START, new TestEvent($test));
if (!$test instanceof TestInterface) {
return;
}
if ($test->getMetadata()->isBlocked()) {
return;
}
try {
$this->startedTests[] = spl_object_hash($test);
$this->fire(Events::TEST_BEFORE, new TestEvent($test));
} catch (\PHPUnit\Framework\IncompleteTestError $e) {
$test->getTestResultObject()->addFailure($test, $e, 0);
} catch (\PHPUnit\Framework\SkippedTestError $e) {
$test->getTestResultObject()->addFailure($test, $e, 0);
} catch (\Throwable $e) {
$test->getTestResultObject()->addError($test, $e, 0);
}
}
public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
{
$hash = spl_object_hash($test);
if (!in_array($hash, $this->unsuccessfulTests)) {
$this->fire(Events::TEST_SUCCESS, new TestEvent($test, $time));
}
if (in_array($hash, $this->startedTests)) {
$this->fire(Events::TEST_AFTER, new TestEvent($test, $time));
}
$this->dispatcher->dispatch(Events::TEST_END, new TestEvent($test, $time));
}
protected function fire($event, TestEvent $eventType)
{
$test = $eventType->getTest();
if ($test instanceof TestInterface) {
foreach ($test->getMetadata()->getGroups() as $group) {
$this->dispatcher->dispatch($event . '.' . $group, $eventType);
}
}
$this->dispatcher->dispatch($event, $eventType);
}
}
<?php
namespace Codeception\PHPUnit\Log;
use Codeception\Configuration;
use Codeception\Test\Interfaces\Reported;
use Codeception\Test\Test;
class JUnit extends \PHPUnit\Util\Log\JUnit
{
protected $strictAttributes = ['file', 'name', 'class'];
public function startTest(\PHPUnit\Framework\Test $test):void
{
if (!$test instanceof Reported) {
parent::startTest($test);
return;
}
$this->currentTestCase = $this->document->createElement('testcase');
$isStrict = Configuration::config()['settings']['strict_xml'];
foreach ($test->getReportFields() as $attr => $value) {
if ($isStrict and !in_array($attr, $this->strictAttributes)) {
continue;
}
$this->currentTestCase->setAttribute($attr, $value);
}
}
public function endTest(\PHPUnit\Framework\Test $test, float $time):void
{
if ($this->currentTestCase !== null and $test instanceof Test) {
$numAssertions = $test->getNumAssertions();
$this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;
$this->currentTestCase->setAttribute(
'assertions',
$numAssertions
);
}
parent::endTest($test, $time);
}
}
<?php
namespace PHPUnit\Util;
// @codingStandardsIgnoreStart
class Filter
{
// @codingStandardsIgnoreEnd
protected static $filteredClassesPattern = [
'Symfony\Component\Console',
'Codeception\Command\\',
'Codeception\TestCase\\',
];
public static function getFilteredStackTrace($e, $asString = true, $filter = true)
{
$stackTrace = $asString ? '' : [];
$trace = $e->getPrevious() ? $e->getPrevious()->getTrace() : $e->getTrace();
if ($e instanceof \PHPUnit\Framework\ExceptionWrapper) {
$trace = $e->getSerializableTrace();
}
$eFile = $e->getFile();
$eLine = $e->getLine();
if (!self::frameExists($trace, $eFile, $eLine)) {
array_unshift(
$trace,
['file' => $eFile, 'line' => $eLine]
);
}
foreach ($trace as $step) {
if (self::classIsFiltered($step) and $filter) {
continue;
}
if (self::fileIsFiltered($step) and $filter) {
continue;
}
if (!$asString) {
$stackTrace[] = $step;
continue;
}
if (!isset($step['file'])) {
continue;
}
$stackTrace .= $step['file'] . ':' . $step['line'] . "\n";
}
return $stackTrace;
}
protected static function classIsFiltered($step)
{
if (!isset($step['class'])) {
return false;
}
$className = $step['class'];
foreach (self::$filteredClassesPattern as $filteredClassName) {
if (strpos($className, $filteredClassName) === 0) {
return true;
}
}
return false;
}
protected static function fileIsFiltered($step)
{
if (!isset($step['file'])) {
return false;
}
if (strpos($step['file'], 'codecept.phar/') !== false) {
return true;
}
if (strpos($step['file'], 'vendor' . DIRECTORY_SEPARATOR . 'phpunit') !== false) {
return true;
}
if (strpos($step['file'], 'vendor' . DIRECTORY_SEPARATOR . 'codeception') !== false) {
return true;
}
$modulePath = 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR . 'Module';
if (strpos($step['file'], $modulePath) !== false) {
return false; // don`t filter modules
}
if (strpos($step['file'], 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR) !== false) {
return true;
}
return false;
}
/**
* @param array $trace
* @param string $file
* @param int $line
*
* @return bool
*/
private static function frameExists(array $trace, $file, $line)
{
foreach ($trace as $frame) {
if (isset($frame['file']) && $frame['file'] == $file &&
isset($frame['line']) && $frame['line'] == $line) {
return true;
}
}
return false;
}
}
<?php
namespace Codeception\PHPUnit;
use \PHPUnit\Framework\AssertionFailedError;
use \PHPUnit\Framework\Test;
use \PHPUnit\Runner\BaseTestRunner;
class ResultPrinter extends \PHPUnit\Util\TestDox\ResultPrinter
{
/**
* An error occurred.
*
* @param \PHPUnit\Framework\Test $test
* @param \Throwable $e
* @param float $time
*/
public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_ERROR;
$this->failed++;
}
/**
* A failure occurred.
*
* @param \PHPUnit\Framework\Test $test
* @param \PHPUnit\Framework\AssertionFailedError $e
* @param float $time
*/
public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
{
$this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_FAILURE;
$this->failed++;
}
/**
* A warning occurred.
*
* @param \PHPUnit\Framework\Test $test
* @param \PHPUnit\Framework\Warning $e
* @param float $time
*/
public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time): void
{
$this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_WARNING;
$this->warned++;
}
/**
* Incomplete test.
*
* @param \PHPUnit\Framework\Test $test
* @param \Throwable $e
* @param float $time
*/
public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_INCOMPLETE;
$this->incomplete++;
}
/**
* Risky test.
*
* @param \PHPUnit\Framework\Test $test
* @param \Throwable $e
* @param float $time
*
* @since Method available since Release 4.0.0
*/
public function addRiskyTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_RISKY;
$this->risky++;
}
/**
* Skipped test.
*
* @param \PHPUnit\Framework\Test $test
* @param \Throwable $e
* @param float $time
*
* @since Method available since Release 3.0.0
*/
public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_SKIPPED;
$this->skipped++;
}
public function startTest(\PHPUnit\Framework\Test $test) : void
{
$this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_PASSED;
}
}
<?php
namespace Codeception\PHPUnit\ResultPrinter;
use Codeception\PHPUnit\ResultPrinter as CodeceptionResultPrinter;
use Codeception\Step;
use Codeception\Step\Meta;
use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\TestInterface;
use Codeception\Util\PathResolver;
class HTML extends CodeceptionResultPrinter
{
/**
* @var boolean
*/
protected $printsHTML = true;
/**
* @var integer
*/
protected $id = 0;
/**
* @var string
*/
protected $scenarios = '';
/**
* @var string
*/
protected $templatePath;
/**
* @var int
*/
protected $timeTaken = 0;
protected $failures = [];
/**
* Constructor.
*
* @param mixed $out
* @throws InvalidArgumentException
*/
public function __construct($out = null)
{
parent::__construct($out);
$this->templatePath = sprintf(
'%s%stemplate%s',
__DIR__,
DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR
);
}
/**
* Handler for 'start class' event.
*
* @param string $name
*/
protected function startClass(string $name):void
{
}
public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
{
$steps = [];
$success = ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_PASSED);
if ($success) {
$this->successful++;
}
if ($test instanceof ScenarioDriven) {
$steps = $test->getScenario()->getSteps();
}
$this->timeTaken += $time;
switch ($this->testStatus) {
case \PHPUnit\Runner\BaseTestRunner::STATUS_FAILURE:
$scenarioStatus = 'scenarioFailed';
break;
case \PHPUnit\Runner\BaseTestRunner::STATUS_SKIPPED:
$scenarioStatus = 'scenarioSkipped';
break;
case \PHPUnit\Runner\BaseTestRunner::STATUS_INCOMPLETE:
$scenarioStatus = 'scenarioIncomplete';
break;
case \PHPUnit\Runner\BaseTestRunner::STATUS_ERROR:
$scenarioStatus = 'scenarioFailed';
break;
default:
$scenarioStatus = 'scenarioSuccess';
}
$stepsBuffer = '';
$subStepsBuffer = '';
$subStepsRendered = [];
foreach ($steps as $step) {
if ($step->getMetaStep()) {
$subStepsRendered[$step->getMetaStep()->getAction()][] = $this->renderStep($step);
}
}
foreach ($steps as $step) {
if ($step->getMetaStep()) {
if (! empty($subStepsRendered[$step->getMetaStep()->getAction()])) {
$subStepsBuffer = implode('', $subStepsRendered[$step->getMetaStep()->getAction()]);
unset($subStepsRendered[$step->getMetaStep()->getAction()]);
$stepsBuffer .= $this->renderSubsteps($step->getMetaStep(), $subStepsBuffer);
}
} else {
$stepsBuffer .= $this->renderStep($step);
}
}
$scenarioTemplate = new \Text_Template(
$this->templatePath . 'scenario.html'
);
$failures = '';
$name = Descriptor::getTestSignatureUnique($test);
if (isset($this->failures[$name])) {
$failTemplate = new \Text_Template(
$this->templatePath . 'fail.html'
);
foreach ($this->failures[$name] as $failure) {
$failTemplate->setVar(['fail' => nl2br($failure)]);
$failures .= $failTemplate->render() . PHP_EOL;
}
$this->failures[$name] = [];
}
$png = '';
$html = '';
if ($test instanceof TestInterface) {
$reports = $test->getMetadata()->getReports();
if (isset($reports['png'])) {
$localPath = PathResolver::getRelativeDir($reports['png'], codecept_output_dir());
$png = "<tr><td class='error'><div class='screenshot'><img src='$localPath' alt='failure screenshot'></div></td></tr>";
}
if (isset($reports['html'])) {
$localPath = PathResolver::getRelativeDir($reports['html'], codecept_output_dir());
$html = "<tr><td class='error'>See <a href='$localPath' target='_blank'>HTML snapshot</a> of a failed page</td></tr>";
}
}
$toggle = $stepsBuffer ? '<span class="toggle">+</span>' : '';
$testString = htmlspecialchars(ucfirst(Descriptor::getTestAsString($test)));
$testString = preg_replace('~^([\s\w\\\]+):\s~', '<span class="quiet">$1 &raquo;</span> ', $testString);
$scenarioTemplate->setVar(
[
'id' => ++$this->id,
'name' => $testString,
'scenarioStatus' => $scenarioStatus,
'steps' => $stepsBuffer,
'toggle' => $toggle,
'failure' => $failures,
'png' => $png,
'html' => $html,
'time' => round($time, 2)
]
);
$this->scenarios .= $scenarioTemplate->render();
}
public function startTestSuite(\PHPUnit\Framework\TestSuite $suite) : void
{
$suiteTemplate = new \Text_Template(
$this->templatePath . 'suite.html'
);
if (!$suite->getName()) {
return;
}
$suiteTemplate->setVar(['suite' => ucfirst($suite->getName())]);
$this->scenarios .= $suiteTemplate->render();
}
/**
* Handler for 'end run' event.
*/
protected function endRun():void
{
$scenarioHeaderTemplate = new \Text_Template(
$this->templatePath . 'scenario_header.html'
);
$status = !$this->failed
? '<span style="color: green">OK</span>'
: '<span style="color: #e74c3c">FAILED</span>';
$scenarioHeaderTemplate->setVar(
[
'name' => 'Codeception Results',
'status' => $status,
'time' => round($this->timeTaken, 1)
]
);
$header = $scenarioHeaderTemplate->render();
$scenariosTemplate = new \Text_Template(
$this->templatePath . 'scenarios.html'
);
$scenariosTemplate->setVar(
[
'header' => $header,
'scenarios' => $this->scenarios,
'successfulScenarios' => $this->successful,
'failedScenarios' => $this->failed,
'skippedScenarios' => $this->skipped,
'incompleteScenarios' => $this->incomplete
]
);
$this->write($scenariosTemplate->render());
}
/**
* An error occurred.
*
* @param \PHPUnit\Framework\Test $test
* @param \Exception $e
* @param float $time
*/
public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->failures[Descriptor::getTestSignatureUnique($test)][] = $this->cleanMessage($e);
parent::addError($test, $e, $time);
}
/**
* A failure occurred.
*
* @param \PHPUnit\Framework\Test $test
* @param \PHPUnit\Framework\AssertionFailedError $e
* @param float $time
*/
public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
{
$this->failures[Descriptor::getTestSignatureUnique($test)][] = $this->cleanMessage($e);
parent::addFailure($test, $e, $time);
}
/**
* Starts test
*
* @param \PHPUnit\Framework\Test $test
*/
public function startTest(\PHPUnit\Framework\Test $test):void
{
$name = Descriptor::getTestSignatureUnique($test);
if (isset($this->failures[$name])) {
// test failed in before hook
return;
}
// start test and mark initialize as passed
parent::startTest($test);
}
/**
* @param $step
* @return string
*/
protected function renderStep(Step $step)
{
$stepTemplate = new \Text_Template($this->templatePath . 'step.html');
$stepTemplate->setVar(['action' => $step->getHtml(), 'error' => $step->hasFailed() ? 'failedStep' : '']);
return $stepTemplate->render();
}
/**
* @param $metaStep
* @param $substepsBuffer
* @return string
*/
protected function renderSubsteps(Meta $metaStep, $substepsBuffer)
{
$metaTemplate = new \Text_Template($this->templatePath . 'substeps.html');
$metaTemplate->setVar(['metaStep' => $metaStep->getHtml(), 'error' => $metaStep->hasFailed() ? 'failedStep' : '', 'steps' => $substepsBuffer, 'id' => uniqid()]);
return $metaTemplate->render();
}
private function cleanMessage($exception)
{
$msg = $exception->getMessage();
if ($exception instanceof \PHPUnit\Framework\ExpectationFailedException && $exception->getComparisonFailure()) {
$msg .= $exception->getComparisonFailure()->getDiff();
}
$msg = str_replace(['<info>','</info>','<bold>','</bold>'], ['','','',''], $msg);
return htmlentities($msg);
}
}
<?php
namespace Codeception\PHPUnit\ResultPrinter;
use Codeception\Lib\Console\Output;
use Codeception\PHPUnit\ConsolePrinter;
use Codeception\PHPUnit\ResultPrinter;
use Codeception\Test\Descriptor;
class Report extends ResultPrinter implements ConsolePrinter
{
/**
* @param \PHPUnit\Framework\Test $test
* @param float $time
*/
public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
{
$name = Descriptor::getTestAsString($test);
$success = ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_PASSED);
if ($success) {
$this->successful++;
}
if ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_FAILURE) {
$status = "\033[41;37mFAIL\033[0m";
} elseif ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_SKIPPED) {
$status = 'Skipped';
} elseif ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_INCOMPLETE) {
$status = 'Incomplete';
} elseif ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_ERROR) {
$status = 'ERROR';
} else {
$status = 'Ok';
}
if (strlen($name) > 75) {
$name = substr($name, 0, 70);
}
$line = $name . str_repeat('.', 75 - strlen($name));
$line .= $status;
$this->write($line . "\n");
}
protected function endRun() : void
{
$this->write("\nCodeception Results\n");
$this->write(sprintf(
"Successful: %s. Failed: %s. Incomplete: %s. Skipped: %s",
$this->successful,
$this->failed,
$this->skipped,
$this->incomplete
) . "\n");
}
public function printResult(\PHPUnit\Framework\TestResult $result)
{
}
public function write(string $buffer) : void
{
parent::write($buffer);
}
}
<?php
namespace Codeception\PHPUnit\ResultPrinter;
use Codeception\Event\FailEvent;
use Codeception\Events;
use Codeception\Test\Unit;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
class UI extends \PHPUnit\TextUI\ResultPrinter
{
/**
* @var EventDispatcher
*/
protected $dispatcher;
public function __construct(EventDispatcher $dispatcher, $options, $out = null)
{
parent::__construct($out, $options['verbosity'] > OutputInterface::VERBOSITY_NORMAL, $options['colors'] ? 'always' : 'never');
$this->dispatcher = $dispatcher;
}
protected function printDefect(\PHPUnit\Framework\TestFailure $defect, int $count): void
{
$this->write("\n---------\n");
$this->dispatcher->dispatch(
Events::TEST_FAIL_PRINT,
new FailEvent($defect->failedTest(), null, $defect->thrownException(), $count)
);
}
/**
* @param \PHPUnit\Framework\TestFailure $defect
*/
protected function printDefectTrace(\PHPUnit\Framework\TestFailure $defect): void
{
$this->write($defect->getExceptionAsString());
$this->writeNewLine();
$stackTrace = \PHPUnit\Util\Filter::getFilteredStacktrace($defect->thrownException());
foreach ($stackTrace as $i => $frame) {
if (!isset($frame['file'])) {
continue;
}
$this->write(
sprintf(
"#%d %s(%s)",
$i + 1,
$frame['file'],
isset($frame['line']) ? $frame['line'] : '?'
)
);
$this->writeNewLine();
}
}
public function startTest(\PHPUnit\Framework\Test $test) : void
{
if ($test instanceof Unit) {
parent::startTest($test);
}
}
public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
{
if ($test instanceof \PHPUnit\Framework\TestCase or $test instanceof \Codeception\Test\Test) {
$this->numAssertions += $test->getNumAssertions();
}
$this->lastTestFailed = false;
}
public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->lastTestFailed = true;
}
public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
{
$this->lastTestFailed = true;
}
public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time) : void
{
$this->lastTestFailed = true;
}
public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->lastTestFailed = true;
}
public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
{
$this->lastTestFailed = true;
}
}
<tr >
<td class="error">
{fail}
</td>
</tr>
\ No newline at end of file
<tr class="scenarioRow {scenarioStatus}">
<td>
<p class="{scenarioStatus}" onclick="showHide('{id}', this)">{toggle}
{name} <span style="color: #34495e; font-size: 70%;">{time}s</span></p>
</td>
</tr>
<tr class="scenarioRow {scenarioStatus}">
<td>
<table border="0" width="100%" class="{scenarioStatus} scenarioStepsTable" id="stepContainer{id}">
{steps}
{failure}
{png}
{html}
</table>
</td>
</tr>
<html>
<head>
<title>Test results</title>
<meta charset='utf-8'>
<link href='http://fonts.googleapis.com/css?family=Varela+Round&v2' rel='stylesheet' type='text/css'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.layout {
margin: 0 auto;
max-width: 1000px;
}
body { font-family: arial, serif; margin: 0; padding: 0; background: #ecf0f1; font-size: 20px; }
h1,h2,h3 { font-family: arial, serif; color: #7f8c8d; }
h1 { font-size: 2.5em; }
h2 { font-size: 1.3em; }
h3 { font-size: 1em; color: #84BBDD; margin: 0.5em 0; }
table { border: none; margin: 0; padding: 0; font-size: 0.9em;}
.scenarioStepsTable .stepName { padding: 5px; }
.scenarioStepsTable td {
background: #fff;
}
.quiet {
color: #333;
font-size: 0.8em;
}
.screenshot {
max-height: 400px;
overflow-y: scroll;
display: block;
}
.screenshot img {
zoom: 0.5;
}
@media (max-width: 1200px) {
#toolbar-filter {
display: none !important;
}
}
.scenarioStepsTable .nostyle {
background: none;
border: none;
}
p {
cursor: pointer;
}
.scenarioRow>td>p {
padding: 5px;
}
.scenarioStepsTable .failedStep {
padding: 10px;
background: #ecf0f1;
border: 2px solid #e74c3c;
border-radius: 0px;
color: #e74c3c;
}
.scenarioStepsTable .error {
background: #999;
padding: 10px;
color: #fff;
border-radius: 0px;
}
.scenarioStepsTable .error a {
color: #eef;
}
.scenarioStepsTable.substeps td {
background: #bdc3c7;
}
.header { font-size: large; font-weight: bold; }
p.scenarioSuccess {
background: rgb(157,213,58); /* Old browsers */
}
.scenario { color: black; }
p.scenarioFailed, p.scenarioError { color: black;
background: #e74c3c
}
table.scenarioFailed tr:last-child { font-weight: bold; }
td.scenarioSuccess { color: green }
td.scenarioFailed { color: red }
.scenarioSkipped { color: teal; }
.scenarioIncomplete { color: gray; }
.scenarioStepsTable { margin-left: 10px; display: none; color: #333; }
#stepContainerSummary {
background: white;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
padding: 20px;
}
.toggle {
background: rgba(255,255,255,0.5);
border-radius: 10px;
display: inline-block;
width: 20px;
height: 20px;
text-align: center;
margin: auto;
color: #666
}
ul#toolbar-filter {
display: block;
position: fixed;
top: 20px;
left: 0px;
padding: 0px;
}
ul#toolbar-filter li {
list-style: none;
text-align: center;
padding: 20px;
background-color: #3498db;
}
ul#toolbar-filter li a, ul#toolbar-filter li a:hover, ul#toolbar-filter li a:visited {
color: #34495e;
text-decoration: none;
}
ul#toolbar-filter li.disabled {
background-color: #bdc3c7;
}
</style>
<script type="text/javascript">
var showAll = true;
function showHide(nodeId, linkObj)
{
var subObj = document.getElementById('stepContainer' + nodeId);
var toggle = linkObj.childNodes[0];
if (toggle.innerHTML != '-') {
toggle.innerHTML = '-';
subObj.style.display='block';
subObj.style.width = '100%';
} else {
toggle.innerHTML = '+';
subObj.style.display='none';
}
}
function showAllScenarios() {
var toolbar = document.getElementById('toolbar-filter');
for (var i = 0; i < toolbar.children.length; i++) {
toolbar.children[i].className = '';
}
var trs = document.getElementsByTagName('tr');
for(var z = 0; z < trs.length; z++) {
trs[z].style.display = '';
}
showAll = true;
}
function toggleScenarios(name, linkObj) {
var links = document.getElementById('toolbar-filter').children;
var rows = document.getElementsByClassName('scenarioRow');
if (showAll) {
for (var i = 0; i < links.length; i++) {
links[i].className = 'disabled';
}
for (var i = 0; i < rows.length; i++) {
rows[i].style.display = 'none';
}
}
showAll = false;
if (linkObj.className == '') {
linkObj.className = 'disabled';
for (var i = 0; i < rows.length; i++) {
if (rows[i].classList.contains(name)) {
rows[i].style.display = 'none';
}
}
return;
}
if (linkObj.className == 'disabled') {
linkObj.className = '';
for (var i = 0; i < rows.length; i++) {
if (rows[i].classList.contains(name)) {
rows[i].style.display = 'table-row';
}
}
return;
}
}
</script>
</head>
<body>
<ul id="toolbar-filter">
<li> <a href="#" title="Show all" onClick="showAllScenarios()"></a></li>
<li> <a href="#" title="Successful" onClick="toggleScenarios('scenarioSuccess', this.parentElement)"><strong></strong> {successfulScenarios}</a></li>
<li> <a href="#" title="Failed" onClick="toggleScenarios('scenarioFailed', this.parentElement)"><strong></strong> {failedScenarios}</a></li>
<li> <a href="#" title="Skipped" onClick="toggleScenarios('scenarioSkipped', this.parentElement)"><strong>S</strong> {skippedScenarios}</a></li>
<li> <a href="#" title="Incomplete" onClick="toggleScenarios('scenarioIncomplete', this.parentElement)"><strong>I</strong> {incompleteScenarios}</a></li>
</ul>
<div class="layout">
{header}
<table border="0" style="width: 100%;">
{scenarios}
<tr>
<td>
<h2>Summary</h2>
<div id="stepContainerSummary">
<table border="0">
<tr>
<td width="250" class="scenarioSuccess">Successful scenarios:</td>
<td class="scenarioSuccessValue"><strong>{successfulScenarios}</strong></td>
</tr>
<tr>
<td class="scenarioFailed">Failed scenarios:</td>
<td class="scenarioFailedValue"><strong>{failedScenarios}</strong></td>
</tr>
<tr>
<td class="scenarioSkipped">Skipped scenarios:</td>
<td class="scenarioSkippedValue"><strong>{skippedScenarios}</strong></td>
</tr>
<tr>
<td class="scenarioIncomplete">Incomplete scenarios:</td>
<td class="scenarioIncompleteValue"><strong>{incompleteScenarios}</strong></td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</div>
</body>
</html>
<tr>
<td class="stepName {error}">&nbsp;&nbsp;&nbsp;&nbsp;{action}</td>
</tr>
<tr>
<td class="stepName {error}" ><p onclick="showHide('{id}', this)"><span class="toggle">+</span> {metaStep}</p>
</td>
</tr>
<tr>
<td class="nostyle">
<table border="0" width="100%" class="substeps scenarioStepsTable" id="stepContainer{id}">
{steps}
</table>
</td>
</tr>
<tr>
<td>
<h3>{suite} Tests</h3>
</td>
</tr>
\ No newline at end of file
<?php
namespace Codeception\PHPUnit;
use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;
use PHPUnit\Framework\TestSuite;
class Runner extends \PHPUnit\TextUI\TestRunner
{
public static $persistentListeners = [];
protected $defaultListeners = [
'xml' => false,
'html' => false,
'tap' => false,
'json' => false,
'report' => false
];
protected $config = [];
protected $logDir = null;
public function __construct()
{
$this->config = Configuration::config();
$this->logDir = Configuration::outputDir(); // prepare log dir
$this->phpUnitOverriders();
parent::__construct();
}
public function phpUnitOverriders()
{
require_once __DIR__ . DIRECTORY_SEPARATOR . 'Overrides/Filter.php';
}
/**
* @return null|\PHPUnit\TextUI\ResultPrinter
*/
public function getPrinter()
{
return $this->printer;
}
public function prepareSuite(\PHPUnit\Framework\Test $suite, array &$arguments)
{
$this->handleConfiguration($arguments);
$filterAdded = false;
$filterFactory = new \PHPUnit\Runner\Filter\Factory();
if ($arguments['groups']) {
$filterAdded = true;
$filterFactory->addFilter(
new \ReflectionClass('PHPUnit\Runner\Filter\IncludeGroupFilterIterator'),
$arguments['groups']
);
}
if ($arguments['excludeGroups']) {
$filterAdded = true;
$filterFactory->addFilter(
new \ReflectionClass('PHPUnit\Runner\Filter\ExcludeGroupFilterIterator'),
$arguments['excludeGroups']
);
}
if ($arguments['filter']) {
$filterAdded = true;
$filterFactory->addFilter(
new \ReflectionClass('Codeception\PHPUnit\FilterTest'),
$arguments['filter']
);
}
if ($filterAdded) {
$suite->injectFilter($filterFactory);
}
}
public function doEnhancedRun(
\PHPUnit\Framework\Test $suite,
\PHPUnit\Framework\TestResult $result,
array $arguments = []
) {
unset($GLOBALS['app']); // hook for not to serialize globals
$result->convertErrorsToExceptions(false);
if (isset($arguments['report_useless_tests'])) {
$result->beStrictAboutTestsThatDoNotTestAnything((bool)$arguments['report_useless_tests']);
}
if (isset($arguments['disallow_test_output'])) {
$result->beStrictAboutOutputDuringTests((bool)$arguments['disallow_test_output']);
}
if (empty(self::$persistentListeners)) {
$this->applyReporters($result, $arguments);
}
if (class_exists('\Symfony\Bridge\PhpUnit\SymfonyTestsListener')) {
$arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : [];
$arguments['listeners'][] = new \Symfony\Bridge\PhpUnit\SymfonyTestsListener();
}
$arguments['listeners'][] = $this->printer;
// clean up listeners between suites
foreach ($arguments['listeners'] as $listener) {
$result->addListener($listener);
}
$suite->run($result);
unset($suite);
foreach ($arguments['listeners'] as $listener) {
$result->removeListener($listener);
}
return $result;
}
/**
* @param \PHPUnit\Framework\TestResult $result
* @param array $arguments
*
* @return array
*/
protected function applyReporters(\PHPUnit\Framework\TestResult $result, array $arguments)
{
foreach ($this->defaultListeners as $listener => $value) {
if (!isset($arguments[$listener])) {
$arguments[$listener] = $value;
}
}
if ($arguments['report']) {
self::$persistentListeners[] = $this->instantiateReporter('report');
}
if ($arguments['html']) {
codecept_debug('Printing HTML report into ' . $arguments['html']);
self::$persistentListeners[] = $this->instantiateReporter(
'html',
[$this->absolutePath($arguments['html'])]
);
}
if ($arguments['xml']) {
codecept_debug('Printing JUNIT report into ' . $arguments['xml']);
self::$persistentListeners[] = $this->instantiateReporter(
'xml',
[$this->absolutePath($arguments['xml']), (bool)$arguments['log_incomplete_skipped']]
);
}
if ($arguments['tap']) {
codecept_debug('Printing TAP report into ' . $arguments['tap']);
self::$persistentListeners[] = $this->instantiateReporter('tap', [$this->absolutePath($arguments['tap'])]);
}
if ($arguments['json']) {
codecept_debug('Printing JSON report into ' . $arguments['json']);
self::$persistentListeners[] = $this->instantiateReporter(
'json',
[$this->absolutePath($arguments['json'])]
);
}
foreach (self::$persistentListeners as $listener) {
if ($listener instanceof ConsolePrinter) {
$this->printer = $listener;
continue;
}
$result->addListener($listener);
}
}
protected function instantiateReporter($name, $args = [])
{
if (!isset($this->config['reporters'][$name])) {
throw new ConfigurationException("Reporter $name not defined");
}
return (new \ReflectionClass($this->config['reporters'][$name]))->newInstanceArgs($args);
}
private function absolutePath($path)
{
if ((strpos($path, '/') === 0) or (strpos($path, ':') === 1)) { // absolute path
return $path;
}
return $this->logDir . $path;
}
}
This diff is collapsed.
<?php
// @codingStandardsIgnoreStart
// PHPUnit 6 compatibility
namespace PHPUnit\Framework {
if (!interface_exists(Test::class, false)) {
interface Test extends \Countable {
public function run(TestResult $result = null);
}
}
if (!interface_exists(SelfDescribing::class, false)) {
interface SelfDescribing
{
public function toString();
}
}
}
// @codingStandardsIgnoreEnd
<?php
// @codingStandardsIgnoreStart
// Add aliases for PHPUnit 6
namespace {
if (!class_exists('PHPUnit_Framework_Assert')) {
class_alias('PHPUnit\Framework\Assert', 'PHPUnit_Framework_Assert');
}
if (!class_exists('PHPUnit_Framework_TestCase')) {
class_alias('PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase');
}
if (!class_exists('PHPUnit\Util\Log\JSON') || !class_exists('PHPUnit\Util\Log\TAP')) {
if (class_exists('PHPUnit\Util\Printer')) {
require_once __DIR__ . '/phpunit5-loggers.php'; // TAP and JSON loggers were removed in PHPUnit 6
}
}
}
// @codingStandardsIgnoreEnd
.idea/
/vendor/
composer.lock
\ No newline at end of file
language: php
php:
- 5.4
- 5.5
- 5.6
- 7
- 7.1
- 7.2
cache:
directories:
- vendor
- $HOME/.composer/cache
sudo: false
before_install:
- composer update --prefer-source
script: vendor/bin/phpunit tests
\ No newline at end of file
# Codeception\Stub
[![Build Status](https://travis-ci.org/Codeception/Stub.svg?branch=master)](https://travis-ci.org/Codeception/Stub)
[![Latest Stable Version](https://poser.pugx.org/codeception/stub/v/stable)](https://packagist.org/packages/codeception/stub)
[![Total Downloads](https://poser.pugx.org/codeception/stub/downloads)](https://packagist.org/packages/codeception/stub)
[![License](https://poser.pugx.org/codeception/stub/license)](https://packagist.org/packages/codeception/stub)
Library on top of PHPUnit's mock builder providing a highly simplified syntax:
## Reference
* [Stub](https://github.com/Codeception/Stub/blob/master/docs/Stub.md) - creating stub classes using static methods
* [Stub Trait](https://github.com/Codeception/Stub/blob/master/docs/StubTrait.md) - creating stubs and mocks using trait
* [Expected](https://github.com/Codeception/Stub/blob/master/docs/Expected.md) - defining expectations for mocks
## Install
Enabled by default in Codeception.
For PHPUnit install this package:
```
composer require codeception/stub --dev
```
## Stubs
Stubs can be constructed with `Codeception\Stub` static calls:
```php
<?php
// create a stub with find method replaced
$userRepository = Stub::make(UserRepository::class, ['find' => new User]);
$userRepository->find(1); // => User
// create a dummy
$userRepository = Stub::makeEmpty(UserRepository::class);
// create a stub with all methods replaced except one
$user = Stub::makeEmptyExcept(User::class, 'validate');
$user->validate($data);
// create a stub by calling constructor and replacing a method
$user = Stub::construct(User::class, ['name' => 'davert'], ['save' => false]);
// create a stub by calling constructor with empty methods
$user = Stub::constructEmpty(User::class, ['name' => 'davert']);
// create a stub by calling constructor with empty methods
$user = Stub::constructEmptyExcept(User::class, 'getName', ['name' => 'davert']);
$user->getName(); // => davert
$user->setName('jane'); // => this method is empty
$user->getName(); // => davert
```
[See complete reference](https://github.com/Codeception/Stub/blob/master/docs/Stub.md)
Alternatively, stubs can be created by using [`Codeception\Test\Feature\Stub` trait](https://github.com/Codeception/Stub/blob/master/docs/StubTrait.md):
```php
<?php
$this->make(UserRepositry::class);
$this->makeEmpty(UserRepositry::class);
$this->construct(UserRepositry::class);
$this->constructEmpty(UserRepositry::class);
// ...
```
## Mocks
Mocks should be created by including [`Codeception\Test\Feature\Stub` trait](https://github.com/Codeception/Stub/blob/master/docs/StubTrait.md) into a test case.
Execution expectation are set with [`Codescption\Stub\Expected`](https://github.com/Codeception/Stub/blob/master/docs/Expected.md):
```php
<?php
// find should be never called
$userRepository = $this->make(UserRepository::class, [
'find' => Codeception\Stub\Expected::never()
]);
// find should be called once and return a new user
$userRepository = $this->make(UserRepository::class, [
'find' => Codeception\Stub\Expected::once(new User)
]);
```
## License
MIT
\ No newline at end of file
<?php
require_once 'vendor/autoload.php';
/**
* This is project's console commands configuration for Robo task runner.
*
* @see http://robo.li/
*/
class RoboFile extends \Robo\Tasks
{
protected $docs = [
'docs/Stub.md' => 'Codeception\Stub',
'docs/Expected.md' => 'Codeception\Stub\Expected',
'docs/StubTrait.md' => 'Codeception\Test\Feature\Stub',
];
public function docs()
{
foreach ($this->docs as $file => $class) {
if (!class_exists($class, true) && !trait_exists($class, true)) {
throw new Exception('ups');
}
$this->say("Here goes, $class");
$this->taskGenDoc($file)
->docClass($class)
->filterMethods(function(\ReflectionMethod $method) {
if ($method->isConstructor() or $method->isDestructor()) return false;
if (!$method->isPublic()) return false;
if (strpos($method->name, '_') === 0) return false;
if (strpos($method->name, 'stub') === 0) return false;
return true;
})
->processMethodDocBlock(
function (\ReflectionMethod $m, $doc) {
$doc = str_replace(array('@since'), array(' * available since version'), $doc);
$doc = str_replace(array(' @', "\n@"), array(" * ", "\n * "), $doc);
return $doc;
})
->processProperty(false)
->run();
}
}
}
\ No newline at end of file
{
"name": "codeception/stub",
"description":"Flexible Stub wrapper for PHPUnit's Mock Builder",
"type": "library",
"license":"MIT",
"minimum-stability": "stable",
"autoload": {
"psr-4": {
"Codeception\\": "src/"
}
},
"require": {
"phpunit/phpunit-mock-objects": ">2.3 <7.0"
},
"require-dev": {
"phpunit/phpunit": ">=4.8 <8.0"
}
}
## Codeception\Stub\Expected
#### *public static* never($params = null)
Checks if a method never has been invoked
If method invoked, it will immediately throw an
exception.
```php
<?php
use \Codeception\Stub\Expected;
$user = $this->make('User', [
'getName' => Expected::never(),
'someMethod' => function() {}
]);
$user->someMethod();
?>
```
* `param mixed` $params
* return StubMarshaler
#### *public static* once($params = null)
Checks if a method has been invoked exactly one
time.
If the number is less or greater it will later be checked in verify() and also throw an
exception.
```php
<?php
use \Codeception\Stub\Expected;
$user = $this->make(
'User',
array(
'getName' => Expected::once('Davert'),
'someMethod' => function() {}
)
);
$userName = $user->getName();
$this->assertEquals('Davert', $userName);
?>
```
Alternatively, a function can be passed as parameter:
```php
<?php
Expected::once(function() { return Faker::name(); });
```
* `param mixed` $params
* return StubMarshaler
#### *public static* atLeastOnce($params = null)
Checks if a method has been invoked at least one
time.
If the number of invocations is 0 it will throw an exception in verify.
```php
<?php
use \Codeception\Stub\Expected;
$user = $this->make(
'User',
array(
'getName' => Expected::atLeastOnce('Davert')),
'someMethod' => function() {}
)
);
$user->getName();
$userName = $user->getName();
$this->assertEquals('Davert', $userName);
?>
```
Alternatively, a function can be passed as parameter:
```php
<?php
Expected::atLeastOnce(function() { return Faker::name(); });
```
* `param mixed` $params
* return StubMarshaler
#### *public static* exactly($count, $params = null)
Checks if a method has been invoked a certain amount
of times.
If the number of invocations exceeds the value it will immediately throw an
exception,
If the number is less it will later be checked in verify() and also throw an
exception.
``` php
<?php
use \Codeception\Stub;
use \Codeception\Stub\Expected;
$user = $this->make(
'User',
array(
'getName' => Expected::exactly(3, 'Davert'),
'someMethod' => function() {}
)
);
$user->getName();
$user->getName();
$userName = $user->getName();
$this->assertEquals('Davert', $userName);
?>
```
Alternatively, a function can be passed as parameter:
```php
<?php
Expected::exactly(function() { return Faker::name() });
```
* `param int` $count
* `param mixed` $params
* return StubMarshaler
## Codeception\Stub
#### *public static* make($class, $params = null, $testCase = null)
Instantiates a class without executing a constructor.
Properties and methods can be set as a second parameter.
Even protected and private properties can be set.
``` php
<?php
Stub::make('User');
Stub::make('User', ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
Stub::make(new User, ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
Stub::make('User', ['save' => function () { return true; }]);
Stub::make('User', ['save' => true]);
?>
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
Stub::make('User', [
'save' => \Codeception\Stub\Expected::once()
], $this);
```
* `param mixed` $class - A class to be mocked
* `param array` $params - properties and methods to set
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object - mock
* throws \RuntimeException when class does not exist
* throws \Exception
#### *public static* factory($class, $num = null, $params = null)
Creates $num instances of class through `Stub::make`.
* `param mixed` $class
* `param int` $num
* `param array` $params
* return array
* throws \Exception
#### *public static* makeEmptyExcept($class, $method, $params = null, $testCase = null)
Instantiates class having all methods replaced with dummies except one.
Constructor is not triggered.
Properties and methods can be replaced.
Even protected and private properties can be set.
``` php
<?php
Stub::makeEmptyExcept('User', 'save');
Stub::makeEmptyExcept('User', 'save', ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
* Stub::makeEmptyExcept(new User, 'save');
?>
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
Stub::makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
Stub::makeEmptyExcept('User', 'save', ['isValid' => true]);
?>
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
Stub::makeEmptyExcept('User', 'validate', [
'save' => \Codeception\Stub\Expected::once()
], $this);
```
* `param mixed` $class
* `param string` $method
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object
* throws \Exception
#### *public static* makeEmpty($class, $params = null, $testCase = null)
Instantiates class having all methods replaced with dummies.
Constructor is not triggered.
Properties and methods can be set as a second parameter.
Even protected and private properties can be set.
``` php
<?php
Stub::makeEmpty('User');
Stub::makeEmpty('User', ['name' => 'davert']);
```
Accepts either name of class or object of that class
``` php
<?php
Stub::makeEmpty(new User, ['name' => 'davert']);
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
Stub::makeEmpty('User', ['save' => function () { return true; }]);
Stub::makeEmpty('User', ['save' => true));
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
Stub::makeEmpty('User', [
'save' => \Codeception\Stub\Expected::once()
], $this);
```
* `param mixed` $class
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object
* throws \Exception
#### *public static* copy($obj, $params = null)
Clones an object and redefines it's properties (even protected and private)
* `param` $obj
* `param array` $params
* return mixed
* throws \Exception
#### *public static* construct($class, $constructorParams = null, $params = null, $testCase = null)
Instantiates a class instance by running constructor.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
Stub::construct('User', ['autosave' => false]);
Stub::construct('User', ['autosave' => false], ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
Stub::construct(new User, ['autosave' => false), ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
Stub::construct('User', [], ['save' => function () { return true; }]);
Stub::construct('User', [], ['save' => true]);
?>
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
Stub::construct('User', [], [
'save' => \Codeception\Stub\Expected::once()
], $this);
```
* `param mixed` $class
* `param array` $constructorParams
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object
* throws \Exception
#### *public static* constructEmpty($class, $constructorParams = null, $params = null, $testCase = null)
Instantiates a class instance by running constructor with all methods replaced with dummies.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
Stub::constructEmpty('User', ['autosave' => false]);
Stub::constructEmpty('User', ['autosave' => false), ['name' => 'davert']);
```
Accepts either name of class or object of that class
``` php
<?php
Stub::constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
Stub::constructEmpty('User', [], ['save' => function () { return true; }]);
Stub::constructEmpty('User', [], ['save' => true]);
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
Stub::constructEmpty('User', [], [
'save' => \Codeception\Stub\Expected::once()
], $this);
```
* `param mixed` $class
* `param array` $constructorParams
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object
#### *public static* constructEmptyExcept($class, $method, $constructorParams = null, $params = null, $testCase = null)
Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
Stub::constructEmptyExcept('User', 'save');
Stub::constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
Stub::constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
Stub::constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
Stub::constructEmptyExcept('User', 'save', [], ['save' => true]);
?>
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
Stub::constructEmptyExcept('User', 'save', [], [
'save' => \Codeception\Stub\Expected::once()
], $this);
```
* `param mixed` $class
* `param string` $method
* `param array` $constructorParams
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object
#### *public static* update($mock, array $params)
Replaces properties of current stub
* `param \PHPUnit\Framework\MockObject\MockObject` $mock
* `param array` $params
* return mixed
* throws \LogicException
#### *public static* consecutive()
Stubbing a method call to return a list of values in the specified order.
``` php
<?php
$user = Stub::make('User', array('getName' => Stub::consecutive('david', 'emma', 'sam', 'amy')));
$user->getName(); //david
$user->getName(); //emma
$user->getName(); //sam
$user->getName(); //amy
?>
```
* return ConsecutiveMap
## Codeception\Test\Feature\Stub
### Usage in Codeception
Since Codeception 2.3.8 this trait is enabled in `\Codeception\Test\Unit` class.
### Usage in PHPUnit
Include this trait into a TestCase to be able to use Stubs and Mocks:
```php
<?php
class MyTest extends \PHPUnit\Framework\TestCase
{
use Codeception\Test\Feature\Stub;
}
```
#### *public* make($class, $params = null)
Instantiates a class without executing a constructor.
Properties and methods can be set as a second parameter.
Even protected and private properties can be set.
``` php
<?php
$this->make('User');
$this->make('User', ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
$this->make(new User, ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
$this->make('User', ['save' => function () { return true; }]);
$this->make('User', ['save' => true]);
```
* `param mixed` $class - A class to be mocked
* `param array` $params - properties and methods to set
* return object - mock
* throws \RuntimeException when class does not exist
* throws \Exception
#### *public* makeEmpty($class, $params = null)
Instantiates class having all methods replaced with dummies.
Constructor is not triggered.
Properties and methods can be set as a second parameter.
Even protected and private properties can be set.
``` php
<?php
$this->makeEmpty('User');
$this->makeEmpty('User', ['name' => 'davert']);
```
Accepts either name of class or object of that class
``` php
<?php
$this->makeEmpty(new User, ['name' => 'davert']);
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
$this->makeEmpty('User', ['save' => function () { return true; }]);
$this->makeEmpty('User', ['save' => true));
```
* `param mixed` $class
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object
* throws \Exception
#### *public* makeEmptyExcept($class, $method, $params = null)
Instantiates class having all methods replaced with dummies except one.
Constructor is not triggered.
Properties and methods can be replaced.
Even protected and private properties can be set.
``` php
<?php
$this->makeEmptyExcept('User', 'save');
$this->makeEmptyExcept('User', 'save', ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
* $this->makeEmptyExcept(new User, 'save');
?>
```
To replace method provide it's name as a key in second parameter
and it's return value or callback function as parameter
``` php
<?php
$this->makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
$this->makeEmptyExcept('User', 'save', ['isValid' => true]);
```
* `param mixed` $class
* `param string` $method
* `param array` $params
* return object
* throws \Exception
#### *public* construct($class, $constructorParams = null, $params = null)
Instantiates a class instance by running constructor.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
$this->construct('User', ['autosave' => false]);
$this->construct('User', ['autosave' => false], ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
$this->construct(new User, ['autosave' => false), ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
$this->construct('User', [], ['save' => function () { return true; }]);
$this->construct('User', [], ['save' => true]);
?>
```
* `param mixed` $class
* `param array` $constructorParams
* `param array` $params
* `param bool|\PHPUnit\Framework\TestCase` $testCase
* return object
* throws \Exception
#### *public* constructEmpty($class, $constructorParams = null, $params = null)
Instantiates a class instance by running constructor with all methods replaced with dummies.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
$this->constructEmpty('User', ['autosave' => false]);
$this->constructEmpty('User', ['autosave' => false), ['name' => 'davert']);
```
Accepts either name of class or object of that class
``` php
<?php
$this->constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
$this->constructEmpty('User', array(), array('save' => function () { return true; }));
$this->constructEmpty('User', array(), array('save' => true));
```
**To create a mock, pass current testcase name as last argument:**
```php
<?php
$this->constructEmpty('User', [], [
'save' => \Codeception\Stub\Expected::once()
]);
```
* `param mixed` $class
* `param array` $constructorParams
* `param array` $params
* return object
#### *public* constructEmptyExcept($class, $method, $constructorParams = null, $params = null)
Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
Parameters for constructor passed as second argument
Properties and methods can be set in third argument.
Even protected and private properties can be set.
``` php
<?php
$this->constructEmptyExcept('User', 'save');
$this->constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
?>
```
Accepts either name of class or object of that class
``` php
<?php
$this->constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
?>
```
To replace method provide it's name as a key in third parameter
and it's return value or callback function as parameter
``` php
<?php
$this->constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
$this->constructEmptyExcept('User', 'save', [], ['save' => true]);
?>
```
* `param mixed` $class
* `param string` $method
* `param array` $constructorParams
* `param array` $params
* return object
This diff is collapsed.
<?php
namespace Codeception\Stub;
/**
* Holds matcher and value of mocked method
*/
class ConsecutiveMap
{
private $consecutiveMap = [];
public function __construct(array $consecutiveMap)
{
$this->consecutiveMap = $consecutiveMap;
}
public function getMap()
{
return $this->consecutiveMap;
}
}
\ No newline at end of file
<?php
namespace Codeception\Stub;
require_once __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'shim.php';
use PHPUnit\Framework\MockObject\Matcher\InvokedAtLeastOnce;
use PHPUnit\Framework\MockObject\Matcher\InvokedCount;
class Expected
{
/**
* Checks if a method never has been invoked
*
* If method invoked, it will immediately throw an
* exception.
*
* ```php
* <?php
* use \Codeception\Stub\Expected;
*
* $user = $this->make('User', [
* 'getName' => Expected::never(),
* 'someMethod' => function() {}
* ]);
* $user->someMethod();
* ?>
* ```
*
* @param mixed $params
* @return StubMarshaler
*/
public static function never($params = null)
{
return new StubMarshaler(
new InvokedCount(0),
self::closureIfNull($params)
);
}
/**
* Checks if a method has been invoked exactly one
* time.
*
* If the number is less or greater it will later be checked in verify() and also throw an
* exception.
*
* ```php
* <?php
* use \Codeception\Stub\Expected;
*
* $user = $this->make(
* 'User',
* array(
* 'getName' => Expected::once('Davert'),
* 'someMethod' => function() {}
* )
* );
* $userName = $user->getName();
* $this->assertEquals('Davert', $userName);
* ?>
* ```
* Alternatively, a function can be passed as parameter:
*
* ```php
* <?php
* Expected::once(function() { return Faker::name(); });
* ```
*
* @param mixed $params
*
* @return StubMarshaler
*/
public static function once($params = null)
{
return new StubMarshaler(
new InvokedCount(1),
self::closureIfNull($params)
);
}
/**
* Checks if a method has been invoked at least one
* time.
*
* If the number of invocations is 0 it will throw an exception in verify.
*
* ```php
* <?php
* use \Codeception\Stub\Expected;
*
* $user = $this->make(
* 'User',
* array(
* 'getName' => Expected::atLeastOnce('Davert')),
* 'someMethod' => function() {}
* )
* );
* $user->getName();
* $userName = $user->getName();
* $this->assertEquals('Davert', $userName);
* ?>
* ```
*
* Alternatively, a function can be passed as parameter:
*
* ```php
* <?php
* Expected::atLeastOnce(function() { return Faker::name(); });
* ```
*
* @param mixed $params
*
* @return StubMarshaler
*/
public static function atLeastOnce($params = null)
{
return new StubMarshaler(
new InvokedAtLeastOnce(),
self::closureIfNull($params)
);
}
/**
* Checks if a method has been invoked a certain amount
* of times.
* If the number of invocations exceeds the value it will immediately throw an
* exception,
* If the number is less it will later be checked in verify() and also throw an
* exception.
*
* ``` php
* <?php
* use \Codeception\Stub;
* use \Codeception\Stub\Expected;
*
* $user = $this->make(
* 'User',
* array(
* 'getName' => Expected::exactly(3, 'Davert'),
* 'someMethod' => function() {}
* )
* );
* $user->getName();
* $user->getName();
* $userName = $user->getName();
* $this->assertEquals('Davert', $userName);
* ?>
* ```
* Alternatively, a function can be passed as parameter:
*
* ```php
* <?php
* Expected::exactly(function() { return Faker::name() });
* ```
*
* @param int $count
* @param mixed $params
*
* @return StubMarshaler
*/
public static function exactly($count, $params = null)
{
return new StubMarshaler(
new InvokedCount($count),
self::closureIfNull($params)
);
}
private static function closureIfNull($params)
{
if ($params instanceof \Closure) {
return $params;
}
return function() use ($params) {
return $params;
};
}
}
\ No newline at end of file
<?php
namespace Codeception\Stub;
use PHPUnit\Framework\MockObject\Matcher\InvokedRecorder;
/**
* Holds matcher and value of mocked method
*/
class StubMarshaler
{
private $methodMatcher;
private $methodValue;
public function __construct(InvokedRecorder $matcher, $value)
{
$this->methodMatcher = $matcher;
$this->methodValue = $value;
}
public function getMatcher()
{
return $this->methodMatcher;
}
public function getValue()
{
return $this->methodValue;
}
}
<?php
namespace Codeception\Test\Feature;
/**
* ### Usage in Codeception
*
* Since Codeception 2.3.8 this trait is enabled in `\Codeception\Test\Unit` class.
*
* ### Usage in PHPUnit
*
* Include this trait into a TestCase to be able to use Stubs and Mocks:
*
* ```php
* <?php
* class MyTest extends \PHPUnit\Framework\TestCase
* {
* use Codeception\Test\Feature\Stub;
* }
* ```
*/
trait Stub
{
private $mocks;
protected function stubStart()
{
if ($this instanceof \PHPUnit\Framework\TestCase) {
return;
}
$this->mocks = [];
}
protected function stubEnd($status, $time)
{
if ($this instanceof \PHPUnit\Framework\TestCase) {
return;
}
if ($status !== 'ok') { // Codeception status
return;
}
foreach ($this->mocks as $mockObject) {
if ($mockObject->__phpunit_hasMatchers()) {
$this->assertTrue(true); // incrementing assertions
}
$mockObject->__phpunit_verify(true);
}
}
/**
* Instantiates a class without executing a constructor.
* Properties and methods can be set as a second parameter.
* Even protected and private properties can be set.
*
* ``` php
* <?php
* $this->make('User');
* $this->make('User', ['name' => 'davert']);
* ?>
* ```
*
* Accepts either name of class or object of that class
*
* ``` php
* <?php
* $this->make(new User, ['name' => 'davert']);
* ?>
* ```
*
* To replace method provide it's name as a key in second parameter
* and it's return value or callback function as parameter
*
* ``` php
* <?php
* $this->make('User', ['save' => function () { return true; }]);
* $this->make('User', ['save' => true]);
* ```
*
* @param mixed $class - A class to be mocked
* @param array $params - properties and methods to set
*
* @return object - mock
* @throws \RuntimeException when class does not exist
* @throws \Exception
*/
public function make($class, $params = [])
{
return $this->mocks[] = \Codeception\Stub::make($class, $params, $this);
}
/**
* Instantiates class having all methods replaced with dummies.
* Constructor is not triggered.
* Properties and methods can be set as a second parameter.
* Even protected and private properties can be set.
*
* ``` php
* <?php
* $this->makeEmpty('User');
* $this->makeEmpty('User', ['name' => 'davert']);
* ```
*
* Accepts either name of class or object of that class
*
* ``` php
* <?php
* $this->makeEmpty(new User, ['name' => 'davert']);
* ```
*
* To replace method provide it's name as a key in second parameter
* and it's return value or callback function as parameter
*
* ``` php
* <?php
* $this->makeEmpty('User', ['save' => function () { return true; }]);
* $this->makeEmpty('User', ['save' => true));
* ```
*
* @param mixed $class
* @param array $params
* @param bool|\PHPUnit\Framework\TestCase $testCase
*
* @return object
* @throws \Exception
*/
public function makeEmpty($class, $params = [])
{
return $this->mocks[] = \Codeception\Stub::makeEmpty($class, $params, $this);
}
/**
* Instantiates class having all methods replaced with dummies except one.
* Constructor is not triggered.
* Properties and methods can be replaced.
* Even protected and private properties can be set.
*
* ``` php
* <?php
* $this->makeEmptyExcept('User', 'save');
* $this->makeEmptyExcept('User', 'save', ['name' => 'davert']);
* ?>
* ```
*
* Accepts either name of class or object of that class
*
* ``` php
* <?php
* * $this->makeEmptyExcept(new User, 'save');
* ?>
* ```
*
* To replace method provide it's name as a key in second parameter
* and it's return value or callback function as parameter
*
* ``` php
* <?php
* $this->makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
* $this->makeEmptyExcept('User', 'save', ['isValid' => true]);
* ```
*
* @param mixed $class
* @param string $method
* @param array $params
*
* @return object
* @throws \Exception
*/
public function makeEmptyExcept($class, $method, $params = [])
{
return $this->mocks[] = \Codeception\Stub::makeEmptyExcept($class, $method, $params, $this);
}
/**
* Instantiates a class instance by running constructor.
* Parameters for constructor passed as second argument
* Properties and methods can be set in third argument.
* Even protected and private properties can be set.
*
* ``` php
* <?php
* $this->construct('User', ['autosave' => false]);
* $this->construct('User', ['autosave' => false], ['name' => 'davert']);
* ?>
* ```
*
* Accepts either name of class or object of that class
*
* ``` php
* <?php
* $this->construct(new User, ['autosave' => false), ['name' => 'davert']);
* ?>
* ```
*
* To replace method provide it's name as a key in third parameter
* and it's return value or callback function as parameter
*
* ``` php
* <?php
* $this->construct('User', [], ['save' => function () { return true; }]);
* $this->construct('User', [], ['save' => true]);
* ?>
* ```
*
* @param mixed $class
* @param array $constructorParams
* @param array $params
* @param bool|\PHPUnit\Framework\TestCase $testCase
*
* @return object
* @throws \Exception
*/
public function construct($class, $constructorParams = [], $params = [])
{
return $this->mocks[] = \Codeception\Stub::construct($class, $constructorParams, $params, $this);
}
/**
* Instantiates a class instance by running constructor with all methods replaced with dummies.
* Parameters for constructor passed as second argument
* Properties and methods can be set in third argument.
* Even protected and private properties can be set.
*
* ``` php
* <?php
* $this->constructEmpty('User', ['autosave' => false]);
* $this->constructEmpty('User', ['autosave' => false), ['name' => 'davert']);
* ```
*
* Accepts either name of class or object of that class
*
* ``` php
* <?php
* $this->constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
* ```
*
* To replace method provide it's name as a key in third parameter
* and it's return value or callback function as parameter
*
* ``` php
* <?php
* $this->constructEmpty('User', array(), array('save' => function () { return true; }));
* $this->constructEmpty('User', array(), array('save' => true));
* ```
*
* **To create a mock, pass current testcase name as last argument:**
*
* ```php
* <?php
* $this->constructEmpty('User', [], [
* 'save' => \Codeception\Stub\Expected::once()
* ]);
* ```
*
* @param mixed $class
* @param array $constructorParams
* @param array $params
*
* @return object
*/
public function constructEmpty($class, $constructorParams = [], $params = [])
{
return $this->mocks[] = \Codeception\Stub::constructEmpty($class, $constructorParams, $params, $this);
}
/**
* Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
* Parameters for constructor passed as second argument
* Properties and methods can be set in third argument.
* Even protected and private properties can be set.
*
* ``` php
* <?php
* $this->constructEmptyExcept('User', 'save');
* $this->constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
* ?>
* ```
*
* Accepts either name of class or object of that class
*
* ``` php
* <?php
* $this->constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
* ?>
* ```
*
* To replace method provide it's name as a key in third parameter
* and it's return value or callback function as parameter
*
* ``` php
* <?php
* $this->constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
* $this->constructEmptyExcept('User', 'save', [], ['save' => true]);
* ?>
* ```
*
* @param mixed $class
* @param string $method
* @param array $constructorParams
* @param array $params
*
* @return object
*/
public function constructEmptyExcept($class, $method, $constructorParams = [], $params = [])
{
return $this->mocks[] = \Codeception\Stub::constructEmptyExcept($class, $method, $constructorParams, $params, $this);
}
}
\ No newline at end of file
<?php
if (!class_exists('PHPUnit\Framework\TestCase') && class_exists('PHPUnit_Framework_TestCase')) {
class_alias('PHPUnit_Framework_TestCase', 'PHPUnit'.'\Framework\TestCase');
}
if (!class_exists('PHPUnit\Runner\Version')) {
class_alias('PHPUnit_Runner_Version', 'PHPUnit\Runner\Version');
}
if (class_exists('PHPUnit_Framework_MockObject_Generator')) {
class_alias('PHPUnit_Framework_MockObject_Generator', 'PHPUnit\Framework\MockObject\Generator');
class_alias('PHPUnit_Framework_MockObject_InvocationMocker', 'PHPUnit\Framework\MockObject\InvocationMocker');
class_alias('PHPUnit_Framework_MockObject_Invokable', 'PHPUnit\Framework\MockObject\Invokable');
class_alias('PHPUnit_Framework_MockObject_Matcher', 'PHPUnit\Framework\MockObject\Matcher');
class_alias('PHPUnit_Framework_MockObject_MockBuilder', 'PHPUnit\Framework\MockObject\MockBuilder');
if (interface_exists('PHPUnit_Framework_MockObject_MockObject')) {
/*
* old name still exists in https://github.com/sebastianbergmann/phpunit-mock-objects/blob/master/src/MockObject.php
* but namespaced alias is provided by https://github.com/sebastianbergmann/phpunit-mock-objects/blob/master/src/ForwardCompatibility/MockObject.php
*/
class_alias('PHPUnit_Framework_MockObject_MockObject', 'PHPUnit\Framework\MockObject\MockObject');
}
class_alias('PHPUnit_Framework_MockObject_Stub', 'PHPUnit\Framework\MockObject\Stub');
class_alias('PHPUnit_Framework_MockObject_Verifiable', 'PHPUnit\Framework\MockObject\Verifiable');
class_alias('PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount', 'PHPUnit\Framework\MockObject\Matcher\AnyInvokedCount');
class_alias('PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters', 'PHPUnit\Framework\MockObject\Matcher\ConsecutiveParameters');
class_alias('PHPUnit_Framework_MockObject_Matcher_Invocation', 'PHPUnit\Framework\MockObject\Matcher\Invocation');
class_alias('PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex', 'PHPUnit\Framework\MockObject\Matcher\InvokedAtIndex');
class_alias('PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastCount', 'PHPUnit\Framework\MockObject\Matcher\InvokedAtLeastCount');
class_alias('PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce', 'PHPUnit\Framework\MockObject\Matcher\InvokedAtLeastOnce');
class_alias('PHPUnit_Framework_MockObject_Matcher_InvokedAtMostCount', 'PHPUnit\Framework\MockObject\Matcher\InvokedAtMostCount');
class_alias('PHPUnit_Framework_MockObject_Matcher_InvokedCount', 'PHPUnit\Framework\MockObject\Matcher\InvokedCount');
class_alias('PHPUnit_Framework_MockObject_Matcher_InvokedRecorder', 'PHPUnit\Framework\MockObject\Matcher\InvokedRecorder');
class_alias('PHPUnit_Framework_MockObject_Matcher_MethodName', 'PHPUnit\Framework\MockObject\Matcher\MethodName');
class_alias('PHPUnit_Framework_MockObject_Matcher_Parameters', 'PHPUnit\Framework\MockObject\Matcher\Parameters');
class_alias('PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls', 'PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls');
class_alias('PHPUnit_Framework_MockObject_Stub_Exception', 'PHPUnit\Framework\MockObject\Stub\Exception');
class_alias('PHPUnit_Framework_MockObject_Stub_ReturnArgument', 'PHPUnit\Framework\MockObject\Stub\ReturnArgument');
class_alias('PHPUnit_Framework_MockObject_Stub_ReturnCallback', 'PHPUnit\Framework\MockObject\Stub\ReturnCallback');
class_alias('PHPUnit_Framework_MockObject_Stub_Return', 'PHPUnit\Framework\MockObject\Stub\ReturnStub');
}
<?php
trait ResetMocks
{
protected function resetMockObjects()
{
$refl = new ReflectionObject($this);
while (!$refl->hasProperty('mockObjects')) {
$refl = $refl->getParentClass();
}
$prop = $refl->getProperty('mockObjects');
$prop->setAccessible(true);
$prop->setValue($this, array());
}
}
\ No newline at end of file
This diff is collapsed.
<?php
require_once __DIR__ .'/ResetMocks.php';
class StubTraitTest extends \PHPUnit\Framework\TestCase
{
use ResetMocks;
use \Codeception\Test\Feature\Stub;
/**
* @var DummyClass
*/
protected $dummy;
public function setUp()
{
require_once $file = __DIR__. '/_data/DummyOverloadableClass.php';
require_once $file = __DIR__. '/_data/DummyClass.php';
$this->dummy = new DummyClass(true);
}
public function testMakeStubs()
{
$this->dummy = $this->make('DummyClass', ['helloWorld' => 'bye']);
$this->assertEquals('bye', $this->dummy->helloWorld());
$this->assertEquals('good bye', $this->dummy->goodByeWorld());
$this->dummy = $this->makeEmpty('DummyClass', ['helloWorld' => 'bye']);
$this->assertEquals('bye', $this->dummy->helloWorld());
$this->assertNull($this->dummy->goodByeWorld());
$this->dummy = $this->makeEmptyExcept('DummyClass', 'goodByeWorld', ['helloWorld' => 'bye']);
$this->assertEquals('bye', $this->dummy->helloWorld());
$this->assertEquals('good bye', $this->dummy->goodByeWorld());
$this->assertNull($this->dummy->exceptionalMethod());
}
public function testConstructStubs()
{
$this->dummy = $this->construct('DummyClass', ['!'], ['helloWorld' => 'bye']);
$this->assertEquals('constructed: !', $this->dummy->getCheckMe());
$this->assertEquals('bye', $this->dummy->helloWorld());
$this->assertEquals('good bye', $this->dummy->goodByeWorld());
$this->dummy = $this->constructEmpty('DummyClass', ['!'], ['helloWorld' => 'bye']);
$this->assertNull($this->dummy->getCheckMe());
$this->assertEquals('bye', $this->dummy->helloWorld());
$this->assertNull($this->dummy->goodByeWorld());
$this->dummy = $this->constructEmptyExcept('DummyClass', 'getCheckMe', ['!'], ['helloWorld' => 'bye']);
$this->assertEquals('constructed: !', $this->dummy->getCheckMe());
$this->assertEquals('bye', $this->dummy->helloWorld());
$this->assertNull($this->dummy->goodByeWorld());
$this->assertNull($this->dummy->exceptionalMethod());
}
public function testMakeMocks()
{
$this->dummy = $this->make('DummyClass', [
'helloWorld' => \Codeception\Stub\Expected::once()
]);
$this->dummy->helloWorld();
try {
$this->dummy->helloWorld();
} catch (Exception $e) {
$this->assertContains('was not expected to be called more than once', $e->getMessage());
$this->resetMockObjects();
return;
}
$this->fail('No exception thrown');
}
}
\ No newline at end of file
<?php
class DummyClass
{
protected $checkMe = 1;
protected $properties = array('checkMeToo' => 1);
function __construct($checkMe = 1)
{
$this->checkMe = "constructed: ".$checkMe;
}
public function helloWorld() {
return "hello";
}
public function goodByeWorld() {
return "good bye";
}
protected function notYourBusinessWorld()
{
return "goAway";
}
public function getCheckMe() {
return $this->checkMe;
}
public function getCheckMeToo() {
return $this->checkMeToo;
}
public function call() {
$this->targetMethod();
return true;
}
public function targetMethod() {
return true;
}
public function exceptionalMethod() {
throw new Exception('Catch it!');
}
public function __set($name, $value) {
if ($this->isMagical($name)) {
$this->properties[$name] = $value;
}
}
public function __get($name) {
if ($this->__isset($name)) {
return $this->properties[$name];
}
}
public function __isset($name) {
return $this->isMagical($name) && isset($this->properties[$name]);
}
private function isMagical($name) {
$reflectionClass = new \ReflectionClass($this);
return !$reflectionClass->hasProperty($name);
}
}
<?php
class DummyOverloadableClass
{
protected $checkMe = 1;
protected $properties = array('checkMeToo' => 1);
function __construct($checkMe = 1)
{
$this->checkMe = "constructed: ".$checkMe;
}
public function helloWorld() {
return "hello";
}
public function goodByeWorld() {
return "good bye";
}
protected function notYourBusinessWorld()
{
return "goAway";
}
public function getCheckMe() {
return $this->checkMe;
}
public function getCheckMeToo() {
return $this->checkMeToo;
}
public function call() {
$this->targetMethod();
return true;
}
public function targetMethod() {
return true;
}
public function exceptionalMethod() {
throw new Exception('Catch it!');
}
public function __get($name) {
//seeing as we're not implementing __set here, add check for __mocked
$return = null;
if ($name === '__mocked') {
$return = isset($this->__mocked) ? $this->__mocked : null;
} else {
if ($this->__isset($name)) {
$return = $this->properties[$name];
}
}
return $return;
}
public function __isset($name) {
return $this->isMagical($name) && isset($this->properties[$name]);
}
private function isMagical($name) {
$reflectionClass = new \ReflectionClass($this);
return !$reflectionClass->hasProperty($name);
}
}
<?php
/**
* @file
* Legacy autoloader for systems lacking spl_autoload_register
*
* Must be separate to prevent deprecation warning on PHP 7.2
*/
function __autoload($class)
{
return HTMLPurifierExtras::autoload($class);
}
// vim: et sw=4 sts=4
<?php
/**
* @file
* Legacy autoloader for systems lacking spl_autoload_register
*
* Must be separate to prevent deprecation warning on PHP 7.2
*/
function __autoload($class)
{
return HTMLPurifier_Bootstrap::autoload($class);
}
// vim: et sw=4 sts=4
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at kartikv2@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
/*!
* FileInput Georgian Translations
*
* This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
* any HTML markup tags in the messages must not be converted or translated.
*
* @see http://github.com/kartik-v/bootstrap-fileinput
* @author Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
(function ($) {
"use strict";
$.fn.fileinputLocales['ka'] = {
fileSingle: 'ფაილი',
filePlural: 'ფაილები',
browseLabel: 'არჩევა &hellip;',
removeLabel: 'წაშლა',
removeTitle: 'არჩეული ფაილების წაშლა',
cancelLabel: 'გაუქმება',
cancelTitle: 'მიმდინარე ატვირთვის გაუქმება',
uploadLabel: 'ატვირთვა',
uploadTitle: 'არჩეული ფაილების ატვირთვა',
msgNo: 'არა',
msgNoFilesSelected: 'ფაილები არ არის არჩეული',
msgCancelled: 'გაუქმებულია',
msgPlaceholder: 'აირჩიეთ {files}...',
msgZoomModalHeading: 'დეტალურად ნახვა',
msgFileRequired: 'ატვირთვისთვის აუცილებელია ფაილის არჩევა.',
msgSizeTooSmall: 'ფაილი "{name}" (<b>{size} KB</b>) არის ძალიან პატარა. მისი ზომა უნდა იყოს არანაკლებ <b>{minSize} KB</b>.',
msgSizeTooLarge: 'ფაილი "{name}" (<b>{size} KB</b>) აჭარბებს მაქსიმალურ დასაშვებ ზომას <b>{maxSize} KB</b>.',
msgFilesTooLess: 'უნდა აირჩიოთ მინიმუმ <b>{n}</b> {file} ატვირთვისთვის.',
msgFilesTooMany: 'არჩეული ფაილების რაოდენობა <b>({n})</b> აჭარბებს დასაშვებ ლიმიტს <b>{m}</b>.',
msgFileNotFound: 'ფაილი "{name}" არ მოიძებნა!',
msgFileSecured: 'უსაფრთხოებით გამოწვეული შეზღუდვები კრძალავს ფაილის "{name}" წაკითხვას.',
msgFileNotReadable: 'ფაილის "{name}" წაკითხვა შეუძლებელია.',
msgFilePreviewAborted: 'პრევიუ გაუქმებულია ფაილისათვის "{name}".',
msgFilePreviewError: 'დაფიქსირდა შეცდომა ფაილის "{name}" კითხვისას.',
msgInvalidFileName: 'ნაპოვნია დაუშვებელი სიმბოლოები ფაილის "{name}" სახელში.',
msgInvalidFileType: 'ფაილს "{name}" გააჩნია დაუშვებელი ტიპი. მხოლოდ "{types}" ტიპის ფაილები არის დაშვებული.',
msgInvalidFileExtension: 'ფაილს "{name}" გააჩნია დაუშვებელი გაფართოება. მხოლოდ "{extensions}" გაფართოების ფაილები არის დაშვებული.',
msgFileTypes: {
'image': 'image',
'html': 'HTML',
'text': 'text',
'video': 'video',
'audio': 'audio',
'flash': 'flash',
'pdf': 'PDF',
'object': 'object'
},
msgUploadAborted: 'ფაილის ატვირთვა შეწყდა',
msgUploadThreshold: 'მუშავდება...',
msgUploadBegin: 'ინიციალიზაცია...',
msgUploadEnd: 'დასრულებულია',
msgUploadEmpty: 'ატვირთვისთვის დაუშვებელი მონაცემები.',
msgUploadError: 'ატვირთვის შეცდომა',
msgValidationError: 'ვალიდაციის შეცდომა',
msgLoading: 'ატვირთვა {index} / {files} &hellip;',
msgProgress: 'ფაილის ატვირთვა დასრულებულია {index} / {files} - {name} - {percent}%.',
msgSelected: 'არჩეულია {n} {file}',
msgFoldersNotAllowed: 'დაშვებულია მხოლოდ ფაილების გადმოთრევა! გამოტოვებულია {n} გადმოთრეული ფოლდერი.',
msgImageWidthSmall: 'სურათის "{name}" სიგანე უნდა იყოს არანაკლებ {size} px.',
msgImageHeightSmall: 'სურათის "{name}" სიმაღლე უნდა იყოს არანაკლებ {size} px.',
msgImageWidthLarge: 'სურათის "{name}" სიგანე არ უნდა აღემატებოდეს {size} px-ს.',
msgImageHeightLarge: 'სურათის "{name}" სიმაღლე არ უნდა აღემატებოდეს {size} px-ს.',
msgImageResizeError: 'ვერ მოხერხდა სურათის ზომის შეცვლისთვის საჭირო მონაცემების გარკვევა.',
msgImageResizeException: 'შეცდომა სურათის ზომის შეცვლისას.<pre>{errors}</pre>',
msgAjaxError: 'დაფიქსირდა შეცდომა ოპერაციის {operation} შესრულებისას. ცადეთ მოგვიანებით!',
msgAjaxProgressError: 'ვერ მოხერხდა ოპერაციის {operation} შესრულება',
ajaxOperations: {
deleteThumb: 'ფაილის წაშლა',
uploadThumb: 'ფაილის ატვირთვა',
uploadBatch: 'ფაილების ატვირთვა',
uploadExtra: 'მონაცემების გაგზავნა ფორმიდან'
},
dropZoneTitle: 'გადმოათრიეთ ფაილები აქ &hellip;',
dropZoneClickTitle: '<br>(ან დააჭირეთ რათა აირჩიოთ {files})',
fileActionSettings: {
removeTitle: 'ფაილის წაშლა',
uploadTitle: 'ფაილის ატვირთვა',
uploadRetryTitle: 'ატვირთვის გამეორება',
downloadTitle: 'ფაილის ჩამოტვირთვა',
zoomTitle: 'დეტალურად ნახვა',
dragTitle: 'გადაადგილება / მიმდევრობის შეცვლა',
indicatorNewTitle: 'ჯერ არ ატვირთულა',
indicatorSuccessTitle: 'ატვირთულია',
indicatorErrorTitle: 'ატვირთვის შეცდომა',
indicatorLoadingTitle: 'ატვირთვა ...'
},
previewZoomButtonTitles: {
prev: 'წინა ფაილის ნახვა',
next: 'შემდეგი ფაილის ნახვა',
toggleheader: 'სათაურის დამალვა',
fullscreen: 'მთელ ეკრანზე გაშლა',
borderless: 'მთელ გვერდზე გაშლა',
close: 'დახურვა'
}
};
})(window.jQuery);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment