Merge pull request #51 from FriendsOfBehat/ci/add-cs-fixer-phpstan
Some checks failed
Test / PHP 8.3 + Symfony 7.4.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.4 + Symfony 7.4.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.4 + Symfony 8.0.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.4 + Symfony 8.1.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.5 + Symfony 7.4.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.5 + Symfony 8.0.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.5 + Symfony 8.1.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.3 + Symfony 7.4.* + Behat stable (push) Has been cancelled
Test / PHP 8.4 + Symfony 7.4.* + Behat stable (push) Has been cancelled
Test / PHP 8.5 + Symfony 7.4.* + Behat stable (push) Has been cancelled
Some checks failed
Test / PHP 8.3 + Symfony 7.4.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.4 + Symfony 7.4.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.4 + Symfony 8.0.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.4 + Symfony 8.1.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.5 + Symfony 7.4.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.5 + Symfony 8.0.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.5 + Symfony 8.1.* + Behat 4.x-dev (push) Has been cancelled
Test / PHP 8.3 + Symfony 7.4.* + Behat stable (push) Has been cancelled
Test / PHP 8.4 + Symfony 7.4.* + Behat stable (push) Has been cancelled
Test / PHP 8.5 + Symfony 7.4.* + Behat stable (push) Has been cancelled
Add PHP CS Fixer + PHPStan max to CI; drop GoutteFactory
This commit is contained in:
6
.github/workflows/test.yaml
vendored
6
.github/workflows/test.yaml
vendored
@@ -67,6 +67,12 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: composer install --prefer-dist --no-progress
|
||||
|
||||
- name: CS Fixer
|
||||
run: vendor/bin/php-cs-fixer fix --dry-run
|
||||
|
||||
- name: PHPStan
|
||||
run: vendor/bin/phpstan analyse --memory-limit=512M
|
||||
|
||||
- name: PHPSpec
|
||||
run: vendor/bin/phpspec run -f pretty
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
*.phar
|
||||
composer.lock
|
||||
vendor
|
||||
.php-cs-fixer.cache
|
||||
|
||||
19
.php-cs-fixer.dist.php
Normal file
19
.php-cs-fixer.dist.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Config;
|
||||
use PhpCsFixer\Finder;
|
||||
|
||||
$finder = Finder::create()
|
||||
->in(__DIR__.'/src')
|
||||
->in(__DIR__.'/spec')
|
||||
;
|
||||
|
||||
return (new Config())
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
'phpdoc_to_comment' => ['ignored_tags' => ['psalm-suppress', 'phpstan-ignore']],
|
||||
])
|
||||
->setFinder($finder)
|
||||
;
|
||||
@@ -30,7 +30,9 @@
|
||||
"behat/mink-browserkit-driver": "^2.0",
|
||||
"phpspec/phpspec": "^8.0",
|
||||
"symfony/browser-kit": "^7.4 || ^8.0",
|
||||
"symfony/http-client": "^7.4 || ^8.0"
|
||||
"symfony/http-client": "^7.4 || ^8.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.75",
|
||||
"phpstan/phpstan": "^2.0"
|
||||
},
|
||||
"replace": {
|
||||
"behat/mink-extension": "self.version"
|
||||
@@ -46,6 +48,9 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"cs": "vendor/bin/php-cs-fixer fix",
|
||||
"cs-check": "vendor/bin/php-cs-fixer fix --dry-run",
|
||||
"phpstan": "vendor/bin/phpstan analyse --memory-limit=512M",
|
||||
"test": [
|
||||
"vendor/bin/phpspec run -f pretty",
|
||||
"vendor/bin/behat --config behat.dist.php -fprogress --strict"
|
||||
|
||||
5
phpstan.neon
Normal file
5
phpstan.neon
Normal file
@@ -0,0 +1,5 @@
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
||||
treatPhpDocTypesAsCertain: false
|
||||
@@ -9,25 +9,25 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class MinkAwareInitializerSpec extends ObjectBehavior
|
||||
{
|
||||
function let(Mink $mink)
|
||||
public function let(Mink $mink)
|
||||
{
|
||||
$this->beConstructedWith($mink, array('base_url' => 'foo'));
|
||||
$this->beConstructedWith($mink, ['base_url' => 'foo']);
|
||||
}
|
||||
|
||||
function it_is_a_context_initializer()
|
||||
public function it_is_a_context_initializer()
|
||||
{
|
||||
$this->shouldHaveType('Behat\Behat\Context\Initializer\ContextInitializer');
|
||||
}
|
||||
|
||||
function it_does_nothing_for_basic_contexts(Context $context)
|
||||
public function it_does_nothing_for_basic_contexts(Context $context)
|
||||
{
|
||||
$this->initializeContext($context);
|
||||
}
|
||||
|
||||
function it_injects_mink_and_parameters_in_mink_aware_contexts(MinkAwareContext $context, $mink)
|
||||
public function it_injects_mink_and_parameters_in_mink_aware_contexts(MinkAwareContext $context, $mink)
|
||||
{
|
||||
$context->setMink($mink)->shouldBeCalled();
|
||||
$context->setMinkParameters(array('base_url' => 'foo'))->shouldBeCalled();
|
||||
$context->setMinkParameters(['base_url' => 'foo'])->shouldBeCalled();
|
||||
$this->initializeContext($context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class SessionsListenerSpec extends ObjectBehavior
|
||||
{
|
||||
function let(Mink $mink, ScenarioTested $event, FeatureNode $feature, ScenarioNode $scenario, Suite $suite)
|
||||
public function let(Mink $mink, ScenarioTested $event, FeatureNode $feature, ScenarioNode $scenario, Suite $suite)
|
||||
{
|
||||
$this->beConstructedWith($mink, 'goutte', 'selenium2', array('selenium2', 'sahi'));
|
||||
$this->beConstructedWith($mink, 'browserkit_http', 'selenium2', ['selenium2', 'sahi']);
|
||||
|
||||
$event->getSuite()->willReturn($suite);
|
||||
$event->getFeature()->willReturn($feature);
|
||||
@@ -25,25 +25,25 @@ class SessionsListenerSpec extends ObjectBehavior
|
||||
$suite->getName()->willReturn('default');
|
||||
|
||||
$feature->hasTag('insulated')->willReturn(false);
|
||||
$feature->getTags()->willReturn(array());
|
||||
$feature->getTags()->willReturn([]);
|
||||
$scenario->hasTag('insulated')->willReturn(false);
|
||||
$scenario->getTags()->willReturn(array());
|
||||
$scenario->getTags()->willReturn([]);
|
||||
}
|
||||
|
||||
function it_is_an_event_subscriber()
|
||||
public function it_is_an_event_subscriber()
|
||||
{
|
||||
$this->shouldHaveType('Symfony\Component\EventDispatcher\EventSubscriberInterface');
|
||||
}
|
||||
|
||||
function it_resets_the_default_session_before_scenarios($event, $mink)
|
||||
public function it_resets_the_default_session_before_scenarios($event, $mink)
|
||||
{
|
||||
$mink->resetSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('goutte')->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('browserkit_http')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_supports_changing_the_default_session_per_suite($event, $mink, $suite)
|
||||
public function it_supports_changing_the_default_session_per_suite($event, $mink, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_session')->willReturn(true);
|
||||
$suite->getSetting('mink_session')->willReturn('test');
|
||||
@@ -54,118 +54,118 @@ class SessionsListenerSpec extends ObjectBehavior
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_fails_for_non_string_default_suite_session($event, $suite)
|
||||
public function it_fails_for_non_string_default_suite_session($event, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_session')->willReturn(true);
|
||||
$suite->getSetting('mink_session')->willReturn(array());
|
||||
$suite->getSetting('mink_session')->willReturn([]);
|
||||
|
||||
$this->shouldThrow(new SuiteConfigurationException('`mink_session` setting of the "default" suite is expected to be a string, array given.', 'default'))
|
||||
->duringPrepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_switches_to_the_javascript_session_for_tagged_scenarios($event, $mink, $scenario, $suite)
|
||||
public function it_switches_to_the_javascript_session_for_tagged_scenarios($event, $mink, $scenario, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_javascript_session')->willReturn(false);
|
||||
$scenario->getTags()->willReturn(array('javascript'));
|
||||
$scenario->getTags()->willReturn(['javascript']);
|
||||
$mink->resetSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('selenium2')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_switches_to_the_javascript_session_for_tagged_features($event, $mink, $feature, $suite)
|
||||
public function it_switches_to_the_javascript_session_for_tagged_features($event, $mink, $feature, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_javascript_session')->willReturn(false);
|
||||
$feature->getTags()->willReturn(array('javascript'));
|
||||
$feature->getTags()->willReturn(['javascript']);
|
||||
$mink->resetSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('selenium2')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_supports_changing_the_default_javascript_session_per_suite($event, $mink, $scenario, $suite)
|
||||
public function it_supports_changing_the_default_javascript_session_per_suite($event, $mink, $scenario, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_javascript_session')->willReturn(true);
|
||||
$suite->getSetting('mink_javascript_session')->willReturn('sahi');
|
||||
|
||||
$scenario->getTags()->willReturn(array('javascript'));
|
||||
$scenario->getTags()->willReturn(['javascript']);
|
||||
$mink->resetSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('sahi')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_fails_for_non_string_javascript_suite_session($event, $scenario, $suite)
|
||||
public function it_fails_for_non_string_javascript_suite_session($event, $scenario, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_javascript_session')->willReturn(true);
|
||||
$suite->getSetting('mink_javascript_session')->willReturn(array());
|
||||
$suite->getSetting('mink_javascript_session')->willReturn([]);
|
||||
|
||||
$scenario->getTags()->willReturn(array('javascript'));
|
||||
$scenario->getTags()->willReturn(['javascript']);
|
||||
|
||||
$this->shouldThrow(new SuiteConfigurationException('`mink_javascript_session` setting of the "default" suite is expected to be a string, array given.', 'default'))
|
||||
->duringPrepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_fails_for_invalid_javascript_suite_session($event, $scenario, $suite)
|
||||
public function it_fails_for_invalid_javascript_suite_session($event, $scenario, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_javascript_session')->willReturn(true);
|
||||
$suite->getSetting('mink_javascript_session')->willReturn('test');
|
||||
|
||||
$scenario->getTags()->willReturn(array('javascript'));
|
||||
$scenario->getTags()->willReturn(['javascript']);
|
||||
|
||||
$this->shouldThrow(new SuiteConfigurationException('`mink_javascript_session` setting of the "default" suite is not a javascript session. test given but expected one of selenium2, sahi.', 'default'))
|
||||
->duringPrepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_fails_when_the_javascript_session_is_used_but_not_defined($event, $mink, $feature, $suite)
|
||||
public function it_fails_when_the_javascript_session_is_used_but_not_defined($event, $mink, $feature, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_javascript_session')->willReturn(false);
|
||||
$this->beConstructedWith($mink, 'goutte', null);
|
||||
$feature->getTags()->willReturn(array('javascript'));
|
||||
$this->beConstructedWith($mink, 'browserkit_http', null);
|
||||
$feature->getTags()->willReturn(['javascript']);
|
||||
|
||||
$this->shouldThrow(new ProcessingException('The @javascript tag cannot be used without enabling a javascript session'))
|
||||
->duringPrepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_switches_to_a_named_session($event, $mink, $scenario)
|
||||
public function it_switches_to_a_named_session($event, $mink, $scenario)
|
||||
{
|
||||
$scenario->getTags()->willReturn(array('mink:test'));
|
||||
$scenario->getTags()->willReturn(['mink:test']);
|
||||
$mink->resetSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('test')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_prefers_the_scenario_over_the_feature($event, $mink, $scenario, $feature, $suite)
|
||||
public function it_prefers_the_scenario_over_the_feature($event, $mink, $scenario, $feature, $suite)
|
||||
{
|
||||
$suite->hasSetting('mink_javascript_session')->willReturn(false);
|
||||
$scenario->getTags()->willReturn(array('mink:test'));
|
||||
$feature->getTags()->willReturn(array('javascript'));
|
||||
$scenario->getTags()->willReturn(['mink:test']);
|
||||
$feature->getTags()->willReturn(['javascript']);
|
||||
$mink->resetSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('test')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_stops_the_sessions_for_insulated_scenarios($event, $mink, $scenario)
|
||||
public function it_stops_the_sessions_for_insulated_scenarios($event, $mink, $scenario)
|
||||
{
|
||||
$scenario->hasTag('insulated')->willReturn(true);
|
||||
$mink->stopSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('goutte')->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('browserkit_http')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_stops_the_sessions_for_insulated_features($event, $mink, $feature)
|
||||
public function it_stops_the_sessions_for_insulated_features($event, $mink, $feature)
|
||||
{
|
||||
$feature->hasTag('insulated')->willReturn(true);
|
||||
$mink->stopSessions()->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('goutte')->shouldBeCalled();
|
||||
$mink->setDefaultSessionName('browserkit_http')->shouldBeCalled();
|
||||
|
||||
$this->prepareDefaultMinkSession($event);
|
||||
}
|
||||
|
||||
function it_stops_the_sessions_at_the_end_of_the_exercise($mink)
|
||||
public function it_stops_the_sessions_at_the_end_of_the_exercise($mink)
|
||||
{
|
||||
$mink->stopSessions()->shouldBeCalled();
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class AppiumFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_appium()
|
||||
public function it_is_named_appium()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('appium');
|
||||
}
|
||||
|
||||
function it_supports_javascript()
|
||||
public function it_supports_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(true);
|
||||
}
|
||||
|
||||
@@ -2,22 +2,22 @@
|
||||
|
||||
namespace spec\Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\DriverFactory;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
|
||||
class BrowserKitFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType(DriverFactory::class);
|
||||
}
|
||||
|
||||
function it_is_named_browserkit()
|
||||
public function it_is_named_browserkit()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('browserkit_http');
|
||||
}
|
||||
|
||||
function it_does_not_support_javascript()
|
||||
public function it_does_not_support_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(false);
|
||||
}
|
||||
|
||||
@@ -3,21 +3,20 @@
|
||||
namespace spec\Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Prophecy\Argument;
|
||||
|
||||
class BrowserStackFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_browser_stack()
|
||||
public function it_is_named_browser_stack()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('browser_stack');
|
||||
}
|
||||
|
||||
function it_supports_javascript()
|
||||
public function it_supports_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(true);
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace spec\Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
|
||||
class GoutteFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_goutte()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('goutte');
|
||||
}
|
||||
|
||||
function it_does_not_support_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(false);
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,17 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class SahiFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_sahi()
|
||||
public function it_is_named_sahi()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('sahi');
|
||||
}
|
||||
|
||||
function it_supports_javascript()
|
||||
public function it_supports_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(true);
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class SauceLabsFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_sauce_labs()
|
||||
public function it_is_named_sauce_labs()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('sauce_labs');
|
||||
}
|
||||
|
||||
function it_supports_javascript()
|
||||
public function it_supports_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(true);
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class Selenium2FactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_selenium2()
|
||||
public function it_is_named_selenium2()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('selenium2');
|
||||
}
|
||||
|
||||
function it_supports_javascript()
|
||||
public function it_supports_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(true);
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class SeleniumFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_selenium()
|
||||
public function it_is_named_selenium()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('selenium');
|
||||
}
|
||||
|
||||
function it_supports_javascript()
|
||||
public function it_supports_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(true);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace spec\Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\DriverFactory;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
|
||||
class WebdriverClassicFactorySpec extends ObjectBehavior
|
||||
{
|
||||
|
||||
@@ -6,17 +6,17 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class ZombieFactorySpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_driver_factory()
|
||||
public function it_is_a_driver_factory()
|
||||
{
|
||||
$this->shouldHaveType('Behat\MinkExtension\ServiceContainer\Driver\DriverFactory');
|
||||
}
|
||||
|
||||
function it_is_named_zombie()
|
||||
public function it_is_named_zombie()
|
||||
{
|
||||
$this->getDriverName()->shouldReturn('zombie');
|
||||
}
|
||||
|
||||
function it_supports_javascript()
|
||||
public function it_supports_javascript()
|
||||
{
|
||||
$this->supportsJavascript()->shouldBe(true);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ use PhpSpec\ObjectBehavior;
|
||||
|
||||
class MinkExtensionSpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_a_testwork_extension()
|
||||
public function it_is_a_testwork_extension()
|
||||
{
|
||||
$this->shouldHaveType('Behat\Testwork\ServiceContainer\Extension');
|
||||
}
|
||||
|
||||
function it_is_named_mink()
|
||||
public function it_is_named_mink()
|
||||
{
|
||||
$this->getConfigKey()->shouldReturn('mink');
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace Behat\MinkExtension\Context\Initializer;
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Context\Initializer\ContextInitializer;
|
||||
|
||||
use Behat\Mink\Mink;
|
||||
use Behat\MinkExtension\Context\MinkAwareContext;
|
||||
|
||||
@@ -24,6 +23,9 @@ use Behat\MinkExtension\Context\MinkAwareContext;
|
||||
*/
|
||||
class MinkAwareInitializer implements ContextInitializer
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $parameters
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly Mink $mink,
|
||||
private readonly array $parameters,
|
||||
|
||||
@@ -25,12 +25,12 @@ interface MinkAwareContext extends Context
|
||||
*
|
||||
* @param Mink $mink Mink session manager
|
||||
*/
|
||||
public function setMink(Mink $mink);
|
||||
public function setMink(Mink $mink): void;
|
||||
|
||||
/**
|
||||
* Sets parameters provided for Mink.
|
||||
*
|
||||
* @param array $parameters
|
||||
* @param array<string, mixed> $parameters
|
||||
*/
|
||||
public function setMinkParameters(array $parameters);
|
||||
public function setMinkParameters(array $parameters): void;
|
||||
}
|
||||
|
||||
@@ -21,294 +21,503 @@ use Behat\Gherkin\Node\TableNode;
|
||||
*/
|
||||
class MinkContext extends RawMinkContext implements TranslatableContext
|
||||
{
|
||||
/**
|
||||
* Opens homepage.
|
||||
* Example: Given I am on "/"
|
||||
* Example: When I go to "/"
|
||||
* Example: And I go to "/".
|
||||
*/
|
||||
#[\Behat\Step\Given('/^(?:|I )am on (?:|the )homepage$/')]
|
||||
#[\Behat\Step\When('/^(?:|I )go to (?:|the )homepage$/')]
|
||||
public function iAmOnHomepage()
|
||||
public function iAmOnHomepage(): void
|
||||
{
|
||||
$this->visitPath('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens specified page.
|
||||
* Example: Given I am on "http://batman.com"
|
||||
* Example: And I am on "/articles/isBatmanBruceWayne"
|
||||
* Example: When I go to "/articles/isBatmanBruceWayne".
|
||||
*/
|
||||
#[\Behat\Step\Given('/^(?:|I )am on "(?P<page>[^"]+)"$/')]
|
||||
#[\Behat\Step\When('/^(?:|I )go to "(?P<page>[^"]+)"$/')]
|
||||
public function visit($page)
|
||||
public function visit(string $page): void
|
||||
{
|
||||
$this->visitPath($page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads current page.
|
||||
* Example: When I reload the page
|
||||
* Example: And I reload the page.
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )reload the page$/')]
|
||||
public function reload()
|
||||
public function reload(): void
|
||||
{
|
||||
$this->getSession()->reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves backward one page in history.
|
||||
* Example: When I move backward one page.
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )move backward one page$/')]
|
||||
public function back()
|
||||
public function back(): void
|
||||
{
|
||||
$this->getSession()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves forward one page in history.
|
||||
* Example: And I move forward one page.
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )move forward one page$/')]
|
||||
public function forward()
|
||||
public function forward(): void
|
||||
{
|
||||
$this->getSession()->forward();
|
||||
}
|
||||
|
||||
/**
|
||||
* Presses button with specified id|name|title|alt|value.
|
||||
* Example: When I press "Log In"
|
||||
* Example: And I press "Log In".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/')]
|
||||
public function pressButton($button)
|
||||
public function pressButton(string $button): void
|
||||
{
|
||||
$button = $this->fixStepArgument($button);
|
||||
$this->getSession()->getPage()->pressButton($button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks link with specified id|title|alt|text.
|
||||
* Example: When I follow "Log In"
|
||||
* Example: And I follow "Log In".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/')]
|
||||
public function clickLink($link)
|
||||
public function clickLink(string $link): void
|
||||
{
|
||||
$link = $this->fixStepArgument($link);
|
||||
$this->getSession()->getPage()->clickLink($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in form field with specified id|name|label|value.
|
||||
* Example: When I fill in "username" with: "bwayne"
|
||||
* Example: And I fill in "bwayne" for "username".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/')]
|
||||
#[\Behat\Step\When('/^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with:$/')]
|
||||
#[\Behat\Step\When('/^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/')]
|
||||
public function fillField($field, $value)
|
||||
public function fillField(string $field, string $value): void
|
||||
{
|
||||
$field = $this->fixStepArgument($field);
|
||||
$value = $this->fixStepArgument($value);
|
||||
$this->getSession()->getPage()->fillField($field, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in form fields with provided table.
|
||||
* Example: When I fill in the following:
|
||||
* | username | bruceWayne |
|
||||
* | password | iLoveBats123 |.
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )fill in the following:$/')]
|
||||
public function fillFields(TableNode $fields)
|
||||
public function fillFields(TableNode $fields): void
|
||||
{
|
||||
foreach ($fields->getRowsHash() as $field => $value) {
|
||||
$this->fillField($field, $value);
|
||||
$this->fillField((string) $field, is_array($value) ? implode(',', $value) : $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects option in select field with specified id|name|label|value.
|
||||
* Example: When I select "Bats" from "user_fears"
|
||||
* Example: And I select "Bats" from "user_fears".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/')]
|
||||
public function selectOption($select, $option)
|
||||
public function selectOption(string $select, string $option): void
|
||||
{
|
||||
$select = $this->fixStepArgument($select);
|
||||
$option = $this->fixStepArgument($option);
|
||||
$this->getSession()->getPage()->selectFieldOption($select, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects additional option in select field with specified id|name|label|value.
|
||||
* Example: When I additionally select "Deceased" from "parents_alive_status"
|
||||
* Example: And I additionally select "Deceased" from "parents_alive_status".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )additionally select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/')]
|
||||
public function additionallySelectOption($select, $option)
|
||||
public function additionallySelectOption(string $select, string $option): void
|
||||
{
|
||||
$select = $this->fixStepArgument($select);
|
||||
$option = $this->fixStepArgument($option);
|
||||
$this->getSession()->getPage()->selectFieldOption($select, $option, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks checkbox with specified id|name|label|value.
|
||||
* Example: When I check "Pearl Necklace"
|
||||
* Example: And I check "Pearl Necklace".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )check "(?P<option>(?:[^"]|\\")*)"$/')]
|
||||
public function checkOption($option)
|
||||
public function checkOption(string $option): void
|
||||
{
|
||||
$option = $this->fixStepArgument($option);
|
||||
$this->getSession()->getPage()->checkField($option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unchecks checkbox with specified id|name|label|value.
|
||||
* Example: When I uncheck "Broadway Plays"
|
||||
* Example: And I uncheck "Broadway Plays".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )uncheck "(?P<option>(?:[^"]|\\")*)"$/')]
|
||||
public function uncheckOption($option)
|
||||
public function uncheckOption(string $option): void
|
||||
{
|
||||
$option = $this->fixStepArgument($option);
|
||||
$this->getSession()->getPage()->uncheckField($option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches file to field with specified id|name|label|value.
|
||||
* Example: When I attach the file "bwayne_profile.png" to "profileImageUpload"
|
||||
* Example: And I attach the file "bwayne_profile.png" to "profileImageUpload".
|
||||
*/
|
||||
#[\Behat\Step\When('/^(?:|I )attach the file "(?P<path>[^"]*)" to "(?P<field>(?:[^"]|\\")*)"$/')]
|
||||
public function attachFileToField($field, $path)
|
||||
public function attachFileToField(string $field, string $path): void
|
||||
{
|
||||
$field = $this->fixStepArgument($field);
|
||||
|
||||
if ($this->getMinkParameter('files_path')) {
|
||||
$fullPath = rtrim(realpath($this->getMinkParameter('files_path')), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$path;
|
||||
$filesPath = $this->getMinkParameter('files_path');
|
||||
if (is_string($filesPath) && '' !== $filesPath) {
|
||||
$realFilesPath = realpath($filesPath);
|
||||
if (false !== $realFilesPath) {
|
||||
$fullPath = rtrim($realFilesPath, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$path;
|
||||
if (is_file($fullPath)) {
|
||||
$path = $fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->getSession()->getPage()->attachFileToField($field, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current page PATH is equal to specified.
|
||||
* Example: Then I should be on "/"
|
||||
* Example: And I should be on "/bats"
|
||||
* Example: And I should be on "http://google.com".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should be on "(?P<page>[^"]+)"$/')]
|
||||
public function assertPageAddress($page)
|
||||
public function assertPageAddress(string $page): void
|
||||
{
|
||||
$this->assertSession()->addressEquals($this->locatePath($page));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current page is the homepage.
|
||||
* Example: Then I should be on the homepage
|
||||
* Example: And I should be on the homepage.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should be on (?:|the )homepage$/')]
|
||||
public function assertHomepage()
|
||||
public function assertHomepage(): void
|
||||
{
|
||||
$this->assertSession()->addressEquals($this->locatePath('/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current page PATH matches regular expression.
|
||||
* Example: Then the url should match "superman is dead"
|
||||
* Example: And the url should match "log in".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the (?i)url(?-i) should match (?P<pattern>"(?:[^"]|\\")*")$/')]
|
||||
public function assertUrlRegExp($pattern)
|
||||
public function assertUrlRegExp(string $pattern): void
|
||||
{
|
||||
$this->assertSession()->addressMatches($this->fixStepArgument($pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current page response status is equal to specified.
|
||||
* Example: Then the response status code should be 200
|
||||
* Example: And the response status code should be 400.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the response status code should be (?P<code>\d+)$/')]
|
||||
public function assertResponseStatus($code)
|
||||
public function assertResponseStatus(string $code): void
|
||||
{
|
||||
$this->assertSession()->statusCodeEquals($code);
|
||||
$this->assertSession()->statusCodeEquals((int) $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current page response status is not equal to specified.
|
||||
* Example: Then the response status code should not be 501
|
||||
* Example: And the response status code should not be 404.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the response status code should not be (?P<code>\d+)$/')]
|
||||
public function assertResponseStatusIsNot($code)
|
||||
public function assertResponseStatusIsNot(string $code): void
|
||||
{
|
||||
$this->assertSession()->statusCodeNotEquals($code);
|
||||
$this->assertSession()->statusCodeNotEquals((int) $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that page contains specified text.
|
||||
* Example: Then I should see "Who is the Batman?"
|
||||
* Example: And I should see "Who is the Batman?".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should see "(?P<text>(?:[^"]|\\")*)"$/')]
|
||||
public function assertPageContainsText($text)
|
||||
public function assertPageContainsText(string $text): void
|
||||
{
|
||||
$this->assertSession()->pageTextContains($this->fixStepArgument($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that page doesn't contain specified text.
|
||||
* Example: Then I should not see "Batman is Bruce Wayne"
|
||||
* Example: And I should not see "Batman is Bruce Wayne".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)"$/')]
|
||||
public function assertPageNotContainsText($text)
|
||||
public function assertPageNotContainsText(string $text): void
|
||||
{
|
||||
$this->assertSession()->pageTextNotContains($this->fixStepArgument($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that page contains text matching specified pattern.
|
||||
* Example: Then I should see text matching "Batman, the vigilante"
|
||||
* Example: And I should not see "Batman, the vigilante".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should see text matching (?P<pattern>"(?:[^"]|\\")*")$/')]
|
||||
public function assertPageMatchesText($pattern)
|
||||
public function assertPageMatchesText(string $pattern): void
|
||||
{
|
||||
$this->assertSession()->pageTextMatches($this->fixStepArgument($pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that page doesn't contain text matching specified pattern.
|
||||
* Example: Then I should not see text matching "Bruce Wayne, the vigilante"
|
||||
* Example: And I should not see "Bruce Wayne, the vigilante".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should not see text matching (?P<pattern>"(?:[^"]|\\")*")$/')]
|
||||
public function assertPageNotMatchesText($pattern)
|
||||
public function assertPageNotMatchesText(string $pattern): void
|
||||
{
|
||||
$this->assertSession()->pageTextNotMatches($this->fixStepArgument($pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that HTML response contains specified string.
|
||||
* Example: Then the response should contain "Batman is the hero Gotham deserves."
|
||||
* Example: And the response should contain "Batman is the hero Gotham deserves.".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the response should contain "(?P<text>(?:[^"]|\\")*)"$/')]
|
||||
public function assertResponseContains($text)
|
||||
public function assertResponseContains(string $text): void
|
||||
{
|
||||
$this->assertSession()->responseContains($this->fixStepArgument($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that HTML response doesn't contain specified string.
|
||||
* Example: Then the response should not contain "Bruce Wayne is a billionaire, play-boy, vigilante."
|
||||
* Example: And the response should not contain "Bruce Wayne is a billionaire, play-boy, vigilante.".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the response should not contain "(?P<text>(?:[^"]|\\")*)"$/')]
|
||||
public function assertResponseNotContains($text)
|
||||
public function assertResponseNotContains(string $text): void
|
||||
{
|
||||
$this->assertSession()->responseNotContains($this->fixStepArgument($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that element with specified CSS contains specified text.
|
||||
* Example: Then I should see "Batman" in the "heroes_list" element
|
||||
* Example: And I should see "Batman" in the "heroes_list" element.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/')]
|
||||
public function assertElementContainsText($element, $text)
|
||||
public function assertElementContainsText(string $element, string $text): void
|
||||
{
|
||||
$this->assertSession()->elementTextContains('css', $element, $this->fixStepArgument($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that element with specified CSS doesn't contain specified text.
|
||||
* Example: Then I should not see "Bruce Wayne" in the "heroes_alter_egos" element
|
||||
* Example: And I should not see "Bruce Wayne" in the "heroes_alter_egos" element.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/')]
|
||||
public function assertElementNotContainsText($element, $text)
|
||||
public function assertElementNotContainsText(string $element, string $text): void
|
||||
{
|
||||
$this->assertSession()->elementTextNotContains('css', $element, $this->fixStepArgument($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that element with specified CSS contains specified HTML.
|
||||
* Example: Then the "body" element should contain "style=\"color:black;\""
|
||||
* Example: And the "body" element should contain "style=\"color:black;\"".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the "(?P<element>[^"]*)" element should contain "(?P<value>(?:[^"]|\\")*)"$/')]
|
||||
public function assertElementContains($element, $value)
|
||||
public function assertElementContains(string $element, string $value): void
|
||||
{
|
||||
$this->assertSession()->elementContains('css', $element, $this->fixStepArgument($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that element with specified CSS doesn't contain specified HTML.
|
||||
* Example: Then the "body" element should not contain "style=\"color:black;\""
|
||||
* Example: And the "body" element should not contain "style=\"color:black;\"".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the "(?P<element>[^"]*)" element should not contain "(?P<value>(?:[^"]|\\")*)"$/')]
|
||||
public function assertElementNotContains($element, $value)
|
||||
public function assertElementNotContains(string $element, string $value): void
|
||||
{
|
||||
$this->assertSession()->elementNotContains('css', $element, $this->fixStepArgument($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that element with specified CSS exists on page.
|
||||
* Example: Then I should see a "body" element
|
||||
* Example: And I should see a "body" element.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should see an? "(?P<element>[^"]*)" element$/')]
|
||||
public function assertElementOnPage($element)
|
||||
public function assertElementOnPage(string $element): void
|
||||
{
|
||||
$this->assertSession()->elementExists('css', $element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that element with specified CSS doesn't exist on page.
|
||||
* Example: Then I should not see a "canvas" element
|
||||
* Example: And I should not see a "canvas" element.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should not see an? "(?P<element>[^"]*)" element$/')]
|
||||
public function assertElementNotOnPage($element)
|
||||
public function assertElementNotOnPage(string $element): void
|
||||
{
|
||||
$this->assertSession()->elementNotExists('css', $element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that form field with specified id|name|label|value has specified value.
|
||||
* Example: Then the "username" field should contain "bwayne"
|
||||
* Example: And the "username" field should contain "bwayne".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the "(?P<field>(?:[^"]|\\")*)" field should contain "(?P<value>(?:[^"]|\\")*)"$/')]
|
||||
public function assertFieldContains($field, $value)
|
||||
public function assertFieldContains(string $field, string $value): void
|
||||
{
|
||||
$field = $this->fixStepArgument($field);
|
||||
$value = $this->fixStepArgument($value);
|
||||
$this->assertSession()->fieldValueEquals($field, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that form field with specified id|name|label|value doesn't have specified value.
|
||||
* Example: Then the "username" field should not contain "batman"
|
||||
* Example: And the "username" field should not contain "batman".
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the "(?P<field>(?:[^"]|\\")*)" field should not contain "(?P<value>(?:[^"]|\\")*)"$/')]
|
||||
public function assertFieldNotContains($field, $value)
|
||||
public function assertFieldNotContains(string $field, string $value): void
|
||||
{
|
||||
$field = $this->fixStepArgument($field);
|
||||
$value = $this->fixStepArgument($value);
|
||||
$this->assertSession()->fieldValueNotEquals($field, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that (?P<num>\d+) CSS elements exist on the page.
|
||||
* Example: Then I should see 5 "div" elements
|
||||
* Example: And I should see 5 "div" elements.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^(?:|I )should see (?P<num>\d+) "(?P<element>[^"]*)" elements?$/')]
|
||||
public function assertNumElements($num, $element)
|
||||
public function assertNumElements(string $num, string $element): void
|
||||
{
|
||||
$this->assertSession()->elementsCount('css', $element, intval($num));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that checkbox with specified id|name|label|value is checked.
|
||||
* Example: Then the "remember_me" checkbox should be checked
|
||||
* Example: And the "remember_me" checkbox is checked.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should be checked$/')]
|
||||
#[\Behat\Step\Then('/^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox is checked$/')]
|
||||
#[\Behat\Step\Then('/^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" (?:is|should be) checked$/')]
|
||||
public function assertCheckboxChecked($checkbox)
|
||||
public function assertCheckboxChecked(string $checkbox): void
|
||||
{
|
||||
$this->assertSession()->checkboxChecked($this->fixStepArgument($checkbox));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that checkbox with specified id|name|label|value is unchecked.
|
||||
* Example: Then the "newsletter" checkbox should be unchecked
|
||||
* Example: Then the "newsletter" checkbox should not be checked
|
||||
* Example: And the "newsletter" checkbox is unchecked.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should (?:be unchecked|not be checked)$/')]
|
||||
#[\Behat\Step\Then('/^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox is (?:unchecked|not checked)$/')]
|
||||
#[\Behat\Step\Then('/^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" should (?:be unchecked|not be checked)$/')]
|
||||
#[\Behat\Step\Then('/^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" is (?:unchecked|not checked)$/')]
|
||||
public function assertCheckboxNotChecked($checkbox)
|
||||
public function assertCheckboxNotChecked(string $checkbox): void
|
||||
{
|
||||
$this->assertSession()->checkboxNotChecked($this->fixStepArgument($checkbox));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints current URL to console.
|
||||
* Example: Then print current URL
|
||||
* Example: And print current URL.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^print current URL$/')]
|
||||
public function printCurrentUrl()
|
||||
public function printCurrentUrl(): void
|
||||
{
|
||||
echo $this->getSession()->getCurrentUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints last response to console.
|
||||
* Example: Then print last response
|
||||
* Example: And print last response.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^print last response$/')]
|
||||
public function printLastResponse()
|
||||
public function printLastResponse(): void
|
||||
{
|
||||
echo (
|
||||
$this->getSession()->getCurrentUrl()."\n\n".
|
||||
echo $this->getSession()->getCurrentUrl()."\n\n".
|
||||
$this->getSession()->getPage()->getContent()
|
||||
);
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens last response content in browser.
|
||||
* Example: Then show last response
|
||||
* Example: And show last response.
|
||||
*/
|
||||
#[\Behat\Step\Then('/^show last response$/')]
|
||||
public function showLastResponse()
|
||||
public function showLastResponse(): void
|
||||
{
|
||||
if (null === $this->getMinkParameter('show_cmd')) {
|
||||
$showCmd = $this->getMinkParameter('show_cmd');
|
||||
if (null === $showCmd) {
|
||||
throw new \RuntimeException('Set "show_cmd" parameter in behat.yml to be able to open page in browser (ex.: "show_cmd: firefox %s")');
|
||||
}
|
||||
|
||||
$filename = rtrim($this->getMinkParameter('show_tmp_dir'), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.uniqid().'.html';
|
||||
$showTmpDir = $this->getMinkParameter('show_tmp_dir');
|
||||
$filename = rtrim(is_string($showTmpDir) ? $showTmpDir : sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.uniqid().'.html';
|
||||
file_put_contents($filename, $this->getSession()->getPage()->getContent());
|
||||
system(sprintf($this->getMinkParameter('show_cmd'), escapeshellarg($filename)));
|
||||
system(sprintf(is_string($showCmd) ? $showCmd : '', escapeshellarg($filename)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getTranslationResources(): array
|
||||
{
|
||||
return self::getMinkTranslationResources();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getMinkTranslationResources(): array
|
||||
{
|
||||
return glob(__DIR__.'/../../../../i18n/*.xliff') ?: [];
|
||||
}
|
||||
|
||||
protected function fixStepArgument($argument)
|
||||
protected function fixStepArgument(string $argument): string
|
||||
{
|
||||
return str_replace('\\"', '"', $argument);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
namespace Behat\MinkExtension\Context;
|
||||
|
||||
use Behat\Mink\Mink;
|
||||
use Behat\Mink\WebAssert;
|
||||
use Behat\Mink\Session;
|
||||
use Behat\Mink\WebAssert;
|
||||
|
||||
/**
|
||||
* Raw Mink context for Behat BDD tool.
|
||||
@@ -22,31 +22,28 @@ use Behat\Mink\Session;
|
||||
*/
|
||||
class RawMinkContext implements MinkAwareContext
|
||||
{
|
||||
private $mink;
|
||||
private $minkParameters;
|
||||
private ?Mink $mink = null;
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
private array $minkParameters = [];
|
||||
|
||||
/**
|
||||
* Sets Mink instance.
|
||||
*
|
||||
* @param Mink $mink Mink session manager
|
||||
*/
|
||||
public function setMink(Mink $mink)
|
||||
public function setMink(Mink $mink): void
|
||||
{
|
||||
$this->mink = $mink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Mink instance.
|
||||
*
|
||||
* @return Mink
|
||||
*/
|
||||
public function getMink()
|
||||
public function getMink(): Mink
|
||||
{
|
||||
if (null === $this->mink) {
|
||||
throw new \RuntimeException(
|
||||
'Mink instance has not been set on Mink context class. ' .
|
||||
'Have you enabled the Mink Extension?'
|
||||
);
|
||||
throw new \RuntimeException('Mink instance has not been set on Mink context class. Have you enabled the Mink Extension?');
|
||||
}
|
||||
|
||||
return $this->mink;
|
||||
@@ -55,9 +52,9 @@ class RawMinkContext implements MinkAwareContext
|
||||
/**
|
||||
* Returns the parameters provided for Mink.
|
||||
*
|
||||
* @return array
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getMinkParameters()
|
||||
public function getMinkParameters(): array
|
||||
{
|
||||
return $this->minkParameters;
|
||||
}
|
||||
@@ -65,21 +62,17 @@ class RawMinkContext implements MinkAwareContext
|
||||
/**
|
||||
* Sets parameters provided for Mink.
|
||||
*
|
||||
* @param array $parameters
|
||||
* @param array<string, mixed> $parameters
|
||||
*/
|
||||
public function setMinkParameters(array $parameters)
|
||||
public function setMinkParameters(array $parameters): void
|
||||
{
|
||||
$this->minkParameters = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns specific mink parameter.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMinkParameter($name)
|
||||
public function getMinkParameter(string $name): mixed
|
||||
{
|
||||
return isset($this->minkParameters[$name]) ? $this->minkParameters[$name] : null;
|
||||
}
|
||||
@@ -89,9 +82,9 @@ class RawMinkContext implements MinkAwareContext
|
||||
* feature context.
|
||||
*
|
||||
* @param string $name The key of the parameter
|
||||
* @param string $value The value of the parameter
|
||||
* @param mixed $value The value of the parameter
|
||||
*/
|
||||
public function setMinkParameter($name, $value)
|
||||
public function setMinkParameter(string $name, mixed $value): void
|
||||
{
|
||||
$this->minkParameters[$name] = $value;
|
||||
}
|
||||
@@ -100,10 +93,8 @@ class RawMinkContext implements MinkAwareContext
|
||||
* Returns Mink session.
|
||||
*
|
||||
* @param string|null $name name of the session OR active session will be used
|
||||
*
|
||||
* @return Session
|
||||
*/
|
||||
public function getSession($name = null)
|
||||
public function getSession(?string $name = null): Session
|
||||
{
|
||||
return $this->getMink()->getSession($name);
|
||||
}
|
||||
@@ -112,21 +103,16 @@ class RawMinkContext implements MinkAwareContext
|
||||
* Returns Mink session assertion tool.
|
||||
*
|
||||
* @param string|null $name name of the session OR active session will be used
|
||||
*
|
||||
* @return WebAssert
|
||||
*/
|
||||
public function assertSession($name = null)
|
||||
public function assertSession(?string $name = null): WebAssert
|
||||
{
|
||||
return $this->getMink()->assertSession($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits provided relative path using provided or default session.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string|null $sessionName
|
||||
*/
|
||||
public function visitPath($path, $sessionName = null)
|
||||
public function visitPath(string $path, ?string $sessionName = null): void
|
||||
{
|
||||
$this->getSession($sessionName)->visit($this->locatePath($path));
|
||||
}
|
||||
@@ -134,14 +120,11 @@ class RawMinkContext implements MinkAwareContext
|
||||
/**
|
||||
* Locates url, based on provided path.
|
||||
* Override to provide custom routing mechanism.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function locatePath($path)
|
||||
public function locatePath(string $path): string
|
||||
{
|
||||
$startUrl = rtrim($this->getMinkParameter('base_url') ?? '', '/') . '/';
|
||||
$baseUrl = $this->getMinkParameter('base_url');
|
||||
$startUrl = rtrim(is_string($baseUrl) ? $baseUrl : '', '/').'/';
|
||||
|
||||
return 0 !== strpos($path, 'http') ? $startUrl.ltrim($path, '/') : $path;
|
||||
}
|
||||
@@ -154,12 +137,13 @@ class RawMinkContext implements MinkAwareContext
|
||||
* @param string $filepath Desired filepath, defaults to
|
||||
* upload_tmp_dir, falls back to sys_get_temp_dir()
|
||||
*/
|
||||
public function saveScreenshot($filename = null, $filepath = null)
|
||||
public function saveScreenshot(?string $filename = null, ?string $filepath = null): void
|
||||
{
|
||||
// Under Cygwin, uniqid with more_entropy must be set to true.
|
||||
// No effect in other environments.
|
||||
$filename = $filename ?: sprintf('%s_%s_%s.%s', $this->getMinkParameter('browser_name'), date('c'), uniqid('', true), 'png');
|
||||
$filepath = $filepath ?: (ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir());
|
||||
$browserName = $this->getMinkParameter('browser_name');
|
||||
$filename = $filename ?: sprintf('%s_%s_%s.%s', is_string($browserName) ? $browserName : '', date('c'), uniqid('', true), 'png');
|
||||
$filepath = $filepath ?: (ini_get('upload_tmp_dir') ?: sys_get_temp_dir());
|
||||
file_put_contents($filepath.'/'.$filename, $this->getSession()->getScreenshot());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ namespace Behat\MinkExtension\Listener;
|
||||
|
||||
use Behat\Behat\EventDispatcher\Event\AfterStepTested;
|
||||
use Behat\Behat\EventDispatcher\Event\StepTested;
|
||||
use Behat\Mink\Exception\Exception as MinkException;
|
||||
use Behat\Mink\Mink;
|
||||
use Behat\Testwork\Tester\Result\ExceptionResult;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Behat\Mink\Mink;
|
||||
use Behat\Mink\Exception\Exception as MinkException;
|
||||
|
||||
/**
|
||||
* Failed step response show listener.
|
||||
@@ -24,18 +24,20 @@ use Behat\Mink\Exception\Exception as MinkException;
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*
|
||||
* @final since 2.8.0
|
||||
*
|
||||
* @internal since 2.8.0
|
||||
*/
|
||||
class FailureShowListener implements EventSubscriberInterface
|
||||
{
|
||||
private $mink;
|
||||
private $parameters;
|
||||
private Mink $mink;
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
private array $parameters;
|
||||
|
||||
/**
|
||||
* Initializes initializer.
|
||||
*
|
||||
* @param Mink $mink
|
||||
* @param array $parameters
|
||||
* @param array<string, mixed> $parameters
|
||||
*/
|
||||
public function __construct(Mink $mink, array $parameters)
|
||||
{
|
||||
@@ -43,14 +45,11 @@ class FailureShowListener implements EventSubscriberInterface
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return array(
|
||||
StepTested::AFTER => array('showFailedStepResponse', -10)
|
||||
);
|
||||
return [
|
||||
StepTested::AFTER => ['showFailedStepResponse', -10],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,11 +61,9 @@ class FailureShowListener implements EventSubscriberInterface
|
||||
* `show_cmd` command to run (`open %s` to open default browser on Mac)
|
||||
* `show_tmp_dir` folder where to store temp files (default is system temp)
|
||||
*
|
||||
* @param AfterStepTested $event
|
||||
*
|
||||
* @throws \RuntimeException if show_cmd is not configured
|
||||
*/
|
||||
public function showFailedStepResponse(AfterStepTested $event)
|
||||
public function showFailedStepResponse(AfterStepTested $event): void
|
||||
{
|
||||
$testResult = $event->getTestResult();
|
||||
|
||||
@@ -78,12 +75,14 @@ class FailureShowListener implements EventSubscriberInterface
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $this->parameters['show_cmd']) {
|
||||
$showCmd = $this->parameters['show_cmd'];
|
||||
if (null === $showCmd) {
|
||||
throw new \RuntimeException('Set "show_cmd" parameter in behat.yml to be able to open page in browser (ex.: "show_cmd: open %s")');
|
||||
}
|
||||
|
||||
$filename = rtrim($this->parameters['show_tmp_dir'], DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.uniqid().'.html';
|
||||
$showTmpDir = $this->parameters['show_tmp_dir'];
|
||||
$filename = rtrim(is_string($showTmpDir) ? $showTmpDir : sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.uniqid().'.html';
|
||||
file_put_contents($filename, $this->mink->getSession()->getPage()->getContent());
|
||||
system(sprintf($this->parameters['show_cmd'], escapeshellarg($filename)));
|
||||
system(sprintf(is_string($showCmd) ? $showCmd : '', escapeshellarg($filename)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Behat\MinkExtension\Listener;
|
||||
|
||||
use Behat\Behat\EventDispatcher\Event\ExampleTested;
|
||||
use Behat\Behat\EventDispatcher\Event\ScenarioTested;
|
||||
use Behat\Gherkin\Node\TaggedNodeInterface;
|
||||
use Behat\Mink\Mink;
|
||||
use Behat\Testwork\EventDispatcher\Event\ExerciseCompleted;
|
||||
use Behat\Testwork\ServiceContainer\Exception\ProcessingException;
|
||||
@@ -26,28 +27,26 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*
|
||||
* @final since 2.8.0
|
||||
*
|
||||
* @internal since 2.8.0
|
||||
*/
|
||||
class SessionsListener implements EventSubscriberInterface
|
||||
{
|
||||
private $mink;
|
||||
private $defaultSession;
|
||||
private $javascriptSession;
|
||||
private Mink $mink;
|
||||
private string $defaultSession;
|
||||
private ?string $javascriptSession;
|
||||
|
||||
/**
|
||||
* @var string[] The available javascript sessions
|
||||
*/
|
||||
private $availableJavascriptSessions;
|
||||
private array $availableJavascriptSessions;
|
||||
|
||||
/**
|
||||
* Initializes initializer.
|
||||
*
|
||||
* @param Mink $mink
|
||||
* @param string $defaultSession
|
||||
* @param string|null $javascriptSession
|
||||
* @param string[] $availableJavascriptSessions
|
||||
*/
|
||||
public function __construct(Mink $mink, $defaultSession, $javascriptSession, array $availableJavascriptSessions = array())
|
||||
public function __construct(Mink $mink, string $defaultSession, ?string $javascriptSession, array $availableJavascriptSessions = [])
|
||||
{
|
||||
$this->mink = $mink;
|
||||
$this->defaultSession = $defaultSession;
|
||||
@@ -55,16 +54,13 @@ class SessionsListener implements EventSubscriberInterface
|
||||
$this->availableJavascriptSessions = $availableJavascriptSessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return array(
|
||||
ScenarioTested::BEFORE => array('prepareDefaultMinkSession', 10),
|
||||
ExampleTested::BEFORE => array('prepareDefaultMinkSession', 10),
|
||||
ExerciseCompleted::AFTER => array('tearDownMinkSessions', -10)
|
||||
);
|
||||
return [
|
||||
ScenarioTested::BEFORE => ['prepareDefaultMinkSession', 10],
|
||||
ExampleTested::BEFORE => ['prepareDefaultMinkSession', 10],
|
||||
ExerciseCompleted::AFTER => ['tearDownMinkSessions', -10],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,17 +74,16 @@ class SessionsListener implements EventSubscriberInterface
|
||||
* `@insulated` tag will cause Mink to stop current sessions before scenario
|
||||
* instead of just soft-resetting them
|
||||
*
|
||||
* @param ScenarioTested $event
|
||||
*
|
||||
* @throws ProcessingException when the @javascript tag is used without a javascript session
|
||||
*/
|
||||
public function prepareDefaultMinkSession(ScenarioTested $event)
|
||||
public function prepareDefaultMinkSession(ScenarioTested $event): void
|
||||
{
|
||||
$scenario = $event->getScenario();
|
||||
$feature = $event->getFeature();
|
||||
$session = null;
|
||||
|
||||
foreach (array_merge($feature->getTags(), $scenario->getTags()) as $tag) {
|
||||
$scenarioTags = $scenario instanceof TaggedNodeInterface ? $scenario->getTags() : [];
|
||||
foreach (array_merge($feature->getTags(), $scenarioTags) as $tag) {
|
||||
if ('javascript' === $tag) {
|
||||
$session = $this->getJavascriptSession($event->getSuite());
|
||||
} elseif (preg_match('/^mink\:(.+)/', $tag, $matches)) {
|
||||
@@ -100,7 +95,9 @@ class SessionsListener implements EventSubscriberInterface
|
||||
$session = $this->getDefaultSession($event->getSuite());
|
||||
}
|
||||
|
||||
if ($scenario->hasTag('insulated') || $feature->hasTag('insulated')) {
|
||||
$isInsulated = ($scenario instanceof TaggedNodeInterface && $scenario->hasTag('insulated'))
|
||||
|| $feature->hasTag('insulated');
|
||||
if ($isInsulated) {
|
||||
$this->mink->stopSessions();
|
||||
} else {
|
||||
$this->mink->resetSessions();
|
||||
@@ -112,12 +109,12 @@ class SessionsListener implements EventSubscriberInterface
|
||||
/**
|
||||
* Stops all started Mink sessions.
|
||||
*/
|
||||
public function tearDownMinkSessions()
|
||||
public function tearDownMinkSessions(): void
|
||||
{
|
||||
$this->mink->stopSessions();
|
||||
}
|
||||
|
||||
private function getDefaultSession(Suite $suite)
|
||||
private function getDefaultSession(Suite $suite): string
|
||||
{
|
||||
if (!$suite->hasSetting('mink_session')) {
|
||||
return $this->defaultSession;
|
||||
@@ -126,20 +123,13 @@ class SessionsListener implements EventSubscriberInterface
|
||||
$session = $suite->getSetting('mink_session');
|
||||
|
||||
if (!is_string($session)) {
|
||||
throw new SuiteConfigurationException(
|
||||
sprintf(
|
||||
'`mink_session` setting of the "%s" suite is expected to be a string, %s given.',
|
||||
$suite->getName(),
|
||||
gettype($session)
|
||||
),
|
||||
$suite->getName()
|
||||
);
|
||||
throw new SuiteConfigurationException(sprintf('`mink_session` setting of the "%s" suite is expected to be a string, %s given.', $suite->getName(), gettype($session)), $suite->getName());
|
||||
}
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
private function getJavascriptSession(Suite $suite)
|
||||
private function getJavascriptSession(Suite $suite): string
|
||||
{
|
||||
if (!$suite->hasSetting('mink_javascript_session')) {
|
||||
if (null === $this->javascriptSession) {
|
||||
@@ -152,26 +142,11 @@ class SessionsListener implements EventSubscriberInterface
|
||||
$session = $suite->getSetting('mink_javascript_session');
|
||||
|
||||
if (!is_string($session)) {
|
||||
throw new SuiteConfigurationException(
|
||||
sprintf(
|
||||
'`mink_javascript_session` setting of the "%s" suite is expected to be a string, %s given.',
|
||||
$suite->getName(),
|
||||
gettype($session)
|
||||
),
|
||||
$suite->getName()
|
||||
);
|
||||
throw new SuiteConfigurationException(sprintf('`mink_javascript_session` setting of the "%s" suite is expected to be a string, %s given.', $suite->getName(), gettype($session)), $suite->getName());
|
||||
}
|
||||
|
||||
if (!in_array($session, $this->availableJavascriptSessions)) {
|
||||
throw new SuiteConfigurationException(
|
||||
sprintf(
|
||||
'`mink_javascript_session` setting of the "%s" suite is not a javascript session. %s given but expected one of %s.',
|
||||
$suite->getName(),
|
||||
$session,
|
||||
implode(', ', $this->availableJavascriptSessions)
|
||||
),
|
||||
$suite->getName()
|
||||
);
|
||||
throw new SuiteConfigurationException(sprintf('`mink_javascript_session` setting of the "%s" suite is not a javascript session. %s given but expected one of %s.', $suite->getName(), $session, implode(', ', $this->availableJavascriptSessions)), $suite->getName());
|
||||
}
|
||||
|
||||
return $session;
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class AppiumFactory extends Selenium2Factory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'appium';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -31,18 +25,18 @@ class AppiumFactory extends Selenium2Factory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
$host = $config['appium_host'].":".$config['appium_port'];
|
||||
$host = (is_string($config['appium_host']) ? $config['appium_host'] : '').':'.(is_string($config['appium_port']) ? $config['appium_port'] : '');
|
||||
|
||||
$config['wd_host'] = sprintf('%s/wd/hub', $host);
|
||||
|
||||
return parent::buildDriver($config);
|
||||
}
|
||||
|
||||
protected function getCapabilitiesNode()
|
||||
protected function getCapabilitiesNode(): ArrayNodeDefinition
|
||||
{
|
||||
$node = parent::getCapabilitiesNode();
|
||||
|
||||
|
||||
@@ -10,34 +10,24 @@
|
||||
namespace Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use Behat\Mink\Driver\BrowserKitDriver;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
|
||||
|
||||
class BrowserKitFactory implements DriverFactory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'browserkit_http';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript()
|
||||
public function supportsJavascript(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -51,9 +41,9 @@ class BrowserKitFactory implements DriverFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
if (!class_exists(BrowserKitDriver::class)) {
|
||||
throw new \RuntimeException('Install behat/mink-browserkit-driver in order to use the browserkit_http driver.');
|
||||
@@ -77,5 +67,4 @@ class BrowserKitFactory implements DriverFactory
|
||||
'%mink.base_url%',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,21 +11,16 @@
|
||||
namespace Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class BrowserStackFactory extends Selenium2Factory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'browser_stack';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -38,16 +33,16 @@ class BrowserStackFactory extends Selenium2Factory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
$config['wd_host'] = sprintf('%s:%s@hub.browserstack.com/wd/hub', $config['username'], $config['access_key']);
|
||||
$config['wd_host'] = sprintf('%s:%s@hub.browserstack.com/wd/hub', is_string($config['username']) ? $config['username'] : '', is_string($config['access_key']) ? $config['access_key'] : '');
|
||||
|
||||
return parent::buildDriver($config);
|
||||
}
|
||||
|
||||
protected function getCapabilitiesNode()
|
||||
protected function getCapabilitiesNode(): ArrayNodeDefinition
|
||||
{
|
||||
$node = parent::getCapabilitiesNode();
|
||||
|
||||
|
||||
@@ -18,35 +18,14 @@ use Symfony\Component\DependencyInjection\Definition;
|
||||
*/
|
||||
interface DriverFactory
|
||||
{
|
||||
/**
|
||||
* Gets the name of the driver being configured.
|
||||
*
|
||||
* This will be the key of the configuration for the driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDriverName();
|
||||
public function getDriverName(): string;
|
||||
|
||||
public function supportsJavascript(): bool;
|
||||
|
||||
public function configure(ArrayNodeDefinition $builder): void;
|
||||
|
||||
/**
|
||||
* Defines whether a session using this driver is eligible as default javascript session
|
||||
*
|
||||
* @return boolean
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function supportsJavascript();
|
||||
|
||||
/**
|
||||
* Setups configuration for the driver factory.
|
||||
*
|
||||
* @param ArrayNodeDefinition $builder
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder);
|
||||
|
||||
/**
|
||||
* Builds the service definition for the driver.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return Definition
|
||||
*/
|
||||
public function buildDriver(array $config);
|
||||
public function buildDriver(array $config): Definition;
|
||||
}
|
||||
|
||||
@@ -7,12 +7,18 @@ namespace Behat\MinkExtension\ServiceContainer\Driver;
|
||||
*/
|
||||
trait EnvironmentCapabilities
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function guessEnvironmentCapabilities(): array
|
||||
{
|
||||
$travisJobNumber = getenv('TRAVIS_JOB_NUMBER');
|
||||
$jenkinsHome = getenv('JENKINS_HOME');
|
||||
|
||||
switch (true) {
|
||||
case (bool)getenv('TRAVIS_JOB_NUMBER'):
|
||||
case (bool) $travisJobNumber:
|
||||
return [
|
||||
'tunnel-identifier' => getenv('TRAVIS_JOB_NUMBER'),
|
||||
'tunnel-identifier' => $travisJobNumber,
|
||||
'build' => getenv('TRAVIS_BUILD_NUMBER'),
|
||||
'tags' => [
|
||||
'Travis-CI',
|
||||
@@ -20,7 +26,7 @@ trait EnvironmentCapabilities
|
||||
],
|
||||
];
|
||||
|
||||
case (bool)getenv('JENKINS_HOME'):
|
||||
case (bool) $jenkinsHome:
|
||||
return [
|
||||
'tunnel-identifier' => getenv('JOB_NAME'),
|
||||
'build' => getenv('BUILD_NUMBER'),
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Behat MinkExtension.
|
||||
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
/**
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class GoutteFactory implements DriverFactory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
{
|
||||
return 'goutte';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
->arrayNode('server_parameters')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('variable')->end()
|
||||
->end()
|
||||
->arrayNode('guzzle_parameters')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('variable')->end()
|
||||
->info(
|
||||
"For Goutte 1.x, these are the second argument of the Guzzle3 client constructor.\n".
|
||||
'For Goutte 2.x, these are the elements passed in the "defaults" key of the Guzzle4 config.'
|
||||
)
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
{
|
||||
trigger_deprecation('friends-of-behat/mink-extension', '2.8.0', 'Configuration for the "goutte" driver is deprecated, since the client implementation has been abandoned. Support for it will be removed in the next major version of this extension.');
|
||||
|
||||
if (!class_exists('Behat\Mink\Driver\GoutteDriver')) {
|
||||
throw new \RuntimeException(
|
||||
'Install MinkGoutteDriver in order to use goutte driver.'
|
||||
);
|
||||
}
|
||||
|
||||
$clientArguments = array(
|
||||
$config['server_parameters'],
|
||||
);
|
||||
$guzzleClient = null;
|
||||
|
||||
if ($this->isGoutte4()) {
|
||||
$clientArguments = array();
|
||||
|
||||
if (class_exists('Symfony\Component\HttpClient\HttpClient')) {
|
||||
$httpClient = new Definition('Symfony\Component\HttpClient\HttpClient');
|
||||
$httpClient->setFactory('Symfony\Component\HttpClient\HttpClient::create');
|
||||
$httpClient->setArgument(0, $config['server_parameters']);
|
||||
$clientArguments = array($httpClient);
|
||||
}
|
||||
} elseif ($this->isGoutte1()) {
|
||||
$guzzleClient = $this->buildGuzzle3Client($config['guzzle_parameters']);
|
||||
} elseif ($this->isGuzzle6()) {
|
||||
$guzzleClient = $this->buildGuzzle6Client($config['guzzle_parameters']);
|
||||
} else {
|
||||
$guzzleClient = $this->buildGuzzle4Client($config['guzzle_parameters']);
|
||||
}
|
||||
|
||||
$clientDefinition = new Definition('Behat\Mink\Driver\Goutte\Client', $clientArguments);
|
||||
|
||||
if (null !== $guzzleClient) {
|
||||
$clientDefinition->addMethodCall('setClient', array($guzzleClient));
|
||||
}
|
||||
|
||||
return new Definition('Behat\Mink\Driver\GoutteDriver', array(
|
||||
$clientDefinition,
|
||||
));
|
||||
}
|
||||
|
||||
private function buildGuzzle6Client(array $parameters)
|
||||
{
|
||||
// Force the parameters set by default in Goutte to reproduce its behavior
|
||||
$parameters['allow_redirects'] = false;
|
||||
$parameters['cookies'] = true;
|
||||
|
||||
return new Definition('GuzzleHttp\Client', array($parameters));
|
||||
}
|
||||
|
||||
private function buildGuzzle4Client(array $parameters)
|
||||
{
|
||||
// Force the parameters set by default in Goutte to reproduce its behavior
|
||||
$parameters['allow_redirects'] = false;
|
||||
$parameters['cookies'] = true;
|
||||
|
||||
return new Definition('GuzzleHttp\Client', array(array('defaults' => $parameters)));
|
||||
}
|
||||
|
||||
private function buildGuzzle3Client(array $parameters)
|
||||
{
|
||||
// Force the parameters set by default in Goutte to reproduce its behavior
|
||||
$parameters['redirect.disable'] = true;
|
||||
|
||||
return new Definition('Guzzle\Http\Client', array(null, $parameters));
|
||||
}
|
||||
|
||||
private function isGoutte4()
|
||||
{
|
||||
$client = 'Goutte\Client';
|
||||
|
||||
return class_exists($client) && is_a($client, 'Symfony\Component\BrowserKit\HttpBrowser', true);
|
||||
}
|
||||
|
||||
private function isGoutte1()
|
||||
{
|
||||
$refl = new \ReflectionParameter(array('Goutte\Client', 'setClient'), 0);
|
||||
|
||||
$type = $refl->getType();
|
||||
if ($type instanceof \ReflectionNamedType && 'Guzzle\Http\ClientInterface' === $type->getName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isGuzzle6()
|
||||
{
|
||||
return interface_exists('GuzzleHttp\ClientInterface') &&
|
||||
version_compare(\GuzzleHttp\ClientInterface::VERSION, '6.0.0', '>=');
|
||||
}
|
||||
}
|
||||
@@ -15,26 +15,17 @@ use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class SahiFactory implements DriverFactory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'sahi';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript()
|
||||
public function supportsJavascript(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -48,29 +39,27 @@ class SahiFactory implements DriverFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
trigger_deprecation('friends-of-behat/mink-extension', '2.8.0', 'Configuration for the "sahi" driver is deprecated, since the client implementation has been abandoned. Support for it will be removed in the next major version of this extension.');
|
||||
|
||||
if (!class_exists('Behat\Mink\Driver\SahiDriver')) {
|
||||
throw new \RuntimeException(
|
||||
'Install MinkSahiDriver in order to use sahi driver.'
|
||||
);
|
||||
throw new \RuntimeException('Install MinkSahiDriver in order to use sahi driver.');
|
||||
}
|
||||
|
||||
return new Definition('Behat\Mink\Driver\SahiDriver', array(
|
||||
return new Definition('Behat\Mink\Driver\SahiDriver', [
|
||||
'%mink.browser_name%',
|
||||
new Definition('Behat\SahiClient\Client', array(
|
||||
new Definition('Behat\SahiClient\Connection', array(
|
||||
new Definition('Behat\SahiClient\Client', [
|
||||
new Definition('Behat\SahiClient\Connection', [
|
||||
$config['sid'],
|
||||
$config['host'],
|
||||
$config['port'],
|
||||
$config['browser'],
|
||||
$config['limit'],
|
||||
)),
|
||||
)),
|
||||
));
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,21 +11,16 @@
|
||||
namespace Behat\MinkExtension\ServiceContainer\Driver;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class SauceLabsFactory extends Selenium2Factory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'sauce_labs';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -39,21 +34,21 @@ class SauceLabsFactory extends Selenium2Factory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
$host = 'ondemand.saucelabs.com';
|
||||
if ($config['connect']) {
|
||||
if ((bool) $config['connect']) {
|
||||
$host = 'localhost:4445';
|
||||
}
|
||||
|
||||
$config['wd_host'] = sprintf('%s:%s@%s/wd/hub', $config['username'], $config['access_key'], $host);
|
||||
$config['wd_host'] = sprintf('%s:%s@%s/wd/hub', is_string($config['username']) ? $config['username'] : '', is_string($config['access_key']) ? $config['access_key'] : '', $host);
|
||||
|
||||
return parent::buildDriver($config);
|
||||
}
|
||||
|
||||
protected function getCapabilitiesNode()
|
||||
protected function getCapabilitiesNode(): ArrayNodeDefinition
|
||||
{
|
||||
$node = parent::getCapabilitiesNode();
|
||||
|
||||
@@ -84,9 +79,11 @@ class SauceLabsFactory extends Selenium2Factory
|
||||
->booleanNode('disable-popup-handler')->end()
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {return empty($v['custom-data']);})
|
||||
->then(function ($v) {
|
||||
->ifTrue(function (mixed $v): bool {return !is_array($v) || empty($v['custom-data']); })
|
||||
->then(function (mixed $v): mixed {
|
||||
if (is_array($v)) {
|
||||
unset($v['custom-data']);
|
||||
}
|
||||
|
||||
return $v;
|
||||
})
|
||||
|
||||
@@ -17,26 +17,17 @@ class Selenium2Factory implements DriverFactory
|
||||
{
|
||||
use EnvironmentCapabilities;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'selenium2';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript()
|
||||
public function supportsJavascript(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -48,28 +39,26 @@ class Selenium2Factory implements DriverFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
if (!class_exists('Behat\Mink\Driver\Selenium2Driver')) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Install MinkSelenium2Driver in order to use %s driver.',
|
||||
$this->getDriverName()
|
||||
));
|
||||
throw new \RuntimeException(sprintf('Install MinkSelenium2Driver in order to use %s driver.', $this->getDriverName()));
|
||||
}
|
||||
|
||||
$extraCapabilities = $config['capabilities']['extra_capabilities'];
|
||||
unset($config['capabilities']['extra_capabilities']);
|
||||
$capabilities = is_array($config['capabilities']) ? $config['capabilities'] : [];
|
||||
$extraCapabilities = is_array($capabilities['extra_capabilities']) ? $capabilities['extra_capabilities'] : [];
|
||||
unset($capabilities['extra_capabilities']);
|
||||
|
||||
return new Definition('Behat\Mink\Driver\Selenium2Driver', array(
|
||||
return new Definition('Behat\Mink\Driver\Selenium2Driver', [
|
||||
$config['browser'],
|
||||
array_replace($this->guessEnvironmentCapabilities(), $extraCapabilities, $config['capabilities']),
|
||||
array_replace($this->guessEnvironmentCapabilities(), $extraCapabilities, $capabilities),
|
||||
$config['wd_host'],
|
||||
));
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getCapabilitiesNode()
|
||||
protected function getCapabilitiesNode(): ArrayNodeDefinition
|
||||
{
|
||||
$node = new ArrayNodeDefinition('capabilities');
|
||||
|
||||
@@ -106,7 +95,7 @@ class Selenium2Factory implements DriverFactory
|
||||
->scalarNode('sslProxy')->end()
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
->ifTrue(function (mixed $v): bool {
|
||||
return empty($v);
|
||||
})
|
||||
->thenUnset()
|
||||
@@ -116,8 +105,8 @@ class Selenium2Factory implements DriverFactory
|
||||
->children()
|
||||
->scalarNode('profile')
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
return !file_exists($v);
|
||||
->ifTrue(function (mixed $v): bool {
|
||||
return !is_string($v) || !file_exists($v);
|
||||
})
|
||||
->thenInvalid('Cannot find profile zip file %s')
|
||||
->end()
|
||||
@@ -137,11 +126,14 @@ class Selenium2Factory implements DriverFactory
|
||||
->end()
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
return empty($v['prefs']);
|
||||
->ifTrue(function (mixed $v): bool {
|
||||
return !is_array($v) || empty($v['prefs']);
|
||||
})
|
||||
->then(function ($v) {
|
||||
->then(function (mixed $v): mixed {
|
||||
if (is_array($v)) {
|
||||
unset($v['prefs']);
|
||||
}
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
|
||||
@@ -17,26 +17,17 @@ class Selenium4Factory implements DriverFactory
|
||||
{
|
||||
use EnvironmentCapabilities;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'selenium4';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript()
|
||||
public function supportsJavascript(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -49,28 +40,25 @@ class Selenium4Factory implements DriverFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
if (!class_exists('Behat\Mink\Driver\Selenium4Driver')) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Install MinkSelenium4Driver in order to use %s driver.',
|
||||
$this->getDriverName()
|
||||
));
|
||||
throw new \RuntimeException(sprintf('Install MinkSelenium4Driver in order to use %s driver.', $this->getDriverName()));
|
||||
}
|
||||
|
||||
return new Definition('Behat\Mink\Driver\Selenium4Driver', array(
|
||||
return new Definition('Behat\Mink\Driver\Selenium4Driver', [
|
||||
$config['browser'],
|
||||
array_merge(
|
||||
$this->guessEnvironmentCapabilities(),
|
||||
$config['capabilities']
|
||||
is_array($config['capabilities']) ? $config['capabilities'] : []
|
||||
),
|
||||
$config['wd_host'],
|
||||
));
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getCapabilitiesNode()
|
||||
protected function getCapabilitiesNode(): ArrayNodeDefinition
|
||||
{
|
||||
$node = new ArrayNodeDefinition('capabilities');
|
||||
|
||||
|
||||
@@ -15,26 +15,17 @@ use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class SeleniumFactory implements DriverFactory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'selenium';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript()
|
||||
public function supportsJavascript(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -46,25 +37,23 @@ class SeleniumFactory implements DriverFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
trigger_deprecation('friends-of-behat/mink-extension', '2.8.0', 'Configuration for the "selenium" driver is deprecated, since the client implementation has been abandoned. Support for it will be removed in the next major version of this extension.');
|
||||
|
||||
if (!class_exists('Behat\Mink\Driver\SeleniumDriver')) {
|
||||
throw new \RuntimeException(
|
||||
'Install MinkSeleniumDriver in order to activate selenium session.'
|
||||
);
|
||||
throw new \RuntimeException('Install MinkSeleniumDriver in order to activate selenium session.');
|
||||
}
|
||||
|
||||
return new Definition('Behat\Mink\Driver\SeleniumDriver', array(
|
||||
return new Definition('Behat\Mink\Driver\SeleniumDriver', [
|
||||
$config['browser'],
|
||||
'%mink.base_url%',
|
||||
new Definition('Selenium\Client', array(
|
||||
new Definition('Selenium\Client', [
|
||||
$config['host'],
|
||||
$config['port'],
|
||||
)),
|
||||
));
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,25 +10,16 @@ class WebdriverClassicFactory implements DriverFactory
|
||||
{
|
||||
use EnvironmentCapabilities;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'webdriver_classic';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
@@ -44,21 +35,19 @@ class WebdriverClassicFactory implements DriverFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
if (!class_exists(WebdriverClassicDriver::class)) {
|
||||
throw new \RuntimeException(
|
||||
"Install mink/webdriver-classic-driver in order to use the {$this->getDriverName()} driver."
|
||||
);
|
||||
throw new \RuntimeException("Install mink/webdriver-classic-driver in order to use the {$this->getDriverName()} driver.");
|
||||
}
|
||||
|
||||
return new Definition(WebdriverClassicDriver::class, [
|
||||
$config['browser'],
|
||||
array_merge(
|
||||
$this->guessEnvironmentCapabilities(),
|
||||
$config['capabilities']
|
||||
is_array($config['capabilities']) ? $config['capabilities'] : []
|
||||
),
|
||||
$config['wd_host'],
|
||||
]);
|
||||
|
||||
@@ -15,26 +15,17 @@ use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class ZombieFactory implements DriverFactory
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverName()
|
||||
public function getDriverName(): string
|
||||
{
|
||||
return 'zombie';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsJavascript()
|
||||
public function supportsJavascript(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder)
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
@@ -49,27 +40,25 @@ class ZombieFactory implements DriverFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
public function buildDriver(array $config)
|
||||
public function buildDriver(array $config): Definition
|
||||
{
|
||||
trigger_deprecation('friends-of-behat/mink-extension', '2.8.0', 'Configuration for the "zombie" driver is deprecated, since the client implementation has been abandoned. Support for it will be removed in the next major version of this extension.');
|
||||
|
||||
if (!class_exists('Behat\Mink\Driver\ZombieDriver')) {
|
||||
throw new \RuntimeException(
|
||||
'Install MinkZombieDriver in order to use zombie driver.'
|
||||
);
|
||||
throw new \RuntimeException('Install MinkZombieDriver in order to use zombie driver.');
|
||||
}
|
||||
|
||||
return new Definition('Behat\Mink\Driver\ZombieDriver', array(
|
||||
new Definition('Behat\Mink\Driver\NodeJS\Server\ZombieServer', array(
|
||||
return new Definition('Behat\Mink\Driver\ZombieDriver', [
|
||||
new Definition('Behat\Mink\Driver\NodeJS\Server\ZombieServer', [
|
||||
$config['host'],
|
||||
$config['port'],
|
||||
$config['node_bin'],
|
||||
$config['server_path'],
|
||||
$config['threshold'],
|
||||
$config['node_modules_path'],
|
||||
)),
|
||||
));
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ use Behat\MinkExtension\ServiceContainer\Driver\AppiumFactory;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\BrowserKitFactory;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\BrowserStackFactory;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\DriverFactory;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\GoutteFactory;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\SahiFactory;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\SauceLabsFactory;
|
||||
use Behat\MinkExtension\ServiceContainer\Driver\Selenium2Factory;
|
||||
@@ -43,19 +42,18 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
*/
|
||||
class MinkExtension implements ExtensionInterface
|
||||
{
|
||||
const MINK_ID = 'mink';
|
||||
const SELECTORS_HANDLER_ID = 'mink.selectors_handler';
|
||||
public const MINK_ID = 'mink';
|
||||
public const SELECTORS_HANDLER_ID = 'mink.selectors_handler';
|
||||
|
||||
const SELECTOR_TAG = 'mink.selector';
|
||||
public const SELECTOR_TAG = 'mink.selector';
|
||||
|
||||
/**
|
||||
* @var DriverFactory[]
|
||||
*/
|
||||
private $driverFactories = array();
|
||||
private $driverFactories = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->registerDriverFactory(new GoutteFactory());
|
||||
$this->registerDriverFactory(new BrowserKitFactory());
|
||||
$this->registerDriverFactory(new SahiFactory());
|
||||
$this->registerDriverFactory(new SeleniumFactory());
|
||||
@@ -73,18 +71,17 @@ class MinkExtension implements ExtensionInterface
|
||||
$this->driverFactories[$driverFactory->getDriverName()] = $driverFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(ContainerBuilder $container, array $config): void
|
||||
{
|
||||
if (isset($config['mink_loader'])) {
|
||||
$basePath = $container->getParameter('paths.base');
|
||||
$basePath = is_string($basePath) ? $basePath : '';
|
||||
$minkLoader = is_string($config['mink_loader']) ? $config['mink_loader'] : '';
|
||||
|
||||
if (file_exists($basePath.DIRECTORY_SEPARATOR.$config['mink_loader'])) {
|
||||
require($basePath.DIRECTORY_SEPARATOR.$config['mink_loader']);
|
||||
if (file_exists($basePath.DIRECTORY_SEPARATOR.$minkLoader)) {
|
||||
require $basePath.DIRECTORY_SEPARATOR.$minkLoader;
|
||||
} else {
|
||||
require($config['mink_loader']);
|
||||
require $minkLoader;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,31 +98,39 @@ class MinkExtension implements ExtensionInterface
|
||||
unset($config['sessions']);
|
||||
|
||||
$container->setParameter('mink.parameters', $config);
|
||||
$container->setParameter('mink.base_url', $config['base_url']);
|
||||
$container->setParameter('mink.browser_name', $config['browser_name']);
|
||||
$baseUrl = $config['base_url'] ?? '';
|
||||
$container->setParameter('mink.base_url', is_string($baseUrl) ? $baseUrl : '');
|
||||
$browserName = $config['browser_name'] ?? '';
|
||||
$container->setParameter('mink.browser_name', is_string($browserName) ? $browserName : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function configure(ArrayNodeDefinition $builder): void
|
||||
{
|
||||
// Rewrite keys to define a shortcut way without allowing conflicts with real keys
|
||||
$renamedKeys = array_diff(
|
||||
array_keys($this->driverFactories),
|
||||
array('mink_loader', 'base_url', 'files_path', 'show_auto', 'show_cmd', 'show_tmp_dir', 'default_session', 'javascript_session', 'browser_name', 'sessions')
|
||||
['mink_loader', 'base_url', 'files_path', 'show_auto', 'show_cmd', 'show_tmp_dir', 'default_session', 'javascript_session', 'browser_name', 'sessions']
|
||||
);
|
||||
|
||||
$builder
|
||||
->beforeNormalization()
|
||||
->always()
|
||||
->then(function ($v) use ($renamedKeys) {
|
||||
->then(function (mixed $v) use ($renamedKeys): mixed {
|
||||
if (!is_array($v)) {
|
||||
return $v;
|
||||
}
|
||||
|
||||
foreach ($renamedKeys as $driverType) {
|
||||
if (!array_key_exists($driverType, $v) || isset($v['sessions'][$driverType])) {
|
||||
if (!array_key_exists($driverType, $v)) {
|
||||
continue;
|
||||
}
|
||||
$sessions = is_array($v['sessions']) ? $v['sessions'] : [];
|
||||
if (isset($sessions[$driverType])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$v['sessions'][$driverType][$driverType] = $v[$driverType];
|
||||
$sessions[$driverType] = [$driverType => $v[$driverType]];
|
||||
$v['sessions'] = $sessions;
|
||||
unset($v[$driverType]);
|
||||
}
|
||||
|
||||
@@ -164,84 +169,84 @@ class MinkExtension implements ExtensionInterface
|
||||
|
||||
$sessionsBuilder
|
||||
->validate()
|
||||
->ifTrue(function ($v) {return count($v) > 1;})
|
||||
->ifTrue(function (mixed $v): bool {return is_array($v) && count($v) > 1; })
|
||||
->thenInvalid('You cannot set multiple driver types for the same session')
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {return count($v) === 0;})
|
||||
->ifTrue(function (mixed $v): bool {return is_array($v) && 0 === count($v); })
|
||||
->thenInvalid('You must set a driver definition for the session.')
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConfigKey(): string
|
||||
{
|
||||
return 'mink';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function initialize(ExtensionManager $extensionManager): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->processSelectors($container);
|
||||
}
|
||||
|
||||
private function loadMink(ContainerBuilder $container)
|
||||
private function loadMink(ContainerBuilder $container): void
|
||||
{
|
||||
$container->setDefinition(self::MINK_ID, new Definition('Behat\Mink\Mink'));
|
||||
}
|
||||
|
||||
private function loadContextInitializer(ContainerBuilder $container)
|
||||
private function loadContextInitializer(ContainerBuilder $container): void
|
||||
{
|
||||
$definition = new Definition('Behat\MinkExtension\Context\Initializer\MinkAwareInitializer', array(
|
||||
$definition = new Definition('Behat\MinkExtension\Context\Initializer\MinkAwareInitializer', [
|
||||
new Reference(self::MINK_ID),
|
||||
'%mink.parameters%',
|
||||
));
|
||||
$definition->addTag(ContextExtension::INITIALIZER_TAG, array('priority' => 0));
|
||||
]);
|
||||
$definition->addTag(ContextExtension::INITIALIZER_TAG, ['priority' => 0]);
|
||||
$container->setDefinition('mink.context_initializer', $definition);
|
||||
}
|
||||
|
||||
private function loadSelectorsHandler(ContainerBuilder $container)
|
||||
private function loadSelectorsHandler(ContainerBuilder $container): void
|
||||
{
|
||||
$container->setDefinition(self::SELECTORS_HANDLER_ID, new Definition('Behat\Mink\Selector\SelectorsHandler'));
|
||||
|
||||
$cssSelectorDefinition = new Definition('Behat\Mink\Selector\CssSelector');
|
||||
$cssSelectorDefinition->addTag(self::SELECTOR_TAG, array('alias' => 'css'));
|
||||
$cssSelectorDefinition->addTag(self::SELECTOR_TAG, ['alias' => 'css']);
|
||||
$container->setDefinition(self::SELECTOR_TAG.'.css', $cssSelectorDefinition);
|
||||
|
||||
$namedSelectorDefinition = new Definition('Behat\Mink\Selector\NamedSelector');
|
||||
$namedSelectorDefinition->addTag(self::SELECTOR_TAG, array('alias' => 'named'));
|
||||
$namedSelectorDefinition->addTag(self::SELECTOR_TAG, ['alias' => 'named']);
|
||||
$container->setDefinition(self::SELECTOR_TAG.'.named', $namedSelectorDefinition);
|
||||
}
|
||||
|
||||
private function loadSessions(ContainerBuilder $container, array $config)
|
||||
/**
|
||||
* @param array<mixed> $config
|
||||
*/
|
||||
private function loadSessions(ContainerBuilder $container, array $config): void
|
||||
{
|
||||
$defaultSession = $config['default_session'];
|
||||
$javascriptSession = $config['javascript_session'];
|
||||
$javascriptSessions = $nonJavascriptSessions = array();
|
||||
$defaultSession = is_string($config['default_session']) ? $config['default_session'] : null;
|
||||
$javascriptSession = is_string($config['javascript_session']) ? $config['javascript_session'] : null;
|
||||
$javascriptSessions = [];
|
||||
$nonJavascriptSessions = [];
|
||||
|
||||
$minkDefinition = $container->getDefinition(self::MINK_ID);
|
||||
|
||||
foreach ($config['sessions'] as $name => $session) {
|
||||
$driver = key($session);
|
||||
$sessions = is_array($config['sessions']) ? $config['sessions'] : [];
|
||||
foreach ($sessions as $name => $session) {
|
||||
if (!is_array($session)) {
|
||||
continue;
|
||||
}
|
||||
$driver = (string) key($session);
|
||||
$factory = $this->driverFactories[$driver];
|
||||
|
||||
$definition = new Definition('Behat\Mink\Session', array(
|
||||
$factory->buildDriver($session[$driver]),
|
||||
$driverConfig = is_array($session[$driver]) ? $session[$driver] : [];
|
||||
$definition = new Definition('Behat\Mink\Session', [
|
||||
$factory->buildDriver($driverConfig),
|
||||
new Reference(self::SELECTORS_HANDLER_ID),
|
||||
));
|
||||
$minkDefinition->addMethodCall('registerSession', array($name, $definition));
|
||||
]);
|
||||
$minkDefinition->addMethodCall('registerSession', [$name, $definition]);
|
||||
|
||||
if ($factory->supportsJavascript()) {
|
||||
$javascriptSessions[] = $name;
|
||||
@@ -253,16 +258,12 @@ class MinkExtension implements ExtensionInterface
|
||||
if (null === $javascriptSession && !empty($javascriptSessions)) {
|
||||
$javascriptSession = $javascriptSessions[0];
|
||||
} elseif (null !== $javascriptSession && !in_array($javascriptSession, $javascriptSessions)) {
|
||||
throw new InvalidConfigurationException(sprintf(
|
||||
'The javascript session must be one of the enabled javascript sessions (%s), but got %s',
|
||||
json_encode($javascriptSessions),
|
||||
$javascriptSession
|
||||
));
|
||||
throw new InvalidConfigurationException(sprintf('The javascript session must be one of the enabled javascript sessions (%s), but got %s', json_encode($javascriptSessions), $javascriptSession));
|
||||
}
|
||||
|
||||
if (null === $defaultSession) {
|
||||
$defaultSession = !empty($nonJavascriptSessions) ? $nonJavascriptSessions[0] : $javascriptSessions[0];
|
||||
} elseif (!isset($config['sessions'][$defaultSession])) {
|
||||
} elseif (!is_array($config['sessions']) || !isset($config['sessions'][$defaultSession])) {
|
||||
throw new InvalidConfigurationException(sprintf('The default session must be one of the enabled sessions, but got %s', $defaultSession));
|
||||
}
|
||||
|
||||
@@ -271,43 +272,39 @@ class MinkExtension implements ExtensionInterface
|
||||
$container->setParameter('mink.available_javascript_sessions', $javascriptSessions);
|
||||
}
|
||||
|
||||
private function loadSessionsListener(ContainerBuilder $container)
|
||||
private function loadSessionsListener(ContainerBuilder $container): void
|
||||
{
|
||||
$definition = new Definition('Behat\MinkExtension\Listener\SessionsListener', array(
|
||||
$definition = new Definition('Behat\MinkExtension\Listener\SessionsListener', [
|
||||
new Reference(self::MINK_ID),
|
||||
'%mink.default_session%',
|
||||
'%mink.javascript_session%',
|
||||
'%mink.available_javascript_sessions%',
|
||||
));
|
||||
$definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, array('priority' => 0));
|
||||
]);
|
||||
$definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, ['priority' => 0]);
|
||||
$container->setDefinition('mink.listener.sessions', $definition);
|
||||
}
|
||||
|
||||
private function loadFailureShowListener(ContainerBuilder $container)
|
||||
private function loadFailureShowListener(ContainerBuilder $container): void
|
||||
{
|
||||
$definition = new Definition('Behat\MinkExtension\Listener\FailureShowListener', array(
|
||||
$definition = new Definition('Behat\MinkExtension\Listener\FailureShowListener', [
|
||||
new Reference(self::MINK_ID),
|
||||
'%mink.parameters%',
|
||||
));
|
||||
$definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, array('priority' => 0));
|
||||
]);
|
||||
$definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, ['priority' => 0]);
|
||||
$container->setDefinition('mink.listener.failure_show', $definition);
|
||||
}
|
||||
|
||||
private function processSelectors(ContainerBuilder $container)
|
||||
private function processSelectors(ContainerBuilder $container): void
|
||||
{
|
||||
$handlerDefinition = $container->getDefinition(self::SELECTORS_HANDLER_ID);
|
||||
|
||||
foreach ($container->findTaggedServiceIds(self::SELECTOR_TAG) as $id => $tags) {
|
||||
foreach ($tags as $tag) {
|
||||
if (!isset($tag['alias'])) {
|
||||
throw new ProcessingException(sprintf(
|
||||
'All `%s` tags should have an `alias` attribute, but `%s` service has none.',
|
||||
$tag,
|
||||
$id
|
||||
));
|
||||
if (!is_array($tag) || !isset($tag['alias'])) {
|
||||
throw new ProcessingException(sprintf('All `%s` tags should have an `alias` attribute, but `%s` service has none.', self::SELECTOR_TAG, $id));
|
||||
}
|
||||
$handlerDefinition->addMethodCall(
|
||||
'registerSelector', array($tag['alias'], new Reference($id))
|
||||
'registerSelector', [is_string($tag['alias']) ? $tag['alias'] : '', new Reference($id)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user