Как я могу проверить Stripe.js, используя poltergeist и Capybara?

Я с ума сходил, пытаясь написать автоматизированный тест для моей учетной записи пользователя. Пользователям будет взиматься постоянная подписка через Stripe. Они вводят свои основные сведения (адрес электронной почты, пароль и т.д.) И данные своей кредитной карты в одной и той же форме, затем происходит следующий поток:

  • (На стороне клиента) stripe.js делает запрос AJAX для серверов Stripe, который (при условии, что все действительно) возвращает токен кредитной карты.
  • Мой javascript заполняет скрытый ввод в форме HTML с помощью токена кредитной карты и отправляет форму на мой сервер Rails.
  • (Теперь на стороне сервера): Я проверяю основные данные пользователя. Если они недействительны, верните (потому что нет смысла взимать их с помощью Stripe, если, например, их адрес электронной почты недействителен, поэтому они не могут создать учетную запись.)
  • Если они действительны, попытайтесь создать объект Stripe::Customer, добавьте правильную подписку и зарядите их, используя Stripe ruby ​​gem и т.д.

Все это прекрасно работает... за исключением того, что я не могу понять, как его протестировать. Шаг 4 тестирования достаточно прост, так как он имеет место на стороне сервера, поэтому я могу издеваться над вызовами Stripe с камнем, подобным VCR.

Шаг № 1 - это то, что мне неприятно. Я попытался проверить это, используя как puffing-billy, так и stripe-ruby-mock, но ничего не работает. Здесь мой собственный javascript (упрощенный):

    var stripeResponseHandler = function (status, response) {
      console.log("response handler called");
      if (response.error) {
        // show the errors on the form
      } else {
        // insert the token into the form so it gets submitted to the server
        $("#credit_card_token").val(response.id);

        // Now submit the form.
        $form.get(0).submit();
      }
    }


    $form.submit(function (event) {
      // Disable the submit button to prevent repeated clicks
      $submitBtn.prop("disabled", true);
      event.preventDefault();

      console.log("creating token...");
      Stripe.createToken(
        // Get the credit card details from the form
        // and input them here.
      }, stripeResponseHandler);

      // Prevent the form from submitting the normal way.
      return false;
    });

Чтобы повторить, все это отлично работает, когда я тестирую его вручную. Но мои автоматические тесты терпят неудачу:

 Failure/Error: expect{submit_form}.to change{User.count}.by(1)
   expected result to have changed by 1, but was changed by 0

Когда я пытаюсь использовать gem puffing-billy, он, похоже, сам кэширует stripe.js (который загружается с собственных серверов Stripe на js.stripe.com, не подается из моего собственного приложения, так как Stripe не поддерживает это.), но вызов, инициированный Stripe.createToken, не кэшируется. Фактически, когда я вхожу в журналы журналов Stripe Server, кажется, что вызов даже не был выполнен (или, по крайней мере, Stripe не получает его.)

Обратите внимание на те инструкции console.log в моем JS выше. Когда я запускаю свой тестовый пакет, строка "Создание токена..." печатается, но "обработчик ответа называется". не делает. Похоже, обработчик ответа никогда не называется.

Я забыл некоторые детали, потому что этот вопрос уже очень длинный, но может добавить больше по запросу. Что я здесь делаю неправильно? Как я могу проверить свою страницу регистрации?

ОБНОВЛЕНИЕ См. [мой комментарий к этой проблеме Github] на stripe-ruby-mock для получения дополнительной информации о том, что я пробовал и не смог.

Ответ 1

Если я правильно понимаю...

Capybara не будет знать ваши запросы ajax. Вы должны быть в состоянии заглушить запросы AJAX с Sinatra. Попросите его вернуть приборы так же, как и видеомагнитофон.

Вот статья об этом.

https://robots.thoughtbot.com/using-capybara-to-test-javascript-that-makes-http

Вам нужно загрузить приложение Sinatra в Capybara, а затем сопоставить URL-адреса в ваших вызовах ajax.

Что-то вроде:

class FakeContinousIntegration < Sinatra::Base
  def self.boot
    instance = new
    Capybara::Server.new(instance).tap { |server| server.boot }
  end

  get '/some/ajax'
    # send ajax back to capybara
  end
end

При загрузке сервера он вернет адрес и порт, которые вы можете записать в конфигурацию, которую может использовать ваш js.

@server = App.boot

Затем я использую адрес и порт для настройки приложения JS

def write_js_config
  config['api'] = "http://#{@server.host}:#{@server.port}"
  config.to_json
end

В spec_helper.rb отправьте конфигурацию в js, чтобы ваш script указывал на ваше приложение synatra. Шахта компилируется с помощью gulp. Так что я просто создаю конфигурацию в файл перед запуском тестов:

system('gulp build --env capybara')

Ответ 2

У меня были тесты, которые работали на ручном сбое в Capybara/poltergeist из-за таймаута. В моем случае решение должно было дождаться завершения всех запросов AJAX. Ссылка

Не уверен, что Stripe.js использует JQuery внутренне, попробуйте проверить условие, установленное stripeResponseHandler.

Ответ 3

В дополнение к трюку wait_for_ajax, похоже, вы вызываете expect до того, как ваша база данных была обновлена. Один из способов проверить, было бы добавить точку останова в вашем коде (binding.pry) и проверить, является ли это проблемой гонки или нет.

Кроме того, согласно документации Capybara, введение ожидания изменения пользовательского интерфейса делает его "ловко" ожиданием завершения вызовов ajax:

expect(page).not_to have_content('Enter credit card details')