如何在Behat中测试文件下载

时间:2014-07-24 09:42:24

标签: bdd behat mink

在此应用程序上开发了这个新的导出功能,我尝试使用Behat / Mink进行测试。 这里的问题是,当我点击导出链接时,页面上的数据会导出为CSV并保存在/ Downloads下,但我没有在页面上看到任何响应代码或任何内容。

有没有办法可以导出CSV并导航到/ Downloads文件夹来验证文件?

4 个答案:

答案 0 :(得分:3)

假设您使用的是Selenium驱动程序,您可以点击"在链接和$this->getSession()->wait(30)上直到下载完成,然后检查下载文件夹中的文件。

这将是最简单的解决方案。或者,您可以使用代理(如BrowserMob)来监视所有请求,然后验证响应代码。但仅此一点,这将是一条非常痛苦的道路。

检查文件下载的最简单方法是使用基本断言定义另一个步骤。

/**
 * @Then /^the file ".+" should be downloaded$/
 */
public function assertFileDownloaded($filename) 
{
    if (!file_exists('/download/dir/' . $filename)) {
        throw new Exception();
    }
}

当您下载具有相同名称的文件并且浏览器以不同的名称保存文件时,这可能会出现问题。作为解决方案,您可以添加@BeforeScenario挂钩以清除已知文件的列表。

另一个问题是下载目录本身 - 对于其他用户/机器可能会有所不同。要解决此问题,您可以将behat.yml中的下载目录作为参数传递给上下文构造函数,请阅读docs

但最好的方法是将配置传递给Selenium,指定下载目录,以确保它始终清晰,并确切地知道搜索的位置。我不确定如何做到这一点,但从quick googling来看似乎是可能的。

答案 1 :(得分:2)

查看此博客:https://www.jverdeyen.be/php/behat-file-downloads/

基本思路是复制当前会话并使用Guzzle执行请求。之后,您可以按照自己喜欢的方式查看回复。

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));
        }
    }
}

答案 2 :(得分:0)

使用所有Cookie修改iTryToDownload()函数很少:

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));
}
}

答案 3 :(得分:0)

在项目中,我们遇到的问题是我们有两台服务器:一台带有网络驱动程序和浏览器,另一台带有selenium hub。因此,我们决定使用curl请求来获取标头。所以我写了一个在步骤定义中调用的函数。下面你可以找到一个使用标准php函数的函数: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;
    }
}

如何看待我有令牌授权。如果您想了解应该使用哪些标题,则应下载文件手册并在浏览器的标签network

中查看请求和响应