diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..db3c7ec --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,43 @@ +name: Test +on: + - push + - pull_request + +jobs: + test: + name: Run tests + runs-on: 'ubuntu-latest' + strategy: + fail-fast: false + matrix: + php-version: + - "7.4" + - "8.0" + - "8.1" + - "8.2" + - "8.3" + - "8.4" + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + + - name: Update composer + run: composer --verbose self-update --2 + + - name: Dump composer version + run: composer --version + + - name: Validate composer.json + run: composer --verbose validate + + - name: Install dependencies + run: composer --verbose install + + - name: Run tests + run: composer test diff --git a/composer.json b/composer.json index 2a2323a..f5a4d41 100644 --- a/composer.json +++ b/composer.json @@ -6,5 +6,30 @@ "psr-4": { "Frontkom\\CommonBehatDefinitions\\": "src/" } - } + }, + "scripts": { + "test": [ + "@composer phpcs", + "phpstan", + "phpunit" + ], + "phpcs": "vendor/bin/phpcs -p" + }, + "require": { + "behat/behat": "^3.0", + "behat/mink": "^1.0", + "behat/mink-selenium2-driver": "^1.0", + "friends-of-behat/mink-extension": "^2.0" + }, + "require-dev": { + "squizlabs/php_codesniffer": "^3.10", + "slevomat/coding-standard": "^8.15", + "phpunit/phpunit": "^9.0 || ^10.5", + "phpstan/phpstan": "^1.12" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } } diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..00e518a --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,14 @@ + + + + ./src + ./tests + + + + + + + warning + + diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..46b0f47 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,5 @@ +parameters: + level: 5 + paths: + - src + - tests diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..fa0a74d --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,23 @@ + + + + + tests + + + + + + src + + + diff --git a/src/CommonFeatureContext.php b/src/CommonFeatureContext.php index f48e015..38e3dc1 100644 --- a/src/CommonFeatureContext.php +++ b/src/CommonFeatureContext.php @@ -24,14 +24,18 @@ public function iWaitUntilElementIsVisible($selector) { $elements = $this->getSession()->getPage()->findAll('css', $selector); if (count($elements) !== 1) { - throw new \Exception('Expected to find exactly one element by selector ' . $selector . ' but found ' . count($elements) . ' elements'); + throw new \Exception( + 'Expected to find exactly one element by selector ' . + $selector . + ' but found ' . count($elements) . ' elements' + ); } /** @var \Behat\Mink\Element\NodeElement $element */ $element = reset($elements); $i = 0; - while (TRUE) { + while (true) { if ($element->isVisible()) { - return; + return; } sleep(1); $i++; @@ -61,14 +65,33 @@ public function iWaitSeconds($count) usleep($count * 1000000); } + /** + * Set the viewport to something defined as desktop. + * + * If you need to override this, simply create a class that extends this + * class, and reference that class inside your behat.yml file. + * + * @Given viewport is desktop + * @Given the viewport is desktop + */ + public function iSetDesktopViewport() + { + $mink = $this->getMink(); + if (!$mink->getSession()->isStarted()) { + $mink->getSession()->start(); + } + $this->getSession()->resizeWindow(self::WIDTH, self::HEIGHT, 'current'); + } + /** * Scroll something into view. * * @Then I scroll element :selector into view * @Then I scroll :selector into view */ - public function scrollSelectorIntoView($selector) { - $function = <<getSession()->executeScript($function); - } - catch (\Exception $e) { + } catch (\Exception $e) { throw new \Exception("ScrollIntoView failed: " . $e->getMessage()); } } diff --git a/src/ElementExistsTrait.php b/src/ElementExistsTrait.php index e711f1b..86aefcc 100644 --- a/src/ElementExistsTrait.php +++ b/src/ElementExistsTrait.php @@ -14,7 +14,7 @@ trait ElementExistsTrait * @Given I wait until element :arg1 exists * @Given I wait until element :arg1 exists max :arg2 seconds */ - public function iWaitUntilElementExists($element, $seconds = NULL) + public function iWaitUntilElementExists($element, $seconds = null) { $seconds = (isset($seconds) && !empty($seconds)) ? $seconds : 10; $waited = 0; diff --git a/src/GutenbergContext.php b/src/GutenbergContext.php index aa47842..323d9b7 100644 --- a/src/GutenbergContext.php +++ b/src/GutenbergContext.php @@ -4,39 +4,47 @@ use Behat\MinkExtension\Context\RawMinkContext; -class GutenbergContext extends RawMinkContext { +class GutenbergContext extends RawMinkContext +{ /** * Prepend a paragraph block basically. * * @Then /^I write text "([^"]*)" as a paragraph in the gutenberg field on the page$/ */ - public function iWriteInTheGutenbergFieldOnThePage($text) { - $js = sprintf("(function(){ + public function iWriteInTheGutenbergFieldOnThePage($text) + { + $js = sprintf("(function(){ var block = wp.blocks.createBlock('core/paragraph', {content: '%s'}); wp.data.dispatch('core/editor').insertBlock(block, null); return block.clientId; })()", $text); - $this->getSession()->evaluateScript($js); - } + $this->getSession()->evaluateScript($js); + } /** * Step to wait for the editor to be ready. * * @Then /^I wait until gutenberg is ready$/ */ - public function iWaitUntilGutenbergIsReady($max_wait = 10) { - while (TRUE) { - $is_ready = $this->getSession()->evaluateScript("wp && wp.data && wp.data.select && wp.data.select('core/editor').isCleanNewPost() || wp.data.select('core/block-editor').getBlockCount() > 0"); - if ($is_ready) { - break; - } - sleep(1); - $max_wait--; - if ($max_wait <= 0) { - throw new \Exception('Gutenberg did not load in time'); - } + public function iWaitUntilGutenbergIsReady($max_wait = 10) + { + while (true) { + $is_ready = $this->getSession()->evaluateScript( + "wp && + wp.data && + wp.data.select && + wp.data.select('core/editor').isCleanNewPost() || + wp.data.select('core/block-editor').getBlockCount() > 0" + ); + if ($is_ready) { + break; + } + sleep(1); + $max_wait--; + if ($max_wait <= 0) { + throw new \Exception('Gutenberg did not load in time'); + } + } } - } - } diff --git a/src/JsErrorsDumper.php b/src/JsErrorsDumper.php index e68917d..616ac42 100644 --- a/src/JsErrorsDumper.php +++ b/src/JsErrorsDumper.php @@ -9,65 +9,65 @@ /** * Provides AfterStep that dumps any JS errors that appear during given step. */ -trait JsErrorsDumper { +trait JsErrorsDumper +{ /** * Checks that the step did not trigger any JS errors. * * @AfterStep */ - public function lookForJsErrors(AfterStepScope $scope) { - // No steps, nothing to do. - if (!$scope->getStep()) { - return; - } - $driver = $this->getSession()->getDriver(); - if (!($driver instanceof Selenium2Driver)) { - // Only works in browsers. - return; - } - // If the webdriver session has not started, probably means we are not - // navigating in a context where we can actually evaluate any scripts at - // all. This AfterStep will also trigger on steps in a background, for - // example stuff like "Given a node with title something", which of course - // will not let us have a browser window to check if there are any errors, - // even if the driver of the session technically is a Selenium2Driver. - try { - if (!$driver->getWebDriverSession()) { - return; - } - } - catch (DriverException $e) { - // This will happen at least in some version here if the session has not - // been started yet. - return; - } + public function lookForJsErrors(AfterStepScope $scope) + { + // No steps, nothing to do. + if (!$scope->getStep()) { + return; + } + $driver = $this->getSession()->getDriver(); + if (!($driver instanceof Selenium2Driver)) { + // Only works in browsers. + return; + } + // If the webdriver session has not started, probably means we are not + // navigating in a context where we can actually evaluate any scripts at + // all. This AfterStep will also trigger on steps in a background, for + // example stuff like "Given a node with title something", which of course + // will not let us have a browser window to check if there are any errors, + // even if the driver of the session technically is a Selenium2Driver. + try { + if (!$driver->getWebDriverSession()) { + return; + } + } catch (DriverException $e) { + // This will happen at least in some version here if the session has not + // been started yet. + return; + } - try { - $errors = $this->getSession()->evaluateScript("return window.jsErrors"); - } catch (\Exception $e) { - // output where the error occurred for debugging purposes - echo $this->scenarioData; - throw $e; - } + try { + $errors = $this->getSession()->evaluateScript("return window.jsErrors"); + } catch (\Exception $e) { + // output where the error occurred for debugging purposes + echo $this->scenarioData; + throw $e; + } - if (!$errors || empty($errors)) { - return; - } - - $file = sprintf("%s:%d", $scope->getFeature()->getFile(), $scope->getStep()->getLine()); - $message = sprintf("Found %d javascript error%s", count($errors), count($errors) > 0 ? 's' : ''); + if (!$errors || empty($errors)) { + return; + } - echo '-------------------------------------------------------------' . PHP_EOL; - echo $file . PHP_EOL; - echo $message . PHP_EOL; - echo '-------------------------------------------------------------' . PHP_EOL; + $file = sprintf("%s:%d", $scope->getFeature()->getFile(), $scope->getStep()->getLine()); + $message = sprintf("Found %d javascript error%s", count($errors), count($errors) > 0 ? 's' : ''); - foreach ($errors as $index => $error) { - echo sprintf(" #%d: %s", $index, $error) . PHP_EOL; - } + echo '-------------------------------------------------------------' . PHP_EOL; + echo $file . PHP_EOL; + echo $message . PHP_EOL; + echo '-------------------------------------------------------------' . PHP_EOL; - throw new \Exception($message); - } + foreach ($errors as $index => $error) { + echo sprintf(" #%d: %s", $index, $error) . PHP_EOL; + } + throw new \Exception($message); + } } diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29