Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add code activities to the ch4 (using-behat) #18

Merged
merged 4 commits into from
Oct 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions knpu/Challenges/UsingBehat/IndependentScenariosMC.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace Challenges\UsingBehat;

use KnpU\ActivityRunner\Activity\MultipleChoice\AnswerBuilder;
use KnpU\ActivityRunner\Activity\MultipleChoiceChallengeInterface;

class IndependentScenariosMC implements MultipleChoiceChallengeInterface
{
/**
* @return string
*/
public function getQuestion()
{
return <<<EOF
The intern Bob is writing some scenarios that describe
the behavior of the account area of our paleontology app.
Do you see any problems with the second scenario?

```gherkin
Scenario: Register
Given I am on "/"
When I fill in "email" with "[email protected]"
And I fill in "password" with "roar"
And I press "Register"
Then I should see "You're registered!"

Scenario: View my account area
Given I am on "/login"
When I fill in "email" with "[email protected]"
And I fill in "password" with "roar"
And I press "Login"
And I click "My Account"
Then I should see "My Account Information"
```
EOF;
}

/**
* @param AnswerBuilder $builder
*/
public function configureAnswers(AnswerBuilder $builder)
{
$builder
->addAnswer(<<<EOF
The second scenario shouldn't start on `/login`, it should start on `/`
and then you should click a "Login" link.
EOF
)
->addAnswer(<<<EOF
Scenario 2 uses the `[email protected]` user from scenario 1, but each scenario
should act completely independent of each other.
EOF
, true)
->addAnswer(<<<EOF
The second scenario shouldn't need to repeat the email address and password,
since it is already in the first scenario.
EOF
)
;
}

/**
* @return string
*/
public function getExplanation()
{
return <<<EOF
Each scenario should act completely independent of other scenarios.
Right now, in order for scenario 2 to pass, you *must* run scenario 1
first. This makes your scenarios very fragile and difficult to debug.
Instead, the second scenario should make sure that the `[email protected]`
user is in the database via a `Given` statement. We'll talk more about
how to do this soon.
EOF;
}
}
185 changes: 185 additions & 0 deletions knpu/Challenges/UsingBehat/LsFeatureCoding.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

namespace Challenges\UsingBehat;

use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Node\StepNode;
use KnpU\ActivityRunner\Activity\CodingChallenge\CodingContext;
use KnpU\ActivityRunner\Activity\CodingChallenge\CorrectAnswer;
use KnpU\ActivityRunner\Activity\CodingChallengeInterface;
use KnpU\ActivityRunner\Activity\CodingChallenge\CodingExecutionResult;
use KnpU\ActivityRunner\Activity\CodingChallenge\FileBuilder;
use KnpU\ActivityRunner\Activity\Exception\GradingException;
use KnpU\ActivityRunner\Grading\GherkinGradingTool;

class LsFeatureCoding implements CodingChallengeInterface
{
/**
* @return string
*/
public function getQuestion()
{
return <<<EOF
Linus just told us about an edge case with the `ls` command:
it does *not* show files starting with a `.` by default.
To test for this, we've added two new scenarios that make sure
that a `.dino` file only shows up with the `-a` option.

Execute Behat from the command line, copy in the new step definition,
and then fill in the contents so that our scenario passes.
EOF;
}

public function getFileBuilder()
{
$fileBuilder = new FileBuilder();
$fileBuilder
->addFileContents('ls.feature', <<<EOF
Feature: ls
In order to see the directory structure
As a UNIX user
I need to be able to list the current directory's contents
EOF
)
->addFileContents('features/bootstrap/FeatureContext.php', <<<EOF
<?php

use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;

class FeatureContext implements Context, SnippetAcceptingContext
{
private \$output;

/**
* @Given I have a file named :filename
*/
public function iHaveAFileNamed(\$filename)
{
touch(\$filename);
}

/**
* @When I run :command
*/
public function iRun(\$command)
{
\$this->output = shell_exec(\$command);
}

/**
* @Then I should see :string in the output
*/
public function iShouldSeeInTheOutput(\$string)
{
if (strpos(\$this->output, \$string) === false) {
throw new \Exception(sprintf('Did not see "%s" in output "%s"', \$string, \$this->output));
}
}
}
EOF
, true)
->setEntryPointFilename('ls.feature')
;

return $fileBuilder;
}

public function getExecutionMode()
{
return self::EXECUTION_MODE_GHERKIN;
}

public function setupContext(CodingContext $context)
{
}

public function grade(CodingExecutionResult $result)
{
$gherkin = new GherkinGradingTool($result);

$feature = $gherkin->getFeature('ls.feature');

$scenarios = $feature->getScenarios();

if (empty($scenarios)) {
throw new GradingException('I don\'t see *any* scenarios. Check your syntax on the scenario');
}

$countScenarios = count($scenarios);
if (2 !== $countScenarios) {
throw new GradingException(
sprintf('Make sure to create only a *2* new scenarios. Looks like *%d* was created.', $countScenarios)
);
}

/** @var ScenarioNode $scenario */
foreach ($scenarios as $index => $scenario) {
$scenarioNumber = $index + 1;

if (!$scenario->getTitle()) {
throw new GradingException(sprintf(
'Make sure to put a short title after your scenario %d.',
$scenarioNumber
));
}

/** @var StepNode[] $steps */
$steps = $scenario->getSteps();
$hasGiven = false;
$hasWhen = false;
$hasThen = false;
foreach ($steps as $step) {
if ('Given' == $step->getType()) {
$hasGiven = true;
} elseif ('When' == $step->getType()) {
$hasWhen = true;
} elseif ('Then' == $step->getType()) {
$hasThen = true;
}
}

if (!$hasGiven) {
throw new GradingException(sprintf(
'I don\'t see a `Given` in your scenario %d: you probably want one to have a hidden file starting with `.`.',
$scenarioNumber
));
}
if (!$hasWhen) {
throw new GradingException(sprintf(
'I don\'t see a `When` in your scenario %d: you definitely need some, like for running commands in the terminal.',
$scenarioNumber
));
}
if (!$hasThen) {
throw new GradingException(sprintf(
'I don\'t see a `Then` in your scenario %d: you probably want one where you check if the success message was shown.',
$scenarioNumber
));
}
}
}

public function configureCorrectAnswer(CorrectAnswer $correctAnswer)
{
$correctAnswer
->setFileContents('ls.feature', <<<EOF
Feature: ls
In order to see the directory structure
As a UNIX user
I need to be able to list the current directory's contents

Scenario: Do not list hidden files without "-a" option
Given I have a file named ".dino"
When I run "ls"
Then I should see "" in the output

Scenario: List hidden files with "-a" option
Given I have a file named ".dino"
When I run "ls -a"
Then I should see ".dino" in the output
EOF
)
;
}
}
3 changes: 3 additions & 0 deletions knpu/metadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ chapters:
using-behat:
video_key:
is_finished: false
challenges:
# - Challenges\UsingBehat\LsFeatureCoding
- Challenges\UsingBehat\IndependentScenariosMC
behat-hooks-background:
video_key:
is_finished: false
Expand Down