MinkExtension icon indicating copy to clipboard operation
MinkExtension copied to clipboard

Allow to have different base urls per suite

Open wouterj opened this issue 10 years ago • 14 comments

I've 2 suites in behat: frontend and backend. They both live on another subdomain. There should be a way to configure the base url per suite.

Does this already exists?

wouterj avatar Jul 01 '14 08:07 wouterj

I have the same situation( I do not know how to solve this problem.

sorbing avatar Sep 04 '14 18:09 sorbing

you can always create separete profiles, and define others base_url

timiTao avatar Jan 09 '15 14:01 timiTao

I tried created separate profile but I don't see a configuration to run all test suites with behat switching automatically profile according to the current suite it is executing.

This is my behat.yml. With this configuration, I would like to run all scenario with the tag club2 on club2.localhost and the other on club1.localhost. With this configuration, I can make the club2 suite work by runing the command : behat --suite=club2 --profile=club2. But I am looking for a way to run all suite in one command and automaticaly switching profile in the suite.

default:
    autoload:
        '': %paths.base%/features/bootstrap
    extensions:
        Behat\Symfony2Extension: ~
        SensioLabs\Behat\PageObjectExtension: ~
        Behat\MinkExtension:
            base_url: http://club1.localhost/
            selenium2: ~
    suites:
        default:
            contexts:
                - Context\FeatureContext
                - Context\SecurityContext
            filters:
                tags: ~@club2
        club2:
            contexts:
                - Context\FeatureContext
                - Context\SecurityContext
            filters:
                tags: @club2

club2:
    extensions:
        Behat\Symfony2Extension: ~
        SensioLabs\Behat\PageObjectExtension: ~
        Behat\MinkExtension:
            base_url: http://club2.localhost/
            selenium2: ~

I don't know if I went the right way, but I found a solution by creating a custom context which modify all context in the environment before each scenario.

<?php

namespace Context;

use Behat\Behat\Hook\Scope\BeforeScenarioScope;

/**
 * Description of MinkOverrideContext
 *
 * @author jobou
 */
class MinkOverrideContext extends Base\BaseMinkContext
{

    protected $baseUrl;

    public function __construct($base_url)
    {
        $this->baseUrl = $base_url;

    }

    /** @BeforeScenario */
    public function gatherContexts(BeforeScenarioScope $scope)
    {
        $environment = $scope->getEnvironment();

        foreach ($environment->getContexts() as $context) {
            if ($context instanceof \Behat\MinkExtension\Context\RawMinkContext) {
                $context->setMinkParameter('base_url', $this->baseUrl);
            }
        }
    }
}

And then loading it only for my club2 suite :

suites:
        club2:
            contexts:
                - Context\FeatureContext
                - Context\SecurityContext
                - Context\MinkOverrideContext:
                    base_url: http://club2.localhost/
            filters:
                tags: @club2

It seems to work but I would like to have your feedback on good and bad practice of what I am doing.

jbouzekri avatar Feb 20 '15 09:02 jbouzekri

Indeed, it seems only the base_url of default is taken into account, and the rest are ignored.

amitaibu avatar Mar 03 '15 21:03 amitaibu

That's the closest example that I found for v3, but even when I do the following it doesn't work:

class ApiContext extends MinkContext {

  public function __construct($base_url) {
    $this->setMinkParameter('base_url', $base_url);
  }
}

amitaibu avatar Mar 03 '15 21:03 amitaibu

I think it only changes the base_url parameter for the current context instance. If you look at my example https://github.com/Behat/MinkExtension/issues/155#issuecomment-75208256. I was able to make it works by changing the base_url parameter in all context involved in my test suites. However I don'y know if there is a better solution.

    /** @BeforeScenario */
    public function gatherContexts(BeforeScenarioScope $scope)
    {
        $environment = $scope->getEnvironment();

        foreach ($environment->getContexts() as $context) {
            if ($context instanceof \Behat\MinkExtension\Context\RawMinkContext) {
                $context->setMinkParameter('base_url', $this->baseUrl);
            }
        }
    }

jbouzekri avatar Mar 03 '15 21:03 jbouzekri

I have the same problem.

I use a website with subdomains (two applications linked to each other), and I need to do that, by example:

Feature: 404
    In order to see 404 pages
    As a visitor
    I need to visit bad url

@www1
Scenario: 404 on www1
    Given I am on "blabla"
    Then the response status code should be 404

@www2
Scenario: 404 on www2
    Given I am on "blabla"
    Then the response status code should be 404

I think using tags is the best way to update the base_url for each scenario. But my problem is: how?

    /** @BeforeScenario */
    public function updateUrl(BeforeScenarioScope $scope)
    {
        // Here I need to access configuration
        // If the tag @www1: use www1->base_url in configuration
        // If the tag @www2: use www2->base_url in configuration
        // But… how set the new base url and how make it works :/
    }

I don't want to use profiles because I want to run all tests but on different URLs.

jacquesbh avatar Mar 08 '15 22:03 jacquesbh

With MinkExtension you can call setMinkParameter to set the base url inside the definition of a step. For example, you could have a step:

Given I am on subdomain "foo"

With a definition like:

/**
 * @Given I am on subdomain :name
 */
public function iAmOnSubdomain($name)
{
    $url = 'http://'.$name.'.myapp.com';
    $this->setMinkParameter('base_url', $url);
}

You can also call getMinkParameter('base_url') to get the default and alter as needed.

kyleferguson avatar Aug 20 '15 03:08 kyleferguson

Combining the answers of jacquesbh and kyleferguson you could do something like this:

  1. Using tags to change the base_url
Feature: 404
    In order to see 404 pages
    As a visitor
    I need to visit bad url

@www1
Scenario: 404 on www1
    Given I am on "blabla"
    Then the response status code should be 404

@www2
Scenario: 404 on www2
    Given I am on "blabla"
    Then the response status code should be 404
  1. Using setMinkParameter to change the base_url
/** 
 * @BeforeScenario @www1
 */
public function updateUrlToWw1()
{
    $this->setMinkParameter('base_url', 'url to www1');
}

/** 
 * @BeforeScenario @www2
 */
public function updateUrlToWw2()
{
    $this->setMinkParameter('base_url', 'url to www2');
}

capkafitz avatar Oct 20 '16 06:10 capkafitz

I like this solution!

It's a really good idea, very simple. As simple that we didn't see it!

jacquesbh avatar Oct 25 '16 18:10 jacquesbh

BeforeScenario & setMinkParameter is setting the value correctly,

but for the step

Given I am on the homepage OR Given I am on "xyz"

This resets the value of the base_url to the value defined in YML file

sumachaa avatar Dec 15 '16 21:12 sumachaa

Sorry to bump this but for us the solution of jbouzekri actually did the trick. So some context, we set a base_url in our custom FeatureContext since we can't use the selenium2 base_url anymore if we want to switch around.

In our behat.yml we added a custom parameter which we save in our FeatureContext.

Behat.yml

default:
    suites:
        default:
            contexts:
                - FeatureContext:
                    parameters:
                        base_url: "https://pim.local.example.com"

The basic logic is that we set the base url for every scenario with the before scenario hook. If we want to change it we call an extra step Given I change the base url to frontend (We only need to switch between the first sub domain https://pim.example.com and https://example.com or another example https://pim.local.example.com and https://local.example.com

Featurecontext:

  /**
   * Parameters array.
   *
   * @var array
   */
  protected $parameters;

  /**
   * Environment array.
   *
   * @var array
   */
  protected $environment;

  /**
   * Initializes context.
   *
   * Every scenario gets its own context instance.
   * You can also pass arbitrary arguments to the
   * context constructor through behat.yml.
   *
   * @param array $parameters
   *   Parameters from the behat.yml.
   */
  public function __construct($parameters) {
    $this->parameters = $parameters;
  }

  /**
   * Set before each scenario the base URL, if needed override it.
   *
   * @see iChangeTheBaseUrlToFrontend
   *
   * @BeforeScenario
   */
  public function beforeScenario(BeforeScenarioScope $scope) {
    // Load and save the environment for each scenario.
    $this->environment = $scope->getEnvironment();
    // Set the base URL. Can be overridden check @see.
    $base_url = $this->parameters['base_url'];
    $this->setBaseUrl($base_url);
  }

  /**
   * Function to change the base URL to frontend, needed for all frontend tests.
   *
   * @Given I change the base url to frontend
   */
  public function iChangeTheBaseUrlToFrontend() {
    $base_url = $this->parameters['base_url'];
    $base_url = str_replace('https://pim.', '', $base_url);
    $url = 'https://' . $base_url;
    $this->setBaseUrl($url);
  }

  /**
   * Sets the base URL for all environments.
   *
   * @param string $url
   *   The url to set.
   *
   * @see: https://github.com/Behat/MinkExtension/issues/155#issuecomment-77041296
   */
  private function setBaseUrl($url) {
    foreach ($this->environment->getContexts() as $context) {
      if ($context instanceof \Behat\MinkExtension\Context\RawMinkContext) {
        $context->setMinkParameter('base_url', $url);
      }
    }
  }

I hope this can help some one else in the future since it was quite a challenge to find this out :)

BramDriesen avatar Feb 22 '17 08:02 BramDriesen

Well, this is the repo of the MinkExtension. So of course everything is about Mink. Anything else is out of the scope of this extension.

stof avatar Jul 17 '19 11:07 stof

Not sure if this aligns with your requirements, we have different domains for certain languages and organizations which again have differing permission configurations and so on, meaning we have to test them all.

I made the base_url dependent on the environment variable APP_URL, which is defined with a default value used in most of the tests.

base_url: "http://%env(APP_URL)%/"

When I want to test a different domain now, I can run the suite parameterized like so:

APP_URL=differingdomain ./vendor/bin/behat features/somefeature.feature

Hope this helps.

cmedi32 avatar Jan 22 '24 12:01 cmedi32