-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from knpuniversity/code-activities-ch4
Add code activities to the ch4 (using-behat)
- Loading branch information
Showing
3 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
) | ||
; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters