Как я могу проверить только часть URL-адреса, к которому я перенаправлен (используя assert_redirected_to)?

В функциональном тесте моего приложения Rails я хочу проверить, куда я перенаправлен. Ожидаемый URL указывает на внешний ресурс (это означает, что он не является частью моего приложения).

URL-адрес выглядит следующим образом: https://my.url.com/foo?bar1=xyz&bar2=123

К сожалению, я не могу предсказать параметры, потому что они генерируются внешним ресурсом. *
Однако остальная часть URL-адреса всегда остается прежней: https://my.url.com/foo

Я обычно использую assert_redirected_to для такого теста, но это ожидает весь URL, включая параметры.

Может ли кто-нибудь подумать о другом способе проверки этого перенаправления, но проверить только первую часть URL-адреса без параметров?

(URL-адрес не находится в assigns Hash)

* (я делаю вызов API для приложения, ответы с URL которого я перенаправляю)

Ответ 1

Команды запроса http, такие как post, get и т.д., создают переменную экземпляра под названием @response, когда они вызывают *. @response сам содержит метод с именем redirect_url, в котором хранится URL, на который вы перенаправлены (в случае, если вы действительно перенаправлены).

Для этого я могу просто использовать обычный assert_match для сравнения регулярного выражения с @response.redirect_url:

post :my_action_to_test
assert_response :redirect
assert_match /https:\/\/my.url.com\/foo/, @response.redirect_url

* (на самом деле эти http-методы просто используют частный метод process, который создает переменную @response).

Ответ 2

Две быстрые мысли об этом:

1) Если ваш функциональный тест действительно подключается к внешнему приложению, почему бы просто не получить параметры из него, как обычно, и проверить правильность перенаправления?

2) Если ваш функциональный тест фактически не подключается к внешнему приложению, вы все равно его подделываете, поэтому я бы просто пропустил тестирование URL-адреса переадресации и просто проверил перенаправление с помощью assert_response: redirect. Или создайте макет, который возвращает URL-адрес для перенаправления, как если бы это было внешнее приложение, но делайте это так, чтобы вы могли получить из него парамы.

Тем не менее, не увлекайтесь испытаниями, которые, по вашему мнению, вы должны учитывать каждый возможный сценарий.

Ответ 3

Как насчет этого? Он обертывает assert_redirected_to, чтобы разрешить Regexp в качестве первого аргумента. Это не сработает, если вы попытаетесь сопоставить Regexp с Hash - только a String. Для этого потребуется немного больше работы.

ActionController::TestCase.class_eval do

  old_assert_redirected_to = method(:assert_redirected_to)

  define_method(:assert_redirected_to) do |*args|
    if args.[0].kind_of?(Regexp)
      assert_response(:redirect, args[1])
      assert args[0] === @response.redirected_to
    else
      old_assert_redirected_to.bind(self).call(*args)
    end
  end

end

Ответ 4

Я использую следующий метод, чтобы игнорировать любые параметры строки запроса. Он основан на официальной реализации assert_redirected_to

# ignores any query string params eg. notice or alert messages for flash
def custom_assert_redirected_to(path)
  assert_response :redirect

  if path === Regexp
    url = path
  else
    url = ActionController::Redirecting._compute_redirect_to_location(@request, path)
  end

  assert_equal url, @response.location.split("?").first
end