Skip to content

Example to make it possible to inject Page objects in symfony 3.4 #9

@winkbrace

Description

@winkbrace

For several weeks, we've been busy setting up behat in our big 20 year old symfony 3.4 project. During this time we made a bunch of changes to make it simpler to write behat contexts.

This is one of these changes. In order to make it possible to work with symfony autowiring of Page objects, we had to extend SymfonyPage and apply these changes.

The getUrl issue might only exist on our project, but the others should also be a problem for "clean" symfony projects.

The reason I'm opening this issue, is because I'd like to know if you are interested in these kind of changes and if we should make pull requests for something. (We also extended Element to enable us to search for html elements only within that element. Furthermore we added means to interact with Element objects on a Page object.)

<?php

namespace Tweakers\Test\Behat\Page;

use Behat\Mink\Session;
use FriendsOfBehat\PageObjectExtension\Page\SymfonyPage;
use FriendsOfBehat\SymfonyExtension\Mink\MinkParameters;
use Symfony\Component\Routing\RouterInterface;

abstract class BasePage extends SymfonyPage
{
    /**
     * $minkParameters needs to be type hinted for auto-wiring of Pages to work.
     */
    public function __construct(Session $session, MinkParameters $minkParameters, RouterInterface $router)
    {
        parent::__construct($session, $minkParameters, $router);
    }

    protected function getUrl(array $urlParameters = []): string
    {
        // For some reason the url contains the host part twice (e.g. http://domain.com/domain.com/page)
        return str_replace(HOST_NAME . '/' . HOST_NAME, HOST_NAME, parent::getUrl($urlParameters));
    }

    protected function verifyUrl(array $urlParameters = []): void
    {
        $this->fixSymfonyHost();

        parent::verifyUrl($urlParameters);
    }

    private function fixSymfonyHost(): void
    {
        $url  = $this->getDriver()->getCurrentUrl();
        $host = parse_url($url, PHP_URL_HOST);

        $this->router->getContext()->setHost($host);
    }
}

This change allowed us to write our Domain Contexts like this snippet:

class NewsContext extends FeatureContext
{
    /** @var NewsPortalPage */
    private $newsPortal;

    /** @var NewsArticlePage */
    private $articlePage;

    /** @var Heading */
    private $heading;

    public function __construct(
        NewsPortalPage $portal,
        NewsArticlePage $articlePage,
        Heading $heading
    ) {
        $this->newsPortal = $portal;
        $this->articlePage = $articlePage;
        $this->heading = $heading;
    }

    /**
     * @When I visit the news portal
     */
    public function iVisitTheNewsPortal()
    {
        // try to open, because the news portal redirects to listing of today
        $this->newsPortal->tryToOpen();
    }

    /**
     * @When /^I view (this news article)$/
     * @When I read the news article :newsArticle
     * @Given I am reading the news article :newsArticle
     *
     * @see NewsArticleTransformer::ensureNewsArticle()
     */
    public function iViewThisNewsArticle(NewsArticle $newsArticle)
    {
        $this->articlePage->open(['id' => $newsArticle->getId()]);
    }

    /**
     * @Then /^I should see (this news article)$/
     *
     * @see SharedStorageTransformer::getResource()
     */
    public function iShouldSeeThisNewsArticle(NewsArticle $article)
    {
        expect($this->heading)->toHaveText($article->getTitle());
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions