/** * Take a screenshot when a step fails * * @param StepEvent $event * * @AfterStep */ public function takeScreenshotAfterFailedStep(StepEvent $event) { if ($event->getResult() === StepEvent::FAILED) { $driver = $this->getSession()->getDriver(); $rootDir = dirname($this->getParameter('kernel.root_dir')); $filePath = $event->getLogicalParent()->getFile(); $stepStats = ['scenario_file' => substr($filePath, strlen($rootDir) + 1), 'scenario_line' => $event->getLogicalParent()->getLine(), 'scenario_label' => $event->getLogicalParent()->getTitle(), 'exception' => $event->getException()->getMessage(), 'step_line' => $event->getStep()->getLine(), 'step_label' => $event->getStep()->getText(), 'status' => 'failed']; if ($driver instanceof Selenium2Driver) { $dir = getenv('WORKSPACE'); $buildUrl = getenv('BUILD_URL'); if (false !== $dir) { $dir = sprintf('%s/app/build/screenshots', $dir); } else { $dir = '/tmp/behat/screenshots'; } $lineNum = $event->getStep()->getLine(); $filename = strstr($event->getLogicalParent()->getFile(), 'features/'); $filename = sprintf('%s.%d.png', str_replace('/', '__', $filename), $lineNum); $path = sprintf('%s/%s', $dir, $filename); $fs = new \Symfony\Component\Filesystem\Filesystem(); $fs->dumpFile($path, $driver->getScreenshot()); if (false !== $dir) { $path = sprintf('%s/artifact/app/build/screenshots/%s', $buildUrl, $filename); } $stepStats['screenshot'] = $path; $this->getMainContext()->addErrorMessage("Step {$lineNum} failed, screenshot available at {$path}"); } if ('JENKINS' === getenv('BEHAT_CONTEXT')) { echo sprintf("[1;37m##glados_step##%s##glados_step##[0m\n", json_encode($stepStats)); } } }
/** * Listens to "step.after" event. * * @param StepEvent $event * * @uses printStep() */ public function afterStep(StepEvent $event) { if ($this->inBackground && $this->isBackgroundPrinted) { return; } if ($this->isStepChainParent($event->getStep())) { $isStepChainParent = true; $this->inChain = false; } if (!$this->inBackground && $this->inOutlineExample) { $this->delayedStepEvents[] = $event; return; } if ($this->inChain) { $this->chainedSteps[] = $event; return; } $this->printStep($event->getStep(), $event->getResult(), $event->getDefinition(), $event->getSnippet(), $event->getException()); if (isset($this->chainedSteps) && count($this->chainedSteps) && isset($isStepChainParent) && $isStepChainParent) { foreach ($this->chainedSteps as $event) { $this->write($this->indent); $this->printStep($event->getStep(), $event->getResult(), $event->getDefinition(), $event->getSnippet(), $event->getException()); } $this->chainedSteps = []; } }
public function beforeStep(StepEvent $event) { $file = $event->getStep()->getFile(); $relativePath = ltrim(str_replace($this->cwd, '', $file), '\\/'); $text = $event->getStep()->getText(); $type = $event->getStep()->getType(); $line = $event->getStep()->getLine(); $id = sprintf('%s on %s %s line: %s', $relativePath, $type, $text, $line); $this->startCoverage($id); }
/** @AfterStep */ public function afterStep(StepEvent $event) { /** * @var $context \Behat\MinkExtension\Context\MinkContext */ $context = $event->getContext(); if ($this->parameters['screenshots']['enabled'] && $context->getMinkParameter('browser_name') == 'phantomjs' && $event->getResult() == StepEvent::FAILED) { $string = str_replace("'", "_", $event->getStep()->getLine() . ":" . $event->getStep()->getText()); $context->getSession()->executeScript('window.callPhantom(\'' . $string . '\')'); //TODO: show output via console; toggle output print "Wrote screenshot to {$string}\n"; } }
function it_should_stop_coverage_on_afterStep_event(CodeCoverageSession $coverageSession, StepEvent $step, StepNode $node) { $step->getStep()->willReturn($node); $step->getResult()->willReturn(StepEvent::PASSED); $coverageSession->stop()->shouldBeCalled(); $this->afterStep($step); }
/** * @AfterStep @javascript */ public function failScreenshots(StepEvent $event) { if ($event->getResult() == StepEvent::FAILED) { $scenarioName = urlencode(str_replace(' ', '_', $event->getStep()->getParent()->getTitle())); $filename = sprintf('fail_%s_%s.png', time(), $scenarioName); $this->saveScreenshot($filename, $this->screenshotDir); } }
/** * @AfterStep * * Save the output HTML & a screenshot after a failed test. * * @param \Behat\Behat\Event\StepEvent $event */ public function debugDumpAfterFailedStep(\Behat\Behat\Event\StepEvent $event) { if ($event->getResult() !== $event::FAILED) { return; } // Build the information text. $stepInfo = sprintf('Debug FAILED step (%s):', $event->getStep()->getText()); $this->_debugDumpSession(array($stepInfo), $this->debug['dump_html'], $this->debug['dump_screenshot']); }
/** * Take screenshot when step fails. * Works only with Selenium2Driver. * * @AfterStep */ public function takeScreenshotAfterFailedStep(StepEvent $event) { if (StepEvent::FAILED === $event->getResult()) { echo 'This step failed.'; $driver = $this->getSession()->getDriver(); if ($driver instanceof Selenium2Driver) { $step = $event->getStep(); $id = $step->getParent()->getTitle() . '.' . $step->getType() . ' ' . $step->getText(); $fileName = 'Test/Framework/app/screenshot/' . 'Fail.' . preg_replace('/[^a-zA-Z0-9-_\\.]/', '_', $id) . '.jpg'; file_put_contents($fileName, $driver->getScreenshot()); } } else { if ($event->getResult() == 1) { echo 'This step skipped.'; } } }
/** * Searches and runs provided step delegating all the process to the parent class * * Method overwritten to look for: * - Moodle exceptions * - Moodle debugging() calls * - PHP debug messages (depends on the PHP debug level) * * @param StepNode $step step node * @return StepEvent */ protected function executeStep(StepNode $step) { // Redirect to the parent to run the step. $afterEvent = parent::executeStep($step); // Catch Moodle Behat skip exception. if ($afterEvent->getException() instanceof SkippedException) { return new StepEvent($afterEvent->getStep(), $afterEvent->getLogicalParent(), $afterEvent->getContext(), StepEvent::SKIPPED, $afterEvent->getDefinition(), $afterEvent->getException(), null); } // We set $this->dispatchafterstep to true when a step is in the lower level // but if a step is throwing an exception it doesn't arrive to the point where // we set dispatchafterstep to true and the event is not dispatched; here we // set it but we also check failredstep so the parent steps (in a chain) don't // continue dispatching the event. if ($afterEvent->getResult() !== StepEvent::PASSED && $this->failedstep === false) { $this->dispatchafterstep = true; } // Extra step, looking for a moodle exception, a debugging() message or a PHP debug message. $checkingStep = new StepNode('Then', self::EXCEPTIONS_STEP_TEXT, $step->getLine()); $afterExceptionCheckingEvent = parent::executeStep($checkingStep); // If it find something wrong we overwrite the original step result. if ($afterExceptionCheckingEvent->getResult() == StepEvent::FAILED) { // Creating a mix of both StepEvents to report about it as a failure in the original step. $afterEvent = new StepEvent($afterEvent->getStep(), $afterEvent->getLogicalParent(), $afterEvent->getContext(), $afterExceptionCheckingEvent->getResult(), $afterEvent->getDefinition(), $afterExceptionCheckingEvent->getException(), null); } return $afterEvent; }
/** * Listens to "step.after" event. * * @param StepEvent $event * * @uses printStep() */ public function afterStep(StepEvent $event) { if ($this->inBackground && $this->isBackgroundPrinted) { return; } if (!$this->inBackground && $this->inOutlineExample) { $this->delayedStepEvents[] = $event; return; } $this->printStep($event->getStep(), $event->getResult(), $event->getDefinition(), $event->getSnippet(), $event->getException()); }
/** * Take screenshot when a step fails. * * @throws Exception * @param StepEvent $event */ protected function take_screenshot(StepEvent $event) { global $CFG; // Goutte can't save screenshots. if (!$this->running_javascript()) { return false; } // All the run screenshots in the same parent dir. if (!$screenshotsdirname = self::get_run_screenshots_dir()) { $screenshotsdirname = self::$screenshotsdirname = date('Ymd_His'); $dir = $CFG->behat_screenshots_path . DIRECTORY_SEPARATOR . $screenshotsdirname; if (!mkdir($dir, $CFG->directorypermissions, true)) { // It shouldn't, we already checked that the directory is writable. throw new Exception('No directories can be created inside $CFG->behat_screenshots_path, check the directory permissions.'); } } else { // We will always need to know the full path. $dir = $CFG->behat_screenshots_path . DIRECTORY_SEPARATOR . $screenshotsdirname; } // The scenario title + the failed step text. // We want a i-am-the-scenario-title_i-am-the-failed-step.png format. $filename = $event->getStep()->getParent()->getTitle() . '_' . $event->getStep()->getText(); $filename = preg_replace('/([^a-zA-Z0-9\_]+)/', '-', $filename) . '.png'; $this->saveScreenshot($filename, $dir); }
private function buildStepEvent(StepEvent $event) { $node = $event->getStep(); $message = " " . $node->getType() . ' ' . $node->getText() . ' line: ' . $node->getLine(); $this->line = $node->getLine(); $this->file = $node->getFile(); $this->text = $node->getText(); $this->node = $node; return $message; }
/** * Adds a step to the stepBuffer on the server. * * @param StepEvent $event - The step to be added on the server. */ public function beforeStep(StepEvent $event) { $steptext = $event->getStep()->getType() . " " . $event->getStep()->getText(); $stepdata = null; foreach ($event->getStep()->getArguments() as $argument) { if ($argument instanceof PyStringNode) { $steptext .= "\n" . $this->convertPyStringToNormalString($argument); } elseif ($argument instanceof TableNode) { $stepdata = $this->convertTableNodeToServerStringArray($argument); } } $this->_client->addStepToBuffer($steptext, $stepdata); }
public function afterStep(StepEvent $event) { if (!$this->enabled) { return; } if (in_array($event->getResult(), $this->ignoredStates)) { return; } // screenshot not needed for these states $file = $event->getStep()->getParent()->getFeature()->getFile(); $line = $event->getStep()->getLine(); $filename = str_replace('/', '_', ltrim(str_replace($this->rootDir, '', $file), '/')) . '_' . $line . '.png'; /** @var BehatContext $ctx */ $ctx = $event->getContext(); $screenData = $ctx->getSession()->currentScreenshot(); file_put_contents($this->outDir . '/' . $filename, $screenData); $this->currentReport['steps'][] = array('text' => $event->getStep()->getText(), 'file' => $filename, 'result' => $event->getResult(), 'exception' => ($ex = $event->getException()) ? $ex->getMessage() : NULL); }
/** * Listens to "step.after" event. * * @param StepEvent $event * * @uses printStep() */ public function afterStep(StepEvent $event) { $step = $event->getStep(); $newStep = array('type' => $step->getType(), 'text' => $step->getText(), 'arguments' => array(), ''); foreach ($step->getArguments() as $argument) { $newStep['arguments'][] = (string) $argument; } $definition = $event->getDefinition(); if ($definition) { $this->definitions[$definition->getRegex()] = array('regex' => $definition->getRegex(), 'description' => $definition->getDescription(), 'path' => $this->relativizePathsInString($definition->getPath()), 'type' => $definition->getType()); $newStep['definition'] = $definition->getRegex(); } else { $newStep['definition'] = false; } if ($this->inBackground) { $this->currentFeature['background'][$newStep['type'] . $newStep['text']] = $newStep; } else { $this->currentScenario['steps'][] = $newStep; } }
public function takeScreenshot(StepEvent $event) { $driver = $this->getSession()->getDriver(); // quit silently when unsupported if (!$driver instanceof Selenium2Driver) { return; } $parent = $event->getLogicalParent(); $feature = $parent->getFeature(); $step = $event->getStep(); $screenshotPath = null; $path = $this->getMainContext()->getScreenshotPath(); if (!$path) { return; } // quit silently when path is not set \Filesystem::makeFolder($path); $path = realpath($path); if (!file_exists($path)) { file_put_contents('php://stderr', sprintf('"%s" is not valid directory and failed to create it' . PHP_EOL, $path)); return; } if (file_exists($path) && !is_dir($path)) { file_put_contents('php://stderr', sprintf('"%s" is not valid directory' . PHP_EOL, $path)); return; } if (file_exists($path) && !is_writable($path)) { file_put_contents('php://stderr', sprintf('"%s" directory is not writable' . PHP_EOL, $path)); return; } $path = sprintf('%s/%s_%d.png', $path, basename($feature->getFile()), $step->getLine()); $screenshot = $driver->getWebDriverSession()->screenshot(); file_put_contents($path, base64_decode($screenshot)); file_put_contents('php://stderr', sprintf('Saving screenshot into %s' . PHP_EOL, $path)); }
/** * Determine the full pathname to store a failure-related dump. * * This is used for content such as the DOM, and screenshots. * * @param StepEvent $event * @param String $filetype The file suffix to use. Limited to 4 chars. */ protected function get_faildump_filename(StepEvent $event, $filetype) { global $CFG; // All the contentdumps should be in the same parent dir. if (!($faildumpdir = self::get_run_faildump_dir())) { $faildumpdir = self::$faildumpdirname = date('Ymd_His'); $dir = $CFG->behat_faildump_path . DIRECTORY_SEPARATOR . $faildumpdir; if (!is_dir($dir) && !mkdir($dir, $CFG->directorypermissions, true)) { // It shouldn't, we already checked that the directory is writable. throw new Exception('No directories can be created inside $CFG->behat_faildump_path, check the directory permissions.'); } } else { // We will always need to know the full path. $dir = $CFG->behat_faildump_path . DIRECTORY_SEPARATOR . $faildumpdir; } // The scenario title + the failed step text. // We want a i-am-the-scenario-title_i-am-the-failed-step.$filetype format. $filename = $event->getStep()->getParent()->getTitle() . '_' . $event->getStep()->getText(); $filename = preg_replace('/([^a-zA-Z0-9\\_]+)/', '-', $filename); // File name limited to 255 characters. Leaving 4 chars for the file // extension as we allow .png for images and .html for DOM contents. $filename = substr($filename, 0, 250) . '.' . $filetype; return array($dir, $filename); }
/** * Take a screenshot when a step fails * * @param StepEvent $event * * @AfterStep */ public function takeScreenshotAfterFailedStep(StepEvent $event) { if ($event->getResult() === StepEvent::FAILED) { $driver = $this->getSession()->getDriver(); if ($driver instanceof Selenium2Driver) { $dir = getenv('WORKSPACE'); $buildUrl = getenv('BUILD_URL'); if (false !== $dir) { $dir = sprintf('%s/app/build/screenshots', $dir); } else { $dir = '/tmp/behat/screenshots'; } $lineNum = $event->getStep()->getLine(); $filename = strstr($event->getLogicalParent()->getFile(), 'features/'); $filename = sprintf('%s.%d.png', str_replace('/', '__', $filename), $lineNum); $path = sprintf('%s/%s', $dir, $filename); $fs = new \Symfony\Component\Filesystem\Filesystem(); $fs->dumpFile($path, $driver->getScreenshot()); if (false !== $dir) { $path = sprintf('%s/artifact/app/build/screenshots/%s', $buildUrl, $filename); } $this->addErrorMessage("Step {$lineNum} failed, screenshot available at {$path}"); } } }
/** * Return recorded events * * @return array */ public function getEvents() { $events = $this->getEventRecorder()->rip(); foreach ($events as $key => $eventTurple) { list($name, $event) = $eventTurple; if ($event instanceof StepEvent) { $event = new StepEvent($event->getStep(), $event->getLogicalParent(), new NullContext(), $event->getResult(), null, $event->getException() ? new WorkerException($event->getException()->getMessage()) : null, $event->getSnippet()); } if ($event instanceof OutlineExampleEvent) { $event = new OutlineExampleEvent($event->getOutline(), $event->getIteration(), new NullContext(), $event->getResult(), $event->isSkipped()); } if ($event instanceof ScenarioEvent) { $event = new ScenarioEvent($event->getScenario(), new NullContext(), $event->getResult(), $event->isSkipped()); } $event->setDispatcher(new NullEventDispatcher()); $events[$key] = array($name, $event); } return $events; }
/** * Listens to "step.after" event. * * @param Behat\Behat\Event\StepEvent $event * * @uses printStep() */ public function afterStep(StepEvent $event) { $this->printStep($event->getStep(), $event->getResult(), $event->getDefinition(), $event->getSnippet(), $event->getException()); }
/** * Runs step hooks with specified name. * * @param string $name hooks name * @param Behat\Behat\Event\StepEvent $event event to which hooks glued */ protected function fireStepHooks($name, StepEvent $event) { if (!count($this->hooks)) { $this->loadHooks(); } $scenario = $event->getStep()->getParent(); $hooks = isset($this->hooks[$name]) ? $this->hooks[$name] : array(); foreach ($hooks as $hook) { if (is_callable($hook)) { call_user_func($hook, $event); } elseif (!empty($hook[0]) && false !== strpos($hook[0], '@')) { $filter = new TagFilter($hook[0]); if ($filter->isScenarioMatch($scenario)) { call_user_func($hook[1], $event); } } elseif (!empty($hook[0])) { $filter = new NameFilter($hook[0]); if ($filter->isScenarioMatch($scenario)) { call_user_func($hook[1], $event); } } else { call_user_func($hook[1], $event); } } }
/** * @AfterStep */ public function afterStep(StepEvent $event) { $this->_logger()->logInfo('<< End Step: ' . $event->getStep()->getText() . ' >>'); }