diff --git a/behat.yml.dist b/behat.yml.dist index a94d08d..5e42723 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -2,4 +2,4 @@ default: suites: default: contexts: - - FriendsOfBehat\TestContext\Context\TestContext + - Tests\Behat\Context\TestContext diff --git a/composer.json b/composer.json index 588ee4a..b3019d5 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,6 @@ "behat/mink": "^1.7", "behat/mink-browserkit-driver": "^1.3", "behat/mink-extension": "^2.2", - "friends-of-behat/test-context": "^1.0", "phpstan/phpstan-shim": "^0.10", "sylius-labs/coding-standard": "^3.0", "symfony/framework-bundle": "^3.4|^4.1" @@ -31,6 +30,9 @@ "autoload": { "psr-4": { "FriendsOfBehat\\SymfonyExtension\\": "src/" } }, + "autoload-dev": { + "psr-4": { "Tests\\": "tests/" } + }, "config": { "sort-packages": true }, diff --git a/tests/Behat/Context/TestContext.php b/tests/Behat/Context/TestContext.php new file mode 100644 index 0000000..286d511 --- /dev/null +++ b/tests/Behat/Context/TestContext.php @@ -0,0 +1,320 @@ +remove(self::$workingDir); + self::$filesystem->mkdir(self::$workingDir, 0777); + } + + /** + * @AfterScenario + */ + public function afterScenario(): void + { + self::$filesystem->remove(self::$workingDir); + } + + /** + * @Given /^a Behat configuration containing(?: "([^"]+)"|:)$/ + */ + public function thereIsConfiguration($content): void + { + $this->thereIsFile('behat.yml', $content); + } + + /** + * @Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/ + */ + public function thereIsFile($file, $content): void + { + self::$filesystem->dumpFile(self::$workingDir . '/' . $file, (string) $content); + } + + /** + * @Given /^a feature file containing(?: "([^"]+)"|:)$/ + */ + public function thereIsFeatureFile($content): void + { + $this->thereIsFile(sprintf('features/%s.feature', md5(uniqid('', true))), $content); + } + + /** + * @Given /^a feature file with passing scenario$/ + */ + public function thereIsFeatureFileWithPassingScenario(): void + { + $this->thereIsFile('features/bootstrap/FeatureContext.php', <<thereIsFeatureFile(<<thereIsFile('features/bootstrap/FeatureContext.php', <<thereIsFeatureFile(<<thereIsFile('features/bootstrap/FeatureContext.php', <<thereIsFeatureFile(<<thereIsFile('features/bootstrap/FeatureContext.php', <<thereIsFeatureFile(<<process = new Process(sprintf('%s %s --strict -vvv --no-interaction --lang=en', self::$phpBin, escapeshellarg(BEHAT_BIN_PATH))); + $this->process->setWorkingDirectory(self::$workingDir); + $this->process->start(); + $this->process->wait(); + } + + /** + * @Then /^it should pass$/ + */ + public function itShouldPass(): void + { + if (0 === $this->getProcessExitCode()) { + return; + } + + throw new \DomainException( + 'Behat was expecting to pass, but failed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput() + ); + } + + /** + * @Then /^it should pass with(?: "([^"]+)"|:)$/ + */ + public function itShouldPassWith($expectedOutput): void + { + $this->itShouldPass(); + $this->assertOutputMatches((string) $expectedOutput); + } + + /** + * @Then /^it should fail$/ + */ + public function itShouldFail(): void + { + if (0 !== $this->getProcessExitCode()) { + return; + } + + throw new \DomainException( + 'Behat was expecting to fail, but passed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput() + ); + } + + /** + * @Then /^it should fail with(?: "([^"]+)"|:)$/ + */ + public function itShouldFailWith($expectedOutput): void + { + $this->itShouldFail(); + $this->assertOutputMatches((string) $expectedOutput); + } + + /** + * @Then /^it should end with(?: "([^"]+)"|:)$/ + */ + public function itShouldEndWith($expectedOutput): void + { + $this->assertOutputMatches((string) $expectedOutput); + } + + /** + * @param string $expectedOutput + */ + private function assertOutputMatches($expectedOutput): void + { + $pattern = '/' . preg_quote($expectedOutput, '/') . '/sm'; + $output = $this->getProcessOutput(); + + $result = preg_match($pattern, $output); + if (false === $result) { + throw new \InvalidArgumentException('Invalid pattern given:' . $pattern); + } + + if (0 === $result) { + throw new \DomainException(sprintf( + 'Pattern "%s" does not match the following output:' . PHP_EOL . PHP_EOL . '%s', + $pattern, + $output + )); + } + } + + /** + * @return string + */ + private function getProcessOutput(): string + { + $this->assertProcessIsAvailable(); + + return $this->process->getErrorOutput() . $this->process->getOutput(); + } + + /** + * @return int + */ + private function getProcessExitCode(): int + { + $this->assertProcessIsAvailable(); + + return $this->process->getExitCode(); + } + + /** + * @throws \BadMethodCallException + */ + private function assertProcessIsAvailable(): void + { + if (null === $this->process) { + throw new \BadMethodCallException('Behat proccess cannot be found. Did you run it before making assertions?'); + } + } + + /** + * @return string + * + * @throws \RuntimeException + */ + private static function findPhpBinary(): string + { + $phpBinary = (new PhpExecutableFinder())->find(); + if (false === $phpBinary) { + throw new \RuntimeException('Unable to find the PHP executable.'); + } + + return $phpBinary; + } +}