Как проверить загрузку файла в Behat

В этом приложении разработана новая функция экспорта, и я пытаюсь протестировать ее с помощью Behat/Mink. Проблема здесь в том, что когда я нажимаю на ссылку экспорта, данные на странице экспортируются в CSV и сохраняются в папке / Downloads, но я не вижу никакого кода ответа или чего-либо на странице.

Есть ли способ экспортировать CSV и перейти в папку / Downloads, чтобы проверить файл?


person vijay pujar    schedule 24.07.2014    source источник
comment
какое-либо оправдание для отрицательного голоса ?? это абсолютная шутка, не так ли.. на самом деле глупо..   -  person vijay pujar    schedule 19.08.2014


Ответы (4)


Предполагая, что вы используете драйвер 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 в качестве аргумента конструктору контекста, прочитайте документы для этого.

Но лучшим подходом было бы передать конфигурацию Selenium, указав каталог загрузки, чтобы убедиться, что он всегда понятен, и вы точно знаете, где искать. Я не уверен, как это сделать, но из быстрое гугление кажется возможным.

person Ian Bytchek    schedule 24.07.2014
comment
Привет Ян, как проверить папку загрузки. Я использую безголовый браузер (phantomJS) - person vijay pujar; 25.07.2014
comment
Я обновил ответ. Я не думаю, что вы сможете сделать это без настоящего браузера. Я бы предположил, что переход по ссылке с использованием безголового браузера просто вернет содержимое файла, хотя я могу ошибаться — никогда не пробовал этого. Вы можете использовать более одного сеанса с разными драйверами. Проверьте, является ли содержимое страницы после перехода по ссылке вашим CSV (тогда загрузка работает), или настройте разные сеансы и сделайте это правильно. - person Ian Bytchek; 25.07.2014

Загляните в этот блог: 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));
        }
    }
}
person thijsai    schedule 25.01.2015
comment
Большое спасибо за ваш ответ tscheepers. Я попробую это в ближайшее время. - person vijay pujar; 27.01.2015
comment
какой драйвер вы используете? Я помню, как где-то читал, что коды состояния не поддерживаются с помощью драйвера PhanomJS. - person vijay pujar; 17.06.2015

Немного модифицированная функция iTryToDownload() с использованием всех файлов cookie:

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));
}
}
person maks9889    schedule 10.07.2015

В проекте у нас есть проблема, что у нас есть два сервера: один с веб-драйверами и браузерами, а второй с селеновым хабом. В результате мы решили использовать 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

person Reedlee    schedule 21.09.2017