Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
winkbrace opened this issue Feb 20, 2019 · 2 comments
Open

Comments

@winkbrace
Copy link

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());
    }
}
@Zales0123
Copy link
Member

Hello @winkbrace and thank you for this post! I've been thinking about enabling autowiring in this extension for the last days, but I had no time to do it. I would be happy to accept the PR with a sufficient change, can you open it? We can then discuss functionalities there, as it's much easier when you can refer to a specific line/block of code :) Thanks! 🚀

@winkbrace
Copy link
Author

winkbrace commented Mar 6, 2019

Hmm I just thought of an alternative. You could also use a transformer to inject the Page object in the Context.

    /**
     * @When /^I visit (the login page)$/
     * @see PageTransformer::createPage()
     */
    public function iVisitTheLoginPage(LoginPage $page)
    {
        $page->open();
    }

Then the path to the Page objects must be specified in the config, so the PageTransformer knows where to search

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants