i have make test with behat in symfony but is not working.
this is my feature:
Feature: dossiertest
#javascript
Scenario: List 2 files in a directory
Given I am on the homepage
Then I should see "hello"
When I go to "/ajoutermed"
Then I should see "ajouter"
And I wait 2 seconds
And I fill in "test_medbundle_med_section" with "tes nom"
And I fill in "test_medbundle_med_info" with "tes nom"
And I press "Ajouter Med"
Then I should see "ajouter"
this is AjouterContext.php:
<?php
namespace test\MedBundle\Behat\Context;
use Behat\Behat\Context\Context;
use Behat\Behat\Context\BehatContext;
use Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\MinkContext;
use test\MedBundle\Entity\Apps;
use test\MedBundle\Entity\Product;
/**
* Defines application features from the specific context.
*/
class AjouterContext extends MinkContext
{
/**
* #When I press :arg1
*/
public function iPress($arg1)
{
self::$driver->findElement(WebDriverBy::cssSelector($arg1))->click();
//$element = $page->find('css',"input[value='$arg1']");
}
/**
* #Then I wait :arg1 seconds
*/
public function iWaitSeconds($arg1)
{
$this->getSession()->wait($arg1 * 1000);
}
}
behat.yml:
default:
suites:
default:
bundle: MedBundle
contexts:
- test\MedBundle\Behat\Context\FeatureContext
- test\MedBundle\Behat\Context\AjouterContext
extensions:
Behat\Symfony2Extension: ~
Behat\MinkExtension:
base_url: http://localhost/test/web/app_dev.php
goutte: ~
javascript_session: selenium2
selenium2:
wd_host: http://localhost:4444/wd/hub
sessions:
default:
symfony2: ~
and this is my problem when i launche test:
enter image description here
help me please and thank you
regarding your error message, there is an ambigous "#When I press" action. If you change your function iPress by
/**
* #When I click on input :arg1
*/
public function iClickOnInput($arg1)
{
self::$driver->findElement(WebDriverBy::cssSelector($arg1))->click();
//$element = $page->find('css',"input[value='$arg1']");
}
It should work.
If is a button element and it has Ajouter Med as one of the following id|name|title|alt|value then it should work with I press "Ajouter Med"
If this is a link then you should use I follow "Ajouter Med"
Make sure you try to search the appropriate method to use, try using an IDE editor with autocomplete for Behat/Gherkin steps and for php methods.
Avoid writing your own custom base methods/steps, do this only if you have no alternative, you might end with 2-3 steps that are doing the same thing.
Related
I want to use annotations with overblog graphql in symfony. When i create a provider with an query I get an error about the schema.
error: At least one schema should be declare
I don`t know how to config the schema in the config file. Normally I use yaml as type.
When I use the defaults its using CoreQuery whats pointing to the yaml config file. I don`t know how to change this for using annotations in php. When I remove the schema from definitions i get the same error.
What do I need to change to use annotation with overblog graphql bundle?
/config/packages/graphql.yaml
overblog_graphql:
definitions:
schema:
default:
query: CoreQuery
# mutation: CoreMutation
show_debug_info: '%kernel.debug%'
mappings:
auto_discover: false
types:
- type: annotation
dir: "%kernel.project_dir%/src/GraphQL"
suffix: ~
/src/Graphql/Types/SensorProviders.php
namespace App\Graphql\Types;
use Overblog\GraphQLBundle\Annotation as GQL;
/**
* #GQL\Provider
*/
class SensorProviders {
/**
* #GQL\Query(type="[Sensor]", name="sensors")
*/
public function getSensors() {
return [];
}
}
/src/Graphql/Types/Sensor.php
namespace App\Graphql\Types;
use Overblog\GraphQLBundle\Annotation as GQL;
/**
* #GQL\Type
*/
class Sensor
{
/**
* #GQL\Field(type="Integer!")
*/
public $id;
}
I had the same issues, but after hours of debugging, i figured it out:
With your graphql.yaml you would need following additional file:
/src/Graphql/Types/CoreQuery.php:
namespace App\Graphql\Types;
use Overblog\GraphQLBundle\Annotation as GQL;
/**
* #GQL\Type
*/
class CoreQuery
{
}
Basically you need to define an empty root type and all annotated queries get automatically added.
Same for mutations.
This is my behat.yml file. I tried variants inorder to link the FeatureContext file. Can someone help me by checking if that is the right way to link the feature context file in the behat.yml file. in case path for the featurecontext file is required this is the path %path.base%/features/bootstrap
default:
suites:
default:
path: %paths.base%/features
contexts:
- Behat\MinkExtension\Context\MinkContext
- FeatureContext
extensions:
Behat\MinkExtension:
base_url: http://echidnaacerdev.prod.acquia-sites.com/
sessions:
default:
goutte: ~
This is my FeatureContext.php file
<?php
use Behat\Behat\Context\Context;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\MinkContext;
/**
* Defines application features from the specific context.
*/
class FeatureContext implements Context
{
/**
* Initializes context.
*
* Every scenario gets its own context instance.
* You can also pass arbitrary arguments to the
* context constructor through behat.yml.
*/
public function __construct()
{
}
/**
* Click some text
*
* #When /^I click on the text :text$/
*/
public function iClickOnTheText($text)
{
$session = $this->getSession();
$element = $session->getPage()->find('xpath',$session->getSelectorsHandler()->selectorToXpath('xpath', '*//*[text()="'. $text .'"]'));
if (null === $element) {
throw new InvalidArgumentException(sprintf('Cannot find text: "%s"', $text));
}
$element->click();
}
}
Im not sure how to i define the feature context file in my behat.yml. Can anyone help me out with this. the error message i get is that the
behat\minkextension\context\minkcontext has missing steps. define them with the snippets
For the particular step When I click on the text "Members"
You are not using the step correctly, you should use When I click on the text Members , remember the matching is done by regular expression and the sintax should be Gherkin or Turnip.
FeatureContext should extend MinkContext
Remove MinkContext from yml, is not needed if you extend it as I said, also you can remove that path, by default it is looking in features/bootstrap
I followed the Behat 2.5 docs to test mails. After a few tweaks to match Behat 3 I have ended with the following code (I have removed non-relevant parts):
public function getSymfonyProfile()
{
$driver = $this->mink->getSession()->getDriver();
if (!$driver instanceof KernelDriver) {
// Throw exception
}
$profile = $driver->getClient()->getProfile();
if (false === $profile) {
// Throw exception
}
return $profile;
}
/**
* #Then I should get an email with subject :subject on :email
*/
public function iShouldGetAnEmail($subject, $email)
{
$profile = $this->getSymfonyProfile();
$collector = $profile->getCollector('swiftmailer');
foreach ($collector->getMessages() as $message) {
// Assert email
}
// Throw an error if something went wrong
}
When I run this test, it throws the following error:
exception 'LogicException' with message 'Missing default data in Symfony\Bundle\SwiftmailerBundle\DataCollector\MessageDataCollector' in vendor/symfony/swiftmailer-bundle/Symfony/Bundle/SwiftmailerBundle/DataCollector/MessageDataCollector.php:93
Stack trace:
#0 vendor/symfony/swiftmailer-bundle/Symfony/Bundle/SwiftmailerBundle/DataCollector/MessageDataCollector.php(122): Symfony\Bundle\SwiftmailerBundle\DataCollector\MessageDataCollector->getMailerData('default')
#1 features/bootstrap/FeatureContext.php(107): Symfony\Bundle\SwiftmailerBundle\DataCollector\MessageDataCollector->getMessages()
My profiler is configured as follows:
# app/config/config_test.yml
framework:
test: ~
profiler:
enabled: true
collect: true
It seems that the Profile is correctly loaded and the MessageDataCollector from Swiftmailer does exist, but it is not doing its work as expected. Any clue to solve this?
Maybe the issue you have has been fixed as I do not have this anymore (I'm using Behat v3.0.15, BrowserKit driver 1.3.* and Symfony v2.6.6).
I managed to reproduce your error but only when I forgot to enable profiler data collecting:
profiler:
collect: false
Once this problem solved (the configuration you provided solving the problem for me) I managed to check emails in my Behat tests.
Two solutions for this:
Solution #1: Intercepting redirects globally
If it does not break all your other tests you can do so by configuring your web profiler as follows:
web_profiler:
intercept_redirects: true
Solution #2: Preventing client to follow redirections temporarily
For my part, intercepting redirections globally in the configuration broke most of my other functional tests. I therefore use this method instead.
As preventing redirections allows mainly to check data in the data collectors I decided to use a tag #collect on each scenario requiring redirect interception. I then used #BeforeScenario and #AfterScenario to enable this behaviour only for those scenarios:
/**
* Follow client redirection once
*
* #Then /^(?:|I )follow the redirection$/
*/
public function followRedirect()
{
$this->getDriver()->getClient()->followRedirect();
}
/**
* Restore the automatic following of redirections
*
* #param BeforeScenarioScope $scope
*
* #BeforeScenario #collect
*/
public static function disableFollowRedirects(BeforeScenarioScope $scope)
{
$context = $scope->getEnvironment()->getContext(get_class());
$context->getDriver()->getClient()->followRedirects(false);
}
/**
* Restore the automatic following of redirections
*
* #param AfterScenarioScope $scope
*
* #AfterScenario #collect
*/
public static function restoreFollowRedirects(AfterScenarioScope $scope)
{
$context = $scope->getEnvironment()->getContext(get_class());
$context->getDriver()->getClient()->followRedirects(true);
}
It's not the answer your are looking for, but I'm pretty sure it will suits your needs (perhaps more).
If I can suggest, try using Mailcatcher with this bundle: https://packagist.org/packages/alexandresalome/mailcatcher
You'll be able to easily tests if emails are sent, what's their subject, follow a link in the body, and so on...
Many steps are included with this bundle.
In my tests I use this step to confirm a javascript confirm popup:
/**
* #when /^(?:|I )confirm the popup$/
*/
public function confirmPopup()
{
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
}
This step work fine with selenium2 and chrome/firefox, but doesn't work with phantomjs.
How can I handle a confirm popup with phantomjs ?
for informations:
symfony: 2.0.23
behat: 2.4.6
mink: 1.5.0
Symfony2Extension: 1.0.2
MinkExtension: 1.1.4
MinkBrowserKitDriver: 1.1.0
MinkSelenium2Driver: 1.1.0
phamtomjs 1.9.1
behat.yml
default:
extensions:
Behat\Symfony2Extension\Extension:
mink_driver: true
Behat\MinkExtension\Extension:
base_url: "http://localhost:8000/app_test.php"
default_session: selenium2
selenium2:
wd_host: "http://localhost:9876/wd/hub"
Thanks!
PS: Here the gist : https://gist.github.com/blazarecki/2888851
I updated my "Selenium2Driver.php" with the following:
public function acceptAlert()
{
$this->wdSession->accept_alert();
}
This makes the accept_alert() available for the driver.
So in the script, you could do something line this to accept the alert.
$this->getSession()->getDriver()->acceptAlert();
Note that I'm using the RawMinkContext not the native MinkContext
phantomjs is a headless browser, therefore all dialogs are not show and cannot be interacted with. A solution is to rewrite widnow.confirm and window.alert with your own functions that return pre-defined values.
Since a scenario runs within the same driver, it is perfectly safe to overwrite native methods with pre-defined return values (you will not have a situation where you really need to see a window within the same scenario). Moreover, it is safe to call these step definitions multiple times within a single scenario to flip returned value.
/**
* #When I accept confirmation dialogs
*/
public function acceptConfirmation() {
$this->getSession()->getDriver()->executeScript('window.confirm = function(){return true;}');
}
/**
* #When I do not accept confirmation dialogs
*/
public function acceptNotConfirmation() {
$this->getSession()->getDriver()->executeScript('window.confirm = function(){return false;}');
}
Scenario example:
Scenario: Removal of something with confirmation dialog
Given I accept confirmation dialogs
And I click a ".mylink" element
And I wait for AJAX to finish
And I should not see a ".some-removed-element" element
(I'm going to explain situation, incase someone knows of a better way to accomplice what I want to do).
Using Symfony2 + Behat + Symfony2Extension + Mink +
We have an application with multiple urls that will be visited during scenarios.
I do understand that you use the parameters sent in from the FeatureContext __construct method, but what I'm trying to do is set up the urls in the behat.yml file so that we can use them in our custom Context to visit the urls.
Looking at how the extensions work I have setup the dependency injection as follows:
class Extension implements ExtensionInterface
{
/**
* Loads a specific configuration.
*
* #param array $config Extension configuration hash (from behat.yml)
* #param ContainerBuilder $container ContainerBuilder instance
*/
public function load(array $config, ContainerBuilder $container)
{
$container->setParameter('url_one', $config['url_one']);
$container->setParameter('url_two', $config['url_two']);
}
/**
* Setups configuration for current extension.
*
* #param ArrayNodeDefinition $builder
*/
public function getConfig(ArrayNodeDefinition $builder)
{
$builder->
children()->
scalarNode('one_url')->
isRequired()->
end()->
scalarNode('two_url')->
isRequired()->
end()->
end();
}
code continues....
And my behat.yml looks like this:
default:
extensions:
Behat\MinkExtension\Extension:
goutte: ~
selenium2: ~
Behat\Symfony2Extension\Extension: ~
Acme\AcmeExtension\Extension:
url_one: 'http://example1.com'
url_two: 'http:/example2.com'
Now in my FeatureContext.php class I would like to do the following:
$url = $kernel->getContainer()->getParameter('url_one');
But this is not working, it is returning parameters from my Symfony2 application, which is expected since I have symfony2extension enabled. But I can not access the parameters or services from the extension class.
(Please note that if I'm in the Extension class in the load method and I call the parameter I just set it returns it, so I know it is set, but it must be set to a different container?)
First off is this possible? And if so what should I do to make it work.
Many thanks for any help.
Obviously, $kernel->getContainer() returns you container of the Symfony2 app kernel. Those kernel and container are not shared with Behat. Behat has its own container instance, which it uses to manage own services. Which means that extension is setting parameters inside Behat container, but you are attempting to access your app kernel container. That's why you have different results.
Now, the question is, how would you pass some value from your extension to context class. Answer is context initialiser. Check out:
https://github.com/Behat/MinkExtension/blob/master/src/Behat/MinkExtension/services/core.xml#L43-L47
https://github.com/Behat/MinkExtension/blob/master/src/Behat/MinkExtension/Context/Initializer/MinkAwareInitializer.php#L26-L77