There is this new Export functionality developed on this application and I'm trying to test it using Behat/Mink. The issue here is when I click on the export link, the data on the page gets exported in to a CSV and gets saved under /Downloads but I don't see any response code or anything on the page.
Is there a way I can export the CSV and navigate to the /Downloads folder to verify the file?
Assuming you are using the Selenium driver you could "click" on the link and $this->getSession()->wait(30)
until the download is finished and then check the Downloads folder for the file.
That would be the simplest solution. Alternatively you can use a proxy, like BrowserMob, to watch all requests and then verify the response code. But that would be a really painful path for that alone.
The simplest way to check that the file is downloaded would be to define another step with a basic assertion.
/**
* @Then /^the file ".+" should be downloaded$/
*/
public function assertFileDownloaded($filename)
{
if (!file_exists('/download/dir/' . $filename)) {
throw new Exception();
}
}
This might be problematic in situations when you download a file with the same name and the browser saves it under a different name. As a solution you can add a @BeforeScenario
hook to clear the list of the know files.
Another issue would be the download dir itself – it might be different for other users / machines. To fix that you could pass the download dir in your behat.yml
as a argument to the context constructor, read the docs for that.
But the best approach would be to pass the configuration to the Selenium specifying the download dir to ensure it's always clear and you know exactly where to search. I am not certain how to do that, but from the quick googling it seems to be possible.
Checkout this blog: https://www.jverdeyen.be/php/behat-file-downloads/
The basic idea is to copy the current session and do the request with Guzzle. After that you can check the response any way you like.
class FeatureContext extends \Behat\Behat\Context\BehatContext {
/**
* @When /^I try to download "([^"]*)"$/
*/
public function iTryToDownload($url)
{
$cookies = $this->getSession()->getDriver()->getWebDriverSession()->getCookie('PHPSESSID');
$cookie = new \Guzzle\Plugin\Cookie\Cookie();
$cookie->setName($cookies[0]['name']);
$cookie->setValue($cookies[0]['value']);
$cookie->setDomain($cookies[0]['domain']);
$jar = new \Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar();
$jar->add($cookie);
$client = new \Guzzle\Http\Client($this->getSession()->getCurrentUrl());
$client->addSubscriber(new \Guzzle\Plugin\Cookie\CookiePlugin($jar));
$request = $client->get($url);
$this->response = $request->send();
}
/**
* @Then /^I should see response status code "([^"]*)"$/
*/
public function iShouldSeeResponseStatusCode($statusCode)
{
$responseStatusCode = $this->response->getStatusCode();
if (!$responseStatusCode == intval($statusCode)) {
throw new \Exception(sprintf("Did not see response status code %s, but %s.", $statusCode, $responseStatusCode));
}
}
/**
* @Then /^I should see in the header "([^"]*)":"([^"]*)"$/
*/
public function iShouldSeeInTheHeader($header, $value)
{
$headers = $this->response->getHeaders();
if ($headers->get($header) != $value) {
throw new \Exception(sprintf("Did not see %s with value %s.", $header, $value));
}
}
}
Little modified iTryToDownload() function with using all cookies:
public function iTryToDownload($link) {
$elt = $this->getSession()->getPage()->findLink($link);
if($elt) {
$value = $elt->getAttribute('href');
$driver = $this->getSession()->getDriver();
if ($driver instanceof \Behat\Mink\Driver\Selenium2Driver) {
$ds = $driver->getWebDriverSession();
$cookies = $ds->getAllCookies();
} else {
throw new \InvalidArgumentException('Not Selenium2Driver');
}
$jar = new \Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar();
for ($i = 0; $i < count($cookies); $i++) {
$cookie = new \Guzzle\Plugin\Cookie\Cookie();
$cookie->setName($cookies[$i]['name']);
$cookie->setValue($cookies[$i]['value']);
$cookie->setDomain($cookies[$i]['domain']);
$jar->add($cookie);
}
$client = new \Guzzle\Http\Client($this->getSession()->getCurrentUrl());
$client->addSubscriber(new \Guzzle\Plugin\Cookie\CookiePlugin($jar));
$request = $client->get($value);
$this->response = $request->send();
} else {
throw new \InvalidArgumentException(sprintf('Could not evaluate: "%s"', $link));
}
}
In project we have problem that we have two servers: one with web drivers and browsers and second with selenium hub. As result we decide to use curl request for fetching headers. So I wrote function which would called in step definition. Below you can find a function which use a standard php functions: curl_init()
/**
* @param $request_url
* @param $userToken
* @return bool
* @throws Exception
*/
private function makeCurlRequestForDownloadCSV($request_url, $userToken)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$headers = [
'Content-Type: application/json',
"Authorization: Bearer {$userToken}"
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$output = curl_exec($ch);
$info = curl_getinfo($ch);
$output .= "\n" . curl_error($ch);
curl_close($ch);
if ($output === false || $info['http_code'] != 200 || $info['content_type'] != "text/csv; charset=UTF-8") {
$output = "No cURL data returned for $request_url [" . $info['http_code'] . "]";
throw new Exception($output);
} else {
return true;
}
}
How you can see I have authorization by token. If you want to understand what headers you should use you should download file manual and look request and response in browser's tab network
来源:https://stackoverflow.com/questions/24930276/how-to-test-file-download-in-behat