Skip to content

Commit

Permalink
Merge pull request #18 from knpuniversity/code-activities-ch4
Browse files Browse the repository at this point in the history
Add code activities to the ch4 (using-behat)
  • Loading branch information
weaverryan committed Oct 20, 2015
2 parents 87a55a8 + 546de2d commit 6e7ad60
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 0 deletions.
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 "dr_dino@example.com"
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 "dr_dino@example.com"
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 `dr_dino@example.com` 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 `dr_dino@example.com`
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

0 comments on commit 6e7ad60

Please sign in to comment.