at the end of the day, it was inevitable
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Helper;
|
||||
|
||||
/**
|
||||
* Class AccessorTrait
|
||||
* @package Tests\Helper
|
||||
*/
|
||||
trait AccessorTrait
|
||||
{
|
||||
|
||||
/**
|
||||
* Call specified method of given object.
|
||||
*
|
||||
* @param object $object Some object.
|
||||
* @param string $method Called method name.
|
||||
* @param array $arguments Method parameters.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function call($object, $method, array $arguments = [])
|
||||
{
|
||||
$caller = function () use ($method, $arguments) {
|
||||
return call_user_func_array([ $this, $method ], $arguments);
|
||||
};
|
||||
$caller = $caller->bindTo($object, $object);
|
||||
|
||||
return $caller();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Helper;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionFont;
|
||||
|
||||
/**
|
||||
* Class CssAssertBuilder
|
||||
*
|
||||
* @package Helper
|
||||
*/
|
||||
class CssAssertBuilder
|
||||
{
|
||||
|
||||
const PROPERTY_WITH_VALUE_PATTERN_TPL = '/%s[^\{]*?\{[^\}]*%s:\s*%s[^\}]*\}/i';
|
||||
const PROPERTY_PATTERN_TPL = '/%s[^\{]*?\{[^\}]*%s:[^\}]*\}/i';
|
||||
|
||||
private static $searchedCharacters = [
|
||||
'.',
|
||||
'[',
|
||||
']',
|
||||
'(',
|
||||
')',
|
||||
'{',
|
||||
'}',
|
||||
'/',
|
||||
];
|
||||
|
||||
private static $replaceCharacters = [
|
||||
'\.',
|
||||
'\[',
|
||||
'\]',
|
||||
'\(',
|
||||
'\)',
|
||||
'\{',
|
||||
'\}',
|
||||
'\/',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $selector;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $shouldExists = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $asserts = [];
|
||||
|
||||
/**
|
||||
* CssAssertBuilder constructor.
|
||||
*
|
||||
* @param string $selector A base css element selector.
|
||||
* @param boolean $escape Should escape specific pattern symbols or not.
|
||||
*/
|
||||
public function __construct($selector, $escape = true)
|
||||
{
|
||||
if ($escape) {
|
||||
$selector = str_replace(self::$searchedCharacters, self::$replaceCharacters, $selector);
|
||||
}
|
||||
|
||||
$this->selector = $selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CssAssertBuilder
|
||||
*/
|
||||
public function shouldExists()
|
||||
{
|
||||
$this->shouldExists = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CssAssertBuilder
|
||||
*/
|
||||
public function shouldNotExists()
|
||||
{
|
||||
$this->shouldExists = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $selector A base css element selector.
|
||||
*
|
||||
* @return CssAssertBuilder
|
||||
*/
|
||||
public static function create($selector)
|
||||
{
|
||||
return new CssAssertBuilder($selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ThemeOptionFont $font Font which should be rendered.
|
||||
*
|
||||
* @return CssAssertBuilder
|
||||
*/
|
||||
public function hasFont(ThemeOptionFont $font)
|
||||
{
|
||||
$this
|
||||
->propertyShouldBe('font-family', $font->getFamily()->getCss())
|
||||
->propertyShouldBe('font-size', $font->getSize());
|
||||
|
||||
$style = $font->getStyle();
|
||||
|
||||
if ($style->isBold()) {
|
||||
$this->propertyShouldBe('font-weight', 'bold');
|
||||
} else {
|
||||
$this->propertyShouldNotBe('font-weight', 'bold');
|
||||
}
|
||||
|
||||
if ($style->isItalic()) {
|
||||
$this->propertyShouldBe('font-style', 'italic');
|
||||
} else {
|
||||
$this->propertyShouldNotBe('font-style', 'italic');
|
||||
}
|
||||
|
||||
if ($style->isUnderline()) {
|
||||
$this->propertyShouldBe('text-decoration', 'underline');
|
||||
} else {
|
||||
$this->propertyShouldNotBe('text-decoration', 'underline');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function hasNotAnyFonts()
|
||||
{
|
||||
return $this
|
||||
->propertyShouldNotExists('font-family')
|
||||
->propertyShouldNotExists('font-size')
|
||||
->propertyShouldNotExists('font-weight')
|
||||
->propertyShouldNotExists('font-style')
|
||||
->propertyShouldNotExists('text-decoration');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Property name.
|
||||
* @param string $message Error message.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function propertyShouldExists($name, $message = '')
|
||||
{
|
||||
$this->asserts[] = [
|
||||
'method' => 'assertRegExp',
|
||||
'arguments' => [
|
||||
sprintf(self::PROPERTY_PATTERN_TPL, $this->selector, $name),
|
||||
'___',
|
||||
$message,
|
||||
],
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Property name.
|
||||
* @param string $message Error message.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function propertyShouldNotExists($name, $message = '')
|
||||
{
|
||||
$this->asserts[] = [
|
||||
'method' => 'assertNotRegExp',
|
||||
'arguments' => [
|
||||
sprintf(self::PROPERTY_PATTERN_TPL, $this->selector, $name),
|
||||
'___',
|
||||
$message,
|
||||
],
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Property name.
|
||||
* @param string $value Expected property value.
|
||||
* @param string $message Error message.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function propertyShouldBe($name, $value, $message = '')
|
||||
{
|
||||
$name = str_replace(self::$searchedCharacters, self::$replaceCharacters, $name);
|
||||
$value = str_replace(self::$searchedCharacters, self::$replaceCharacters, $value);
|
||||
|
||||
$this->asserts[] = [
|
||||
'method' => 'assertRegExp',
|
||||
'arguments' => [
|
||||
sprintf(self::PROPERTY_WITH_VALUE_PATTERN_TPL, $this->selector, $name, $value),
|
||||
'___',
|
||||
$message,
|
||||
],
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Property name.
|
||||
* @param string $value Expected property value.
|
||||
* @param string $message Error message.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function propertyShouldNotBe($name, $value = '', $message = '')
|
||||
{
|
||||
$name = str_replace(self::$searchedCharacters, self::$replaceCharacters, $name);
|
||||
$value = str_replace(self::$searchedCharacters, self::$replaceCharacters, $value);
|
||||
|
||||
$this->asserts[] = [
|
||||
'method' => 'assertNotRegExp',
|
||||
'arguments' => [
|
||||
sprintf(self::PROPERTY_WITH_VALUE_PATTERN_TPL, $this->selector, $name, $value),
|
||||
'___',
|
||||
$message,
|
||||
],
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html HTML content.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function assert($html)
|
||||
{
|
||||
if (! $this->shouldExists) {
|
||||
TestCase::assertNotRegExp("/{$this->selector}/", $html);
|
||||
|
||||
// Don't assert property 'cause it's not necessary.
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->asserts as $config) {
|
||||
$arguments = \nspl\a\map(function ($argument) use ($html) {
|
||||
if (is_string($argument) && ($argument === '___')) {
|
||||
$argument = $html;
|
||||
}
|
||||
|
||||
return $argument;
|
||||
}, $config['arguments']);
|
||||
call_user_func_array([ TestCase::class, $config['method'] ], $arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Helper;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Class CssAsserter
|
||||
*
|
||||
* @package Helper
|
||||
*/
|
||||
class CssAsserter
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $styles;
|
||||
|
||||
/**
|
||||
* CssAsserter constructor.
|
||||
*
|
||||
* @param string $styles Raw css style text.
|
||||
*/
|
||||
public function __construct($styles)
|
||||
{
|
||||
$this->styles = $styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html Raw html.
|
||||
*
|
||||
* @return CssAsserter
|
||||
*/
|
||||
public static function createFromHtml($html)
|
||||
{
|
||||
$matches = [];
|
||||
preg_match('#<style>([^<]*)</style>#i', $html, $matches);
|
||||
array_shift($matches);
|
||||
|
||||
return new CssAsserter(implode("\n", $matches));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $selector Css selector.
|
||||
*
|
||||
* @return CssAsserter
|
||||
*/
|
||||
public function hasSelector($selector)
|
||||
{
|
||||
TestCase::assertRegExp('/'.$selector.'/i', $this->styles);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $selector Css selector.
|
||||
*
|
||||
* @return CssPropertiesAsserter
|
||||
*/
|
||||
public function with($selector)
|
||||
{
|
||||
$this->hasSelector($selector);
|
||||
|
||||
return new CssPropertiesAsserter(preg_replace('/%s[^\{]*?\{([^\}]*?)\}/i', '$1', $this->styles), $this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Helper;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionFont;
|
||||
|
||||
/**
|
||||
* Class CssPropertiesAsserter
|
||||
*
|
||||
* @package Helper
|
||||
*/
|
||||
class CssPropertiesAsserter
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $properties;
|
||||
|
||||
/**
|
||||
* @var CssAsserter
|
||||
*/
|
||||
private $cssAsserter;
|
||||
|
||||
/**
|
||||
* CssAsserter constructor.
|
||||
*
|
||||
* @param string $properties Css properties.
|
||||
* @param CssAsserter|null $cssAsserter A parent CssAsserter instance.
|
||||
*/
|
||||
public function __construct($properties, CssAsserter $cssAsserter)
|
||||
{
|
||||
$this->properties = $properties;
|
||||
$this->cssAsserter = $cssAsserter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Property name.
|
||||
* @param string|null $value Property value.
|
||||
*
|
||||
* @return CssPropertiesAsserter
|
||||
*/
|
||||
public function has($name, $value = null)
|
||||
{
|
||||
if ($value !== null) {
|
||||
$value = str_replace([ '(', ')' ], [ '\(', '\)' ], $value);
|
||||
}
|
||||
|
||||
$pattern = $value === null
|
||||
? sprintf('/%s:\s*[^;];/i', $name)
|
||||
: sprintf('/%s:\s*%s;/i', $name, $value);
|
||||
|
||||
TestCase::assertRegExp($pattern, $this->properties);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Property name.
|
||||
* @param string|null $value Property value.
|
||||
*
|
||||
* @return CssPropertiesAsserter
|
||||
*/
|
||||
public function hasNot($name, $value = null)
|
||||
{
|
||||
$pattern = $value === null
|
||||
? sprintf('/%s:\s*[^;];/i', $name)
|
||||
: sprintf('/%s:\s*%s;/i', $name, $value);
|
||||
|
||||
TestCase::assertNotRegExp($pattern, $this->properties);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ThemeOptionFont $font A ThemeOptionFont instance.
|
||||
*
|
||||
* @return CssPropertiesAsserter
|
||||
*/
|
||||
public function hasFont(ThemeOptionFont $font)
|
||||
{
|
||||
$this
|
||||
->has('font-family', $font->getFamily()->getCss())
|
||||
->has('font-size', $font->getSize());
|
||||
|
||||
$style = $font->getStyle();
|
||||
|
||||
if ($style->isBold()) {
|
||||
$this->has('font-weight', 'bold');
|
||||
} else {
|
||||
$this->hasNot('font-weight');
|
||||
}
|
||||
|
||||
if ($style->isItalic()) {
|
||||
$this->has('font-style', 'italic');
|
||||
} else {
|
||||
$this->hasNot('font-style');
|
||||
}
|
||||
|
||||
if ($style->isUnderline()) {
|
||||
$this->has('text-decoration', 'underline');
|
||||
} else {
|
||||
$this->hasNot('text-decoration');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CssPropertiesAsserter
|
||||
*/
|
||||
public function hasNotFontAtAll()
|
||||
{
|
||||
return $this
|
||||
->hasNot('font-family')
|
||||
->hasNot('font-size')
|
||||
->hasNot('font-weight')
|
||||
->hasNot('font-style')
|
||||
->hasNot('text-decoration');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|CssAsserter
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->cssAsserter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Helper;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
/**
|
||||
* Class HtmlAsserter
|
||||
*
|
||||
* @package Helper
|
||||
*/
|
||||
class HtmlAsserter
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Crawler
|
||||
*/
|
||||
private $root;
|
||||
|
||||
/**
|
||||
* @var HtmlAsserter|null
|
||||
*/
|
||||
private $parent;
|
||||
|
||||
/**
|
||||
* HtmlAsserter constructor.
|
||||
*
|
||||
* @param Crawler $root A Crawler instance.
|
||||
* @param HtmlAsserter $parent A parent Crawler instance.
|
||||
*/
|
||||
public function __construct(Crawler $root, HtmlAsserter $parent = null)
|
||||
{
|
||||
$this->root = $root;
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $selector Node selector.
|
||||
* @param integer $count Expected node numbers. Check that at least one
|
||||
* exists if -1.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function hasNode($selector, $count = 1)
|
||||
{
|
||||
$nodes = $this->root->filter($selector);
|
||||
|
||||
if ($count === -1) {
|
||||
TestCase::assertGreaterThan(0, count($nodes), sprintf(
|
||||
'Expects at least one node \'%s\' but got zero',
|
||||
$selector
|
||||
));
|
||||
} else {
|
||||
TestCase::assertCount($count, $nodes, sprintf(
|
||||
'Expects %d of \'%s\' nodes but got another count',
|
||||
$count,
|
||||
$selector
|
||||
));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $selector Node selector.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function hasNotNode($selector)
|
||||
{
|
||||
TestCase::assertCount(0, $this->root->filter($selector), sprintf(
|
||||
'Node \'%s\' is exists but should\'nt',
|
||||
$selector
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class Expected node class.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function hasClass($class)
|
||||
{
|
||||
TestCase::assertContains($class, $this->root->attr('class'), sprintf(
|
||||
'Current node should has \'%s\' class but it has not',
|
||||
$class
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name HTML node attribute name.
|
||||
* @param string $value Expected value.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function hasAttr($name, $value = null)
|
||||
{
|
||||
$nodeValue = $this->root->attr($name);
|
||||
|
||||
if ($value === null) {
|
||||
TestCase::assertNotNull($nodeValue, sprintf(
|
||||
'Node attribute \'%s\' should exists but it has not',
|
||||
$name
|
||||
));
|
||||
} else {
|
||||
TestCase::assertEquals($value, $nodeValue, sprintf(
|
||||
'Node attribute \'%s\' should match to \'%s\' but it has \'%s\'',
|
||||
$name,
|
||||
$value,
|
||||
$nodeValue
|
||||
));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content Expected text content.
|
||||
* @param boolean $strict Should content only specified values or not.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function contains($content, $strict = false)
|
||||
{
|
||||
$nodeContent = $this->root->getNode(0)->textContent;
|
||||
|
||||
if ($strict) {
|
||||
TestCase::assertEquals($content, $nodeContent, sprintf(
|
||||
'Node should contains only \'%s\' but it has not',
|
||||
$content
|
||||
));
|
||||
} else {
|
||||
TestCase::assertContains($content, $nodeContent, sprintf(
|
||||
'Node should contains \'%s\' but it has not',
|
||||
$content
|
||||
));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content Unexpected text content.
|
||||
* @param boolean $strict Should content only specified values or not.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function notContains($content, $strict = false)
|
||||
{
|
||||
$nodeContent = $this->root->getNode(0)->textContent;
|
||||
|
||||
if ($strict) {
|
||||
TestCase::assertNotEquals($content, $nodeContent, sprintf(
|
||||
'Node should\'nt contains \'%s\' but it has',
|
||||
$content
|
||||
));
|
||||
} else {
|
||||
TestCase::assertNotContains($content, $nodeContent, sprintf(
|
||||
'Node should\'nt contains \'%s\' but it has',
|
||||
$content
|
||||
));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $regex Regular expression.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function regexContent($regex)
|
||||
{
|
||||
TestCase::assertRegExp($regex, $this->root->getNode(0)->textContent, sprintf(
|
||||
'Content of node should match to \'%s\' but it has not',
|
||||
$regex
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $selector Node selector.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function with($selector)
|
||||
{
|
||||
$this->hasNode($selector, -1);
|
||||
|
||||
return new static($this->root->filter($selector), $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $idx Child node index.
|
||||
*
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function child($idx)
|
||||
{
|
||||
return new static(new Crawler($this->root->getNode($idx)), $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->parent !== null ? $this->parent : $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HtmlAsserter
|
||||
*/
|
||||
public function dump()
|
||||
{
|
||||
echo $this->root->html();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user