Javascript 从 Selenium 切换到 Poltergeist 时测试中断

Javascript tests break when switching from Selenium to Poltergeist

我有一些功能测试在我从 Selenium 切换到 Poltergeist 后完全崩溃了。有趣的是,中断发生在我对第三方外部 API 调用 Mailgun 进行电子邮件验证的 AJAX 调用时。

有了 Selenium,所有测试都通过了。使用 Poltergeist,测试的行为方式与预期完全相反。换句话说,使用 Poltergeist,所有有效的电子邮件都被标记为无效,反之亦然。除了一些 Poltergeist 语法外,我的测试没有任何变化。

什么可能导致 Poltergeist 无法通过 Selenium 通过的 JS 测试?

编辑以包含示例代码:

功能测试:

scenario "with missing required parameters" do
  visit new_subscriber_path
  fill_in 'subscriber_firstname', with: ''
  fill_in 'subscriber_lastname', with: 'Appleseed'
  fill_in 'subscriber_account_attributes_email', with: 'john@yahoo.com'
  fill_in 'subscriber_account_attributes_password', with: 'test123'
  fill_in 'subscriber_account_attributes_password_confirmation', with: 'test123'
  click_button 'Next'

  page.should have_selector('.error', text: "can't be blank")
  expect(current_path).to eq subscribers_path
end

输出:(此测试通过了 Selenium,没有任何问题)。

1) Subscriber registering with missing required parameters
     Failure/Error: page.should have_selector('.error', text: "can't be blank")
       expected to find css ".error" with text "can't be blank" but there were no matches. Also found "", "", "This doesn't seem like a valid email address.", "", "", "", "", "", "", "", "", "", "", which matched the selector but not all filters.
     # ./spec/features/subscriber_registration_spec.rb:45:in `block (2 levels) in <top (required)>'

Mailgun 验证器:

$.fn.mailgun_validator = function(options) {
    return this.each(function() {
      run_validator($(this).val(), options);
    });
};

function run_validator(address_text, options) {
    // don't run validator without input
    if (!address_text) {
        return;
    }

    // length check
    if (address_text.length > 512) {
        error_message = 'Stream exceeds maxiumum allowable length of 512.';
        if (options && options.error) {
            options.error(error_message);
        }
        else {
            console.log(error_message);
        }
        return;
    }

    // validator is in progress
    if (options && options.in_progress) {
        options.in_progress();
    }

    // require api key
    if (options && options.api_key == undefined) {
        console.log('Please pass in api_key to mailgun_validator.')
    }

    var success = false;

    // make ajax call to get validation results
    $.ajax({
        type: "GET",
        url: 'https://api.mailgun.net/v2/address/validate?callback=?',
        data: { address: address_text, api_key: options.api_key },
        dataType: "jsonp",
        crossDomain: true,
        success: function(data, status_text) {
            success = true;
            if (options && options.success) {
                options.success(data);
            }
        },
        error: function(request, status_text, error) {
            success = true;
            error_message = 'Error occurred, unable to validate address.';

            if (options && options.error) {
                options.error(error_message);
            }
            else {
                console.log(error_message);
            }
        }
    });

    // timeout incase of some kind of internal server error
    setTimeout(function() {
        error_message = 'Error occurred, unable to validate address.';
        if (!success) {
            if (options && options.error) {
                options.error(error_message);
            }
            else {
                console.log(error_message);
            }
        }
    }, 30000);

}

Mailgun 验证器实现:

//= require mailgun_validator/mailgun_validator

var MailgunEmailValidator = function(emailTextField) {
  this.htmlElements = {
    emailField: $(emailTextField),
    form: $(emailTextField.form),
    errorField: $(emailTextField).siblings('.error')
  }
};

MailgunEmailValidator.PublicKey = 'pubkeyfoo';

MailgunEmailValidator.prototype.focusoutValidation = function () {
  var _this = this;
  $(_this.htmlElements.emailField).focusout(function() {
    _this.htmlElements.emailField.mailgun_validator({
      api_key: MailgunEmailValidator.PublicKey,
      success: function(data) {
        console.log(data)
        _this.isEmailValid = data.is_valid;
        if (_this.isEmailValid) {
          _this.showSuccess(data.did_you_mean);
        } else {
          _this.showError();
        }
      }
    });
  });
};

MailgunEmailValidator.prototype.prepopulatedFieldValidation = function() {
  var _this = this;
  if(_this.htmlElements.emailField[0].defaultValue) {
    _this.htmlElements.emailField.mailgun_validator({
      api_key: MailgunEmailValidator.PublicKey,
      success: function(data) {
        _this.isEmailValid = data.is_valid;
        if (_this.isEmailValid) {
          _this.showSuccess(data.did_you_mean);
        } else {
          _this.showError();
        }
      }
    });
  }
}

MailgunEmailValidator.prototype.showSuccess = function(didYouMean) {
  var _this = this,
      text = '';
  if(didYouMean) {
    text = '<font color="green">Address is valid. (Though did you mean ' + didYouMean + ')</font>';
  }
  if (_this.htmlElements.errorField.length == 0) {
    _this.htmlElements.errorField = $('<div>', {
      'class': 'error'
    });
  }
  _this.htmlElements.emailField.after(_this.htmlElements.errorField.html(text));
};

MailgunEmailValidator.prototype.showError = function() {
  var _this = this;
  if (_this.htmlElements.errorField.length == 0) {
    _this.htmlElements.errorField = $('<div>', {
      'class': 'error'
    });
  }
  _this.htmlElements.emailField.after(_this.htmlElements.errorField.text("This doesn't seem like a valid email address."));
};

MailgunEmailValidator.prototype.bindPreventInvalidEmailFormSubmissionEvent = function() {
  var _this = this;
  _this.htmlElements.form.on('submit', function(event) {
    if (!_this.isEmailValid) {
      event.preventDefault();
      _this.showError();
      _this.htmlElements.emailField[0].scrollIntoView();
    }
  });
};

MailgunEmailValidator.prototype.bindEvents = function() {
  this.bindPreventInvalidEmailFormSubmissionEvent();
};

MailgunEmailValidator.prototype.init = function() {
  this.focusoutValidation();
  this.prepopulatedFieldValidation();
  this.bindEvents();
};

MailgunEmailValidator.init = function() {
  this.emailFields = $('.mailgun');
  this.emailFields.each(function() {
    new MailgunEmailValidator(this).init();
  });
}

我为 poltergeist 添加的唯一配置是 spec_helper 中的以下配置:

Capybara.javascript_driver = :poltergeist

mailgun API 通过 https。 PhantomJS(由 poltergeist 使用)在 SSL 和配置方面可能存在一些问题。如果您在创建 poltergeist 驱动程序时为 phantomjs 指定了 ignore-ssl-errors 选项,那么它应该可以工作

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, phantomjs_options: ['--ignore-ssl-errors=true'])
end

您可能还想根据服务器设置指定“--ssl-protocol=TLSv1”选项。