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”选项。
我有一些功能测试在我从 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”选项。