Skip to content

Commit

Permalink
Merge 48358d6 into f4f7869
Browse files Browse the repository at this point in the history
  • Loading branch information
OndraM committed Nov 29, 2020
2 parents f4f7869 + 48358d6 commit 7787efa
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 131 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -32,10 +32,11 @@
- Instead of `TestUtils::setSelect2Value()` use directly the new `Select2` component and `selectByVisiblePartialText()` method.
- Instead of `TestUtils::getFixturePath()` use `Facebook\WebDriver\Remote\FileDetector` instead.
- Instead of `TestUtils::sleep()` use `AbstractTestCase::sleep()` method instead.
- `getConfig()` method of ConfigProvider. Instead call the property directly on instance of the ConfigProvider.
- `getConfig()` method of ConfigProvider. Call the property instead directly on an instance of the ConfigProvider.
- `--fixtures-dir` option of the `run` command, `fixtures_dir` option of configuration file and `ConfigProvider->fixturesDir` variable. They were deprecated in version 2.1.0 and no longer used since.
- `UniqueValue` component. (You may use Faker or some other library for similar use-case.)
- `AbstractTestCaseBase` class. It should probably not affect anything, as it was only used internally.
- Workarounds for legacy Firefox (version 47 and older) which are no longer needed.

## 2.3.2 - 2017-12-02
### Changed
Expand Down
14 changes: 7 additions & 7 deletions composer.json
Expand Up @@ -29,29 +29,29 @@
"ext-zip": "*",
"beberlei/assert": "^3.0",
"clue/graph": "~0.9.0",
"doctrine/inflector": "~1.0",
"doctrine/inflector": "^2.0.3",
"florianwolters/component-util-singleton": "0.3.2",
"graphp/algorithms": "^0.8.1",
"nette/reflection": "^2.4.2",
"ondram/ci-detector": "^3.1",
"php-webdriver/webdriver": "^1.8.1",
"phpunit/phpunit": "^7.5",
"phpunit/phpunit": "^7.5.20",
"symfony/console": "^4.0",
"symfony/event-dispatcher": "^4.0",
"symfony/filesystem": "^4.0",
"symfony/finder": "^4.0",
"symfony/options-resolver": "^4.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^4.0 !=4.0.2",
"symfony/process": "^4.0.3",
"symfony/stopwatch": "^4.0",
"symfony/yaml": "^4.0"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.2",
"ergebnis/composer-normalize": "^2.11",
"lmc/coding-standard": "^2.1",
"php-coveralls/php-coveralls": "^2.0",
"php-mock/php-mock-phpunit": "^2.1.2",
"php-parallel-lint/php-parallel-lint": "^1.0.0",
"php-coveralls/php-coveralls": "^2.4.2",
"php-mock/php-mock-phpunit": "^2.6.0",
"php-parallel-lint/php-parallel-lint": "^1.2.0",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.11",
"phpstan/phpstan-phpunit": "^0.12.6",
Expand Down
2 changes: 0 additions & 2 deletions phpstan.neon
Expand Up @@ -6,8 +6,6 @@ parameters:
- "#Property Lmc\\\\Steward\\\\Test\\\\AbstractTestCase::\\$wd \\(Facebook\\\\WebDriver\\\\Remote\\\\RemoteWebDriver\\) does not accept Lmc\\\\Steward\\\\WebDriver\\\\NullWebDriver#"
- message: '#should return .+ but return statement is missing#'
path: 'src/WebDriver/NullWebDriver.php'
- message: '#Variable \$e might not be defined.#'
path: 'src/Listener/WebDriverListener.php'
excludes_analyse:
- '%rootDir%/../../../src-tests/Process/Fixtures/InvalidTests/WrongClassTest.php'
- '%rootDir%/../../../src-tests/Test/SyntaxSugarTraitTest.php'
Expand Down
2 changes: 1 addition & 1 deletion src-tests/Console/Command/RunCommandTest.php
Expand Up @@ -249,7 +249,7 @@ public function testShouldStopIfServerIsRespondingButIsNotSelenium(): void

$this->assertContains('Unexpected response from Selenium server (This is teapot)', $this->tester->getDisplay());
$this->assertContains(
'Looks like url "http://foo.bar:1337" is occupied by something else than Selenium server.',
'URL "http://foo.bar:1337" is occupied by something else than Selenium server.',
$this->tester->getDisplay()
);
$this->assertSame(1, $this->tester->getStatusCode());
Expand Down
34 changes: 14 additions & 20 deletions src-tests/Process/ProcessSetCreatorTest.php
Expand Up @@ -101,7 +101,6 @@ public function testShouldCreateProcessSetFromGivenFiles(): void
$processes = $processSet->get(ProcessWrapper::PROCESS_STATUS_QUEUED);
$dummyTestProcess = $processes[self::NAME_DUMMY_TEST]->getProcess();
$testCommand = $dummyTestProcess->getCommandLine();
$testEnv = $dummyTestProcess->getEnv();

$this->assertContains('phpunit', $testCommand);
$this->assertContains(
Expand All @@ -112,15 +111,13 @@ public function testShouldCreateProcessSetFromGivenFiles(): void
$this->assertNotContains('--filter', $testCommand);
$this->assertStringMatchesFormat('%A--configuration=%A%esrc%ephpunit.xml%A', $testCommand);

// Check defaults were passed to the Processes
// Check defaults were passed to the Process environment
$testEnv = $dummyTestProcess->getEnv();
$definition = $this->command->getDefinition();
$expectedEnv = [
'BROWSER_NAME' => 'firefox',
'ENV' => 'staging',
'SERVER_URL' => $definition->getOption(RunCommand::OPTION_SERVER_URL)->getDefault(),
'LOGS_DIR' => '/foo/bar/logs',
];
$this->assertArraySubset($expectedEnv, $testEnv);
$this->assertSame('firefox', $testEnv['BROWSER_NAME']);
$this->assertSame('staging', $testEnv['ENV']);
$this->assertSame($definition->getOption(RunCommand::OPTION_SERVER_URL)->getDefault(), $testEnv['SERVER_URL']);
$this->assertSame('/foo/bar/logs', $testEnv['LOGS_DIR']);
}

public function testShouldThrowExceptionIfAddingFileWithNoClass(): void
Expand Down Expand Up @@ -295,18 +292,15 @@ public function testShouldPropagateCustomOptionsIntoProcess(): void
$process = $processSet->get(ProcessWrapper::PROCESS_STATUS_QUEUED)[self::NAME_DUMMY_TEST]->getProcess();
$processEnv = $process->getEnv();

$this->assertArraySubset(
[
'BROWSER_NAME' => 'chrome',
'ENV' => 'staging',
'SERVER_URL' => 'http://foo.bar:1337',
'LOGS_DIR' => realpath(__DIR__ . '/Fixtures/custom-logs-dir/'),
'CAPABILITY' => '{"webdriver.log.file":"\/foo\/bar.log","whitespaced":"OS X 10.8",'
. '"webdriver.foo":false,"version":"14.14393"}',
'CAPABILITIES_RESOLVER' => '',
],
$processEnv
$this->assertSame('chrome', $processEnv['BROWSER_NAME']);
$this->assertSame('staging', $processEnv['ENV']);
$this->assertSame('http://foo.bar:1337', $processEnv['SERVER_URL']);
$this->assertSame(realpath(__DIR__ . '/Fixtures/custom-logs-dir/'), $processEnv['LOGS_DIR']);
$this->assertSame(
'{"webdriver.log.file":"\/foo\/bar.log","whitespaced":"OS X 10.8","webdriver.foo":false,"version":"14.14393"}',
$processEnv['CAPABILITY']
);
$this->assertSame('', $processEnv['CAPABILITIES_RESOLVER']);
}

public function testShouldSetPHPUnitColoredOptionOnlyIfTheOutputIsDecorated(): void
Expand Down
8 changes: 1 addition & 7 deletions src-tests/Selenium/CapabilitiesResolverTest.php
Expand Up @@ -33,7 +33,6 @@ public function testShouldResolveBasicDesiredCapabilities(string $browser, calla
$resolver->setCiDetector($this->createConfiguredMock(CiDetector::class, ['isCiDetected' => false]));

$desiredCapabilities = $resolver->resolveDesiredCapabilities($test);
$this->assertInstanceOf(DesiredCapabilities::class, $desiredCapabilities);

$desiredCapabilitiesArray = $desiredCapabilities->toArray();
$this->assertSame($browser, $desiredCapabilitiesArray['browserName']);
Expand All @@ -51,12 +50,7 @@ public function testShouldResolveBasicDesiredCapabilities(string $browser, calla
public function provideBrowsers(): array
{
return [
[
WebDriverBrowserType::FIREFOX,
function ($capabilitiesArray): void {
$this->assertNotEmpty($capabilitiesArray['firefox_profile']);
},
],
[WebDriverBrowserType::FIREFOX],
[WebDriverBrowserType::CHROME],
[WebDriverBrowserType::MICROSOFT_EDGE],
[
Expand Down
8 changes: 1 addition & 7 deletions src-tests/Test/AbstractTestCaseTest.php
Expand Up @@ -47,13 +47,7 @@ public function testShouldSetDefaultWindowSizeInitUtils(): void

$wdWindowMock->expects($this->once())
->method('setSize')
->with(
$this->logicalAnd(
$this->isInstanceOf(WebDriverDimension::class),
$this->attributeEqualTo('width', 1280),
$this->attributeEqualTo('height', 1024)
)
);
->with($this->equalTo(new WebDriverDimension(1280, 1024)));

$this->testCase->wd = $wdMock;

Expand Down
6 changes: 4 additions & 2 deletions src/ConfigProvider.php
Expand Up @@ -2,7 +2,8 @@

namespace Lmc\Steward;

use Doctrine\Common\Inflector\Inflector;
use Doctrine\Inflector\InflectorFactory;
use Doctrine\Inflector\Language;
use FlorianWolters\Component\Util\Singleton\SingletonTrait;

/**
Expand Down Expand Up @@ -117,6 +118,7 @@ private function assembleConfigurationOptions(): array
private function retrieveConfigurationValues(array $options): array
{
$outputValues = [];
$inflector = InflectorFactory::createForLanguage(Language::ENGLISH)->build();

foreach ($options as $option) {
$value = getenv($option);
Expand All @@ -126,7 +128,7 @@ private function retrieveConfigurationValues(array $options): array
throw new \RuntimeException(sprintf('%s environment variable must be defined', $option));
}

$outputValues[Inflector::camelize(mb_strtolower($option))] = $value;
$outputValues[$inflector->camelize(mb_strtolower($option))] = $value;
}

return $outputValues;
Expand Down
6 changes: 3 additions & 3 deletions src/Console/Command/RunCommand.php
Expand Up @@ -364,9 +364,9 @@ protected function testSeleniumConnection(): bool
);
$this->io->error(
sprintf(
'Looks like url "%s" is occupied by something else than Selenium server. '
. 'Make sure Selenium server is really accessible on this url '
. 'or change it using --server-url option',
'URL "%s" is occupied by something else than Selenium server. Make sure Selenium server is really'
. ' accessible on this URL or change it using --server-url option.'
. ' If using Selenium 3.x, also make sure you are not be missing "/wd/hub" part in the server URL.',
$seleniumAdapter->getServerUrl()
)
);
Expand Down
79 changes: 16 additions & 63 deletions src/Listener/WebDriverListener.php
Expand Up @@ -2,7 +2,7 @@

namespace Lmc\Steward\Listener;

use Facebook\WebDriver\Exception\UnknownServerException;
use Facebook\WebDriver\Exception\SessionNotCreatedException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\WebDriverBrowserType;
Expand Down Expand Up @@ -140,10 +140,8 @@ public function endTest(Test $test, float $time): void
}

/**
* Subroutine to encapsulate creation of real WebDriver. Handles some exceptions that may occur etc.
* Subroutine to encapsulate creation of real WebDriver.
* The WebDriver instance is stored to $test->wd when created.
*
* @throws UnknownServerException
*/
protected function createWebDriver(
AbstractTestCase $test,
Expand All @@ -153,66 +151,21 @@ protected function createWebDriver(
int $connectTimeoutMs,
int $requestTimeoutMs
): void {
$browserName = ConfigProvider::getInstance()->browserName;

for ($startAttempts = 0; $startAttempts < 4; $startAttempts++) {
try {
$test->wd = RemoteWebDriver::create(
$remoteServerUrl,
$desiredCapabilities,
$connectTimeoutMs,
$requestTimeoutMs,
null,
null,
$requiredCapabilities
);

return;
} catch (UnknownServerException $e) {
if ($this->cannotBindToFirefoxLockingPort($browserName, $e->getMessage())) {
// As a consequence of Selenium issue #5172 (cannot change locking port), Firefox may on CI server
// collide with other FF instance. As a workaround, we try to start it again after a short delay.
$test->warn(
'Firefox locking port is occupied; beginning attempt #%d to start it ("%s")',
$startAttempts + 2,
$e->getMessage()
);
sleep(1);
continue;
}

if (mb_strpos($e->getMessage(), 'Error forwarding the new session') !== false) {
$test->warn('Cannot execute test on the node. Maybe you started just the hub and not the node?');
}

throw $e;
} catch (WebDriverException $e) {
if ($this->mayBeMissingFullServerUrl($remoteServerUrl, $e->getMessage())) {
$test->warn('Unable to initialize new WebDriver session.');
$test->warn(
'Server URL ("%s") appears to be missing "/wd/hub" part, so make sure you are ussing full URL'
. ' of the server (not just a hostname and port).',
$remoteServerUrl
);
}
try {
$test->wd = RemoteWebDriver::create(
$remoteServerUrl,
$desiredCapabilities,
$connectTimeoutMs,
$requestTimeoutMs,
null,
null,
$requiredCapabilities
);

throw $e;
}
return;
} catch (SessionNotCreatedException $e) {
$test->warn('Unable to initialize new WebDriver session.');
throw $e;
}

$test->warn('All %d attempts to instantiate Firefox WebDriver failed', $startAttempts + 1);
throw $e;
}

private function cannotBindToFirefoxLockingPort(string $browserName, string $exceptionMessage): bool
{
return $browserName === 'firefox'
&& mb_strpos($exceptionMessage, 'Unable to bind to locking port') !== false;
}

private function mayBeMissingFullServerUrl(string $remoteServerUrl, string $exceptionMessage): bool
{
return mb_strpos($exceptionMessage, 'JSON decoding of remote response failed.') !== false
&& mb_strpos($remoteServerUrl, 'wd/hub') === false;
}
}
23 changes: 5 additions & 18 deletions src/Selenium/CapabilitiesResolver.php
Expand Up @@ -2,8 +2,6 @@

namespace Lmc\Steward\Selenium;

use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxProfile;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\WebDriverBrowserType;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
Expand Down Expand Up @@ -101,14 +99,16 @@ protected function setupCiCapabilities(
return $capabilities;
}

/**
* Setup Steward-default capabilities for specific browsers.
* To setup custom default capabilities for each browser, implement custom capabilities resolver, see
* https://github.com/lmc-eu/steward/wiki/Set-custom-capabilities#implement-custom-capabilities-resolver
*/
protected function setupBrowserSpecificCapabilities(
DesiredCapabilities $capabilities,
string $browser
): DesiredCapabilities {
switch ($browser) {
case WebDriverBrowserType::FIREFOX:
$capabilities = $this->setupFirefoxCapabilities($capabilities);
break;
case WebDriverBrowserType::IE:
$capabilities = $this->setupInternetExplorerCapabilities($capabilities);
break;
Expand All @@ -117,19 +117,6 @@ protected function setupBrowserSpecificCapabilities(
return $capabilities;
}

protected function setupFirefoxCapabilities(DesiredCapabilities $capabilities): DesiredCapabilities
{
// Firefox does not (as a intended feature) trigger "change" and "focus" events in javascript if not in active
// (focused) window. This would be a problem for concurrent testing - solution is to use focusmanager.testmode.
// See https://code.google.com/p/selenium/issues/detail?id=157
$profile = new FirefoxProfile(); // see https://github.com/php-webdriver/php-webdriver/wiki/FirefoxProfile
$profile->setPreference('focusmanager.testmode', true);

$capabilities->setCapability(FirefoxDriver::PROFILE, $profile);

return $capabilities;
}

protected function setupInternetExplorerCapabilities(DesiredCapabilities $capabilities): DesiredCapabilities
{
// Clears cache, cookies, history, and saved form data of MSIE.
Expand Down

0 comments on commit 7787efa

Please sign in to comment.