示例#1
0
 /**
  * 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("##glados_step##%s##glados_step##\n", json_encode($stepStats));
         }
     }
 }
 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);
 }
 /**
  * Automated Screenshot on fail
  *
  *
  * @AfterStep
  */
 public function afterStep(Behat\Behat\Event\StepEvent $event)
 {
     $context = $event->getContext();
     if ($context->getMinkParameter('browser_name') == 'phantomjs' && $event->getResult() == StepEvent::FAILED) {
         $this->iTakeAScreenshotWithName('fail');
     }
 }
 /**
  * After state hook to write failure back to the page, which alerts phantom to a 
  * failure. See: http://shaneauckland.co.uk/2012/11/capturing-screenshots-with-mink-sahi-and-phantomjs/
  * 
  * @AfterStep
  */
 public function afterStep(StepEvent $event)
 {
     $context = $event->getContext();
     if ($context->getMinkParameter('browser_name') == 'phantomjs' && $event->getResult() == StepEvent::FAILED) {
         $javascript = 'window.callPhantom({value:"fail"})';
         $context->getSession()->executeScript($javascript);
     }
 }
示例#5
0
 /**
  * @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);
     }
 }
示例#6
0
 /**
  * @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']);
 }
 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);
 }
 /**
  * Shows last response of failed step with preconfigured command.
  * Configuration is based on `behat.yml`:
  *
  * `show_auto` enable this listener (default to false)
  * `show_cmd` command to run (`open %s` to open default browser on Mac)
  * `show_tmp_dir` folder where to store temp files (default is system temp)
  *
  * @param StepEvent $event
  */
 public function showFailedStepResponse($event)
 {
     if (StepEvent::FAILED !== $event->getResult()) {
         return;
     }
     if (null === $this->parameters['show_cmd']) {
         throw new \RuntimeException('Set "show_cmd" parameter in behat.yml to be able to open page in browser (ex.: "show_cmd: open %s")');
     }
     $filename = rtrim($this->parameters['show_tmp_dir'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . uniqid() . '.html';
     file_put_contents($filename, $this->mink->getSession()->getPage()->getContent());
     system(sprintf($this->parameters['show_cmd'], escapeshellarg($filename)));
 }
示例#9
0
 /** @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";
     }
 }
 /**
  * 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.';
         }
     }
 }
 /**
  * @BeforeStep @maintains-authentication-state
  */
 public function beforeStepObtainAuthenticationState(StepEvent $event)
 {
     // Don't bother if an exception has occurred.
     if ($event->hasException()) {
         return;
     }
     $session = $this->getSession();
     $page = $session->getPage();
     $element = $page->findById("nav-profile");
     $this->authenticationStateLoggedIn = $element && $element->isVisible();
     // Let the end user know what we did.  (This is mostly because this *is* a demo.)
     if ($this->authenticationStateLoggedIn) {
         $this->printDebug('[BeforeStepEvent] A user is signed in.');
     } else {
         $this->printDebug('[BeforeStepEvent] A user is not signed in.');
     }
 }
 public function afterStep(StepEvent $event)
 {
     if (!$this->valid()) {
         return false;
     }
     $result = $event->getContext()->getSession()->evaluateScript("return window.s");
     if ($result) {
         $title = $event->getLogicalParent()->getTitle();
         $subtitle = $this->getStepText($event);
         $this->collectResult($title, $subtitle, $result);
     }
 }
示例#13
0
 /**
  * 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());
 }
示例#14
0
    /**
     * 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);
    }
示例#15
0
 /** @AfterStep */
 public function after(\Behat\Behat\Event\StepEvent $event)
 {
     if ($event->getResult() == \Behat\Behat\Event\StepEvent::FAILED) {
         $screenshot_path = $this->getParameter('screenshots_path');
         if ($screenshot_path) {
             $fileName = uniqid() . '.png';
             $path = rtrim($screenshot_path, '/') . '/' . $fileName;
             $this->getSession()->getDriver()->capturePageScreenshot($path);
             $screenshot_url = $this->getParameter('screenshots_url');
             echo "Captured screenshot: " . ($screenshot_url ? $screenshot_url . '/' . $fileName : $path) . PHP_EOL;
         }
     }
 }
示例#16
0
 /**
  * Collects step statistics.
  *
  * @param   Behat\Behat\Event\StepEvent $event  step.after event
  */
 private function collectStepStats(StepEvent $event)
 {
     ++$this->stepsCount;
     ++$this->stepsStatuses[$this->statuses[$event->getResult()]];
     switch ($event->getResult()) {
         case StepEvent::UNDEFINED:
             $hash = $event->getSnippet()->getHash();
             if (!isset($this->definitionsSnippets[$hash])) {
                 $this->definitionsSnippets[$hash] = $event->getSnippet();
             } else {
                 $this->definitionsSnippets[$hash]->addStep($event->getSnippet()->getLastStep());
             }
             break;
         case StepEvent::FAILED:
             $this->failedStepsEvents[] = $event;
             break;
         case StepEvent::PENDING:
             $this->pendingStepsEvents[] = $event;
             break;
     }
 }
示例#17
0
 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;
 }
 /**
  * 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 = [];
     }
 }
 /**
  * Converts the behat-Result to the serverSide format.
  *
  * @param StepEvent $event The event containing the behat StepResult.
  * @return stub_php\stepResult
  */
 public function convertResultToStepResult(StepEvent $event)
 {
     switch ($event->getResult()) {
         case StepEvent::PASSED:
             return stub_php\stepResult::SUCCESS;
         case StepEvent::UNDEFINED:
         case StepEvent::PENDING:
         case StepEvent::SKIPPED:
             return stub_php\stepResult::SKIPPED;
         case StepEvent::FAILED:
             if ($event->hasException() && !$this->_isAssertionError($event->getException())) {
                 return stub_php\stepResult::ERROR;
             } else {
                 return stub_php\stepResult::FAILURE;
             }
         default:
             return stub_php\stepResult::ERROR;
     }
 }
示例#20
0
 /**
  * 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());
 }
示例#21
0
 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);
 }
示例#22
0
 /**
  * Listens to "step.after" event.
  *
  * @param StepEvent $event
  */
 public function afterStep(StepEvent $event)
 {
     if ($event->hasException()) {
         $this->exceptions[] = $event->getException();
         $this->exceptionsCount++;
     }
     ++$this->stepsCount;
 }
 /**
  * @AfterStep @javascript
  *
  * After every step in a @javascript scenario, we want to wait for AJAX
  * loading to finish.
  */
 public function afterStep(StepEvent $event)
 {
     if ($event->getResult() === 0) {
         $this->iWaitForAJAX();
     }
 }
 /**
  * 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}");
         }
     }
 }
示例#25
0
 /**
  * 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);
 }
 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));
 }
示例#27
0
 /**
  * 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 StepEvent $event
  */
 public function afterStep(StepEvent $event)
 {
     if ($event->hasException()) {
         if ($event->getResult() === StepEvent::SKIPPED || $event->getResult() === StepEvent::PENDING || $event->getResult() === StepEvent::UNDEFINED) {
             $this->pendingCount++;
         } else {
             $this->exceptions[] = $event->getException();
             $this->exceptionsCount++;
             $this->failureCount++;
         }
     }
     ++$this->stepsCount;
     ++$this->scenarioStepsCount;
 }
示例#29
0
 /**
  * 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);
         }
     }
 }
 /**
  * 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;
 }