Skip to content

Commit

Permalink
Added support for show_output option.
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexSkrypnyk committed Jan 10, 2025
1 parent a0ef050 commit 3677543
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 98 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ default:
DrevOps\BehatFormatProgressFail\FormatExtension: ~
```
or
>behat.yml
```yaml
default:
extensions:
DrevOps\BehatFormatProgressFail\FormatExtension:
show_output: in-summary # Supported values: yes | no | on-fail
```
#### `show_output`

Show output from within test steps. "Output" is `print`, `echo`, `var_dump`, etc.

- `yes` - always show the output
- `no` - do not show the output
- `on-fail` - only show the output if there are test fails
- `in-summary` - only show in the summary if there are test fails

## Maintenance

### Lint code
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"require": {
"php": ">=8.1",
"behat/behat": "^3.3"
"behat/behat": "^3.18"
},
"require-dev": {
"behat/mink": "^1.8",
Expand Down
119 changes: 47 additions & 72 deletions src/DrevOps/BehatFormatProgressFail/FormatExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace DrevOps\BehatFormatProgressFail;

use Behat\Behat\Output\Node\EventListener\AST\StepListener;
use Behat\Config\Formatter\ShowOutputOption;
use DrevOps\BehatFormatProgressFail\Printer\PrinterProgressFail;
use Behat\Testwork\Output\NodeEventListeningFormatter;
use Behat\Testwork\Output\Node\EventListener\ChainEventListener;
Expand Down Expand Up @@ -72,6 +73,7 @@ public function initialize(ExtensionManager $extensionManager): void {
public function configure(ArrayNodeDefinition $builder): void {
$builder->children()->scalarNode('name')->defaultValue(self::MOD_ID);
$builder->children()->scalarNode('base_path')->defaultValue(self::BASE_PATH);
$builder->children()->scalarNode(ShowOutputOption::OPTION_NAME)->defaultValue(ShowOutputOption::InSummary->value);
}

/**
Expand All @@ -80,73 +82,50 @@ public function configure(ArrayNodeDefinition $builder): void {
public function load(ContainerBuilder $container, array $config): void {
$name = is_string($config['name']) ? $config['name'] : self::MOD_ID;

$definition = new Definition(
StepListener::class, [
new Reference('output.printer.' . $name),
]
);
$definition = new Definition(StepListener::class, [
new Reference('output.printer.' . $name),
]);
$container->setDefinition(self::ROOT_LISTENER_ID, $definition);

$definition = new Definition(
PrinterProgressFail::class, [
new Reference(self::RESULT_TO_STRING_CONVERTER_ID),
$config['base_path'],
]
);
$container->setDefinition(
'output.printer.' . $name, $definition
);

$definition = new Definition(
NodeEventListeningFormatter::class, [
$config['name'],
'Prints one character per step and fail view pretty.',
['timer' => TRUE],
$this->createOutputPrinterDefinition(),
new Definition(
ChainEventListener::class, [
[
new Reference(self::ROOT_LISTENER_ID),
new Definition(
StatisticsListener::class, [
new Reference('output.progress.statistics'),
new Reference(
'output.node.printer.progress.statistics'
),
]
),
new Definition(
ScenarioStatsListener::class, [
new Reference('output.progress.statistics'),
]
),
new Definition(
StepStatsListener::class, [
new Reference('output.progress.statistics'),
new Reference(
ExceptionExtension::PRESENTER_ID
),
]
),
new Definition(
HookStatsListener::class, [
new Reference('output.progress.statistics'),
new Reference(
ExceptionExtension::PRESENTER_ID
),
]
),
],
]
),
]
);
$definition->addTag(
OutputExtension::FORMATTER_TAG, ['priority' => 100]
);
$container->setDefinition(
OutputExtension::FORMATTER_TAG . '.' . $name, $definition
);
$definition = new Definition(PrinterProgressFail::class, [
new Reference(self::RESULT_TO_STRING_CONVERTER_ID),
$config['base_path'],
]);
$container->setDefinition('output.printer.' . $name, $definition);

$definition = new Definition(NodeEventListeningFormatter::class, [
$config['name'],
'Prints one character per step and fail view pretty.',
[
'timer' => TRUE,
ShowOutputOption::OPTION_NAME => $config[ShowOutputOption::OPTION_NAME],
],
$this->createOutputPrinterDefinition(),
new Definition(ChainEventListener::class, [
[
new Reference(self::ROOT_LISTENER_ID),
new Definition(StatisticsListener::class, [
new Reference('output.progress.statistics'),
new Reference('output.node.printer.progress.statistics'),
]),
new Definition(ScenarioStatsListener::class, [
new Reference('output.progress.statistics'),
]),
new Definition(StepStatsListener::class, [
new Reference('output.progress.statistics'),
new Reference(ExceptionExtension::PRESENTER_ID),
]),
new Definition(HookStatsListener::class, [
new Reference('output.progress.statistics'),
new Reference(ExceptionExtension::PRESENTER_ID),
]),
],
]),
]);

$definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 100]);

$container->setDefinition(OutputExtension::FORMATTER_TAG . '.' . $name, $definition);
}

/**
Expand All @@ -156,13 +135,9 @@ public function load(ContainerBuilder $container, array $config): void {
* The output printer definition.
*/
protected function createOutputPrinterDefinition(): Definition {
return new Definition(
StreamOutputPrinter::class, [
new Definition(
ConsoleOutputFactory::class
),
]
);
return new Definition(StreamOutputPrinter::class, [
new Definition(ConsoleOutputFactory::class),
]);
}

}
64 changes: 47 additions & 17 deletions src/DrevOps/BehatFormatProgressFail/Printer/PrinterProgressFail.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
use Behat\Behat\Output\Node\Printer\StepPrinter;
use Behat\Behat\Tester\Result\ExecutedStepResult;
use Behat\Behat\Tester\Result\StepResult;
use Behat\Config\Formatter\ShowOutputOption;
use Behat\Gherkin\Node\ScenarioLikeInterface as Scenario;
use Behat\Gherkin\Node\StepNode;
use Behat\Testwork\Output\Formatter;
use Behat\Testwork\Output\Printer\OutputPrinter;
use Behat\Testwork\Tester\Result\TestResult;

/**
Expand All @@ -34,7 +36,7 @@ public function __construct(private readonly ResultToStringConverter $resultConv
* {@inheritdoc}
*/
public function printStep(Formatter $formatter, Scenario $scenario, StepNode $step, StepResult $result): void {
$lineWidth = 70;
$line_width = 70;
$printer = $formatter->getOutputPrinter();
$style = $this->resultConverter->convertResultToString($result);

Expand All @@ -60,7 +62,13 @@ public function printStep(Formatter $formatter, Scenario $scenario, StepNode $st
break;
}

if (0 === ++$this->stepsPrinted % $lineWidth) {
$show_output = $formatter->getParameter(ShowOutputOption::OPTION_NAME);
if ($show_output === ShowOutputOption::Yes ||
($show_output === ShowOutputOption::OnFail && !$result->isPassed())) {
$this->printStdOut($formatter->getOutputPrinter(), $result);
}

if (0 === ++$this->stepsPrinted % $line_width) {
$printer->writeln(' ' . $this->stepsPrinted);
}
}
Expand All @@ -81,35 +89,35 @@ protected function printFailure(StepResult $result, StepNode $step): string {

$output = '';

$fileName = '';
$callResult = $result->getCallResult();
$call = $callResult->getCall();
$file_name = '';
$call_result = $result->getCallResult();
$call = $call_result->getCall();
if ($call instanceof DefinitionCall) {
$feature = $call->getFeature();
$fileName = $this->relativizePaths($feature->getFile() ?? '');
$file_name = $this->relativizePaths($feature->getFile() ?? '');
}
$fileLine = $step->getLine();

$output .= PHP_EOL;
$output .= sprintf('{+%s}--- FAIL ---{-%s}', $style, $style);
$output .= PHP_EOL;

$output .= sprintf(sprintf(' {+%s}%%s %%s{-%s} {+comment}# (%%s):%%s{-comment}', $style, $style), $step->getKeyword(), $step->getText(), $fileName, $fileLine);
$output .= sprintf(sprintf(' {+%s}%%s %%s{-%s} {+comment}# (%%s):%%s{-comment}', $style, $style), $step->getKeyword(), $step->getText(), $file_name, $fileLine);
$output .= PHP_EOL;

$stepArguments = $step->getArguments();
$stepArguments = array_map(static function ($item) {
$step_arguments = $step->getArguments();
$step_arguments = array_map(static function ($item) {
if (method_exists($item, '__toString')) {
return $item->__toString();
return $item->__toString();
}

return '';
}, $stepArguments);
return '';
}, $step_arguments);

$stepArguments = array_filter($stepArguments);
$step_arguments = array_filter($step_arguments);

if (count($stepArguments) > 0) {
$output .= sprintf(sprintf(' {+%s}%%s{-%s}', $style, $style), implode(PHP_EOL, $stepArguments));
if (count($step_arguments) > 0) {
$output .= sprintf(sprintf(' {+%s}%%s{-%s}', $style, $style), implode(PHP_EOL, $step_arguments));
$output .= PHP_EOL;
}

Expand All @@ -124,6 +132,28 @@ protected function printFailure(StepResult $result, StepNode $step): string {
return $output . PHP_EOL;
}

/**
* Prints step output (if has one).
*/
protected function printStdOut(OutputPrinter $printer, StepResult $result): void {
if (!$result instanceof ExecutedStepResult || NULL === $result->getCallResult()->getStdOut()) {
return;
}

$step_definition = $result->getStepDefinition();
if (!$step_definition) {
return;
}

$printer->writeln("\n" . $step_definition->getPath() . ':');
$call_result = $result->getCallResult();
$pad = function ($line): string {
return sprintf(' | {+stdout}%s{-stdout}', $line);
};

$printer->write(implode("\n", array_map($pad, explode("\n", (string) $call_result->getStdOut()))));
}

/**
* Transforms path to relative.
*
Expand All @@ -132,8 +162,8 @@ protected function printFailure(StepResult $result, StepNode $step): string {
*/
protected function relativizePaths(string $path): string {
return $this->basePath === '' || $this->basePath === '0' ? $path : str_replace(
$this->basePath . DIRECTORY_SEPARATOR, '', $path
);
$this->basePath . DIRECTORY_SEPARATOR, '', $path
);
}

}
Loading

0 comments on commit 3677543

Please sign in to comment.