phpunit-selenium icon indicating copy to clipboard operation
phpunit-selenium copied to clipboard

Selenium + phantomjs + code coverage: Unable to set Cookie: no URL has been loaded yet

Open nkovacs opened this issue 11 years ago • 12 comments

When PHPUnit_Extensions_Selenium2TestCase::runTest tries to set the PHPUNIT_SELENIUM_TEST_ID cookie, phantomjs/ghostdriver throws an exception, because there's no open url yet.

I can't open a url in setUp, because there's no session there yet, and it's too late by the time it gets to setUpPage If I put $this->url((string)$this->getBrowserUrl()); into prepareSession, after getting the session, it works.

nkovacs avatar Aug 07 '13 10:08 nkovacs

Apparently, this happens to anyone trying to use code coverage with selenium. I'm not sure when this started happening (probably some breakage in the webdriver API similar to what happend in v35 regarding sessions).

Briefly: the problem is that selenium server does not set cookies, unless you are currently on a page of the domain you want to set them to. So you have to first navigate to a page (say, the root of the webserver you're testing), then set cookies, then start the tests.

A stop-gap solution is to derive from the selenium testCase class and override prepareSession (so that you are somewhere when the cookie is set):

class MyTestCase extends PHPUnit_Extensions_Selenium2TestCase {

    public function prepareSession() {
        $res = parent::prepareSession();
        $this->url('/');
        return $res;
    }

}

I'm not sure what the definitive solution for this problem is. Some alternatives:

  • modify the selenium extension so that a given url is always opened before setting the cookie
  • modify the docs to point out the need to access some page when collecting code coverage data
  • modify the data gathering scripts so as to not rely on the cookie
  • something else?

matheusd avatar Aug 21 '13 14:08 matheusd

If you use my solution, you have to add the following line before the url() call:

$res->cookie()->remove('PHPUNIT_SELENIUM_TEST_ID');

If you don't do this and you have multiple tests per test file and reuse sessions, you'll have one file left for each test (because consecutive tests reuse the last cookie sent).

matheusd avatar Aug 21 '13 14:08 matheusd

Thanks for the investigation. We have some tests for coverage but due to the necessity of xdebug they are usually skipped in normal runs of the test suite (and cannot cover the whole cycle). Originally an url was opened in setUp() when setBrowserUrl() was called. When that call started just to configure a prefix for all URLs, this probably broke. Can you open a pull request where if coverage is being requested than that URL is loaded beforehand?

giorgiosironi avatar Aug 24 '13 08:08 giorgiosironi

I am also experiencing this issue, using Codeception+Selenium2+PhantomJS with code coverage. Codeception+Selenium2+Firefox with code coverage works fine however.

mtmacdonald avatar Sep 26 '13 14:09 mtmacdonald

matheusd's suggestions worked for me. This should be fixed in either the testcase base class or the documentation.

billschaller avatar Jan 24 '14 17:01 billschaller

PHPUnit(-selenium) 3.7.29 (1.3.3) + Selenium 2.39.0 + Firefox 26 (on Ubuntu) don't throw an Exception but silently ignore the cookie. I just spent an hour trying to figure out why I didn't get coverage ( >< )

@matheusd's solution works, but is a nasty workaround.

drjayvee avatar Jan 27 '14 15:01 drjayvee

@giorgiosironi @matheusd the change proposed in my PR (#289) works for me in a simple case. I haven't tested anything other than Firefox on Ubuntu using isolated sessions. Can somebody else test and review?

The reason why I don't get('/') is that for my application, that URL has side effects (it logs users out). The URL /phpunit_coverage.php is safe because it has no side-effects (since the cookie isn't set) and is still guaranteed to exist.

Can somebody else test and review this?

drjayvee avatar Jan 30 '14 14:01 drjayvee

@matheusd @nkovacs could you please take a look at my PR #289 and review?

drjayvee avatar Feb 03 '14 13:02 drjayvee

I'm also having this problem with Codeception 1.8.2 / WebDriver / PHPUnit 3.7.28 / PhantomJS 1.9.7.

thinkspill avatar Feb 04 '14 18:02 thinkspill

@drjayvee PR #289 seems fine on my projects. I was able to remove my workaround from my base classes and with your patch the selenium tests ran fine.

matheusd avatar Feb 04 '14 19:02 matheusd

Doesn't work on my project: If the phpunit_coverage.php is not available under the $browserUrl, then it doesn't work. The $coverageScriptUrl can be absolute, because it is called via file_get_contents, but the code from pull request #289 calls it via $this->url() what makes it prefixed by the $browserUrl. So it fails with absolute values for $coverageScriptUrl. At my project, it is not possible to make the script available unter the $browserUrl prefix, so i have to work around it now by adding the $browserUrl to it at PHPUnit_Extensions_SeleniumCommon_RemoteCoverage::get

julianseeger avatar Mar 09 '14 17:03 julianseeger

@julianseeger are you sure $this->url() prefixes $browserUrl? I haven't tested, but the code really looks like it will simply use the absolute URL:

class PHPUnit_Extensions_Selenium2TestCase_SessionCommand_Url
{
    public function __construct($url, $commandUrl, PHPUnit_Extensions_Selenium2TestCase_URL $baseUrl)
    {
        if ($url !== NULL) {
            $absoluteLocation = $baseUrl->jump($url)->getValue();
            $jsonParameters = array('url' => $absoluteLocation);
        } else {
            $jsonParameters = NULL;
        }
        parent::__construct($jsonParameters, $commandUrl);
    }
}

final class PHPUnit_Extensions_Selenium2TestCase_URL
{
    public function jump($newUrl)
    {
        if ($this->isAbsolute($newUrl)) {
            return new self($newUrl);
        } else {
            return $this->descend($newUrl);
        }
    }

    private function isAbsolute($urlValue)
    {
        return preg_match('/^(http|https):\/\//', $urlValue) > 0;
    }
}

Maybe your URL doesn't match the regex?

drjayvee avatar Mar 10 '14 08:03 drjayvee