diff --git a/public/assets/form/form.js b/public/assets/form/form.js
index ef4dda770..54615edc6 100644
--- a/public/assets/form/form.js
+++ b/public/assets/form/form.js
@@ -33,6 +33,7 @@ $(function() {
name: 'email',
tag: 'input',
type: 'email',
+ required: true,
placeholder: 'Your Email',
defaultValue: function () {return User.email;},
},
@@ -40,6 +41,7 @@ $(function() {
display: 'Message',
name: 'body',
tag: 'textarea',
+ required: true,
placeholder: 'Your Message...',
defaultValue: '',
rows: 7,
@@ -76,6 +78,8 @@ $(function() {
name: 'name',
tag: 'input',
type: 'text',
+ id: 'zammad-form-name',
+ required: true,
placeholder: 'Your Name',
defaultValue: '',
},
@@ -84,6 +88,8 @@ $(function() {
name: 'email',
tag: 'input',
type: 'email',
+ id: 'zammad-form-email',
+ required: true,
placeholder: 'Your Email',
defaultValue: '',
},
@@ -91,6 +97,8 @@ $(function() {
display: 'Message',
name: 'body',
tag: 'textarea',
+ id: 'zammad-form-body',
+ required: true,
placeholder: 'Your Message...',
defaultValue: '',
rows: 7,
@@ -396,14 +404,15 @@ $(function() {
$form.append('
' + this.options.messageTitle + '
')
}
$.each(this.options.attributes, function(index, value) {
- var item = $('');
+ var valueId = _this.options.modal ? value.id + '-modal' : value.id + '-inline'
+ var item = $('');
var defaultValue = (typeof value.defaultValue === 'function') ? value.defaultValue() : value.defaultValue;
for (var i=0; i < (value.repeat ? value.repeat : 1); i++) {
if (value.tag == 'input') {
- item.append('')
+ item.append('')
}
else if (value.tag == 'textarea') {
- item.append('')
+ item.append('')
}
}
$form.append(item)
diff --git a/script/build/test_slice_tests.sh b/script/build/test_slice_tests.sh
index 64acc5367..916b32565 100755
--- a/script/build/test_slice_tests.sh
+++ b/script/build/test_slice_tests.sh
@@ -59,7 +59,6 @@ if [ "$LEVEL" == '1' ]; then
rm test/browser/customer_ticket_create_fields_test.rb
rm test/browser/customer_ticket_create_test.rb
rm test/browser/first_steps_test.rb
- # test/browser/form_test.rb
rm test/browser/integration_test.rb
rm test/browser/keyboard_shortcuts_test.rb
# test/browser/maintenance_app_version_test.rb
@@ -135,7 +134,6 @@ elif [ "$LEVEL" == '2' ]; then
rm test/browser/customer_ticket_create_fields_test.rb
rm test/browser/customer_ticket_create_test.rb
rm test/browser/first_steps_test.rb
- rm test/browser/form_test.rb
rm test/browser/integration_test.rb
rm test/browser/keyboard_shortcuts_test.rb
rm test/browser/maintenance_app_version_test.rb
@@ -211,7 +209,6 @@ elif [ "$LEVEL" == '3' ]; then
rm test/browser/customer_ticket_create_fields_test.rb
rm test/browser/customer_ticket_create_test.rb
rm test/browser/first_steps_test.rb
- rm test/browser/form_test.rb
rm test/browser/integration_test.rb
rm test/browser/keyboard_shortcuts_test.rb
rm test/browser/maintenance_app_version_test.rb
@@ -287,7 +284,6 @@ elif [ "$LEVEL" == '4' ]; then
# test/browser/customer_ticket_create_fields_test.rb
# test/browser/customer_ticket_create_test.rb
rm test/browser/first_steps_test.rb
- rm test/browser/form_test.rb
rm test/browser/integration_test.rb
rm test/browser/keyboard_shortcuts_test.rb
rm test/browser/maintenance_app_version_test.rb
@@ -362,7 +358,6 @@ elif [ "$LEVEL" == '5' ]; then
rm test/browser/customer_ticket_create_fields_test.rb
rm test/browser/customer_ticket_create_test.rb
rm test/browser/first_steps_test.rb
- rm test/browser/form_test.rb
rm test/browser/integration_test.rb
rm test/browser/keyboard_shortcuts_test.rb
rm test/browser/maintenance_app_version_test.rb
@@ -440,7 +435,6 @@ elif [ "$LEVEL" == '6' ]; then
rm test/browser/customer_ticket_create_fields_test.rb
rm test/browser/customer_ticket_create_test.rb
# test/browser/first_steps_test.rb
- rm test/browser/form_test.rb
# test/browser/integration_test.rb
# test/browser/keyboard_shortcuts_test.rb
rm test/browser/maintenance_app_version_test.rb
diff --git a/spec/support/capybara/browser_test_helper.rb b/spec/support/capybara/browser_test_helper.rb
index 4ba739c04..241662591 100644
--- a/spec/support/capybara/browser_test_helper.rb
+++ b/spec/support/capybara/browser_test_helper.rb
@@ -68,6 +68,12 @@ module BrowserTestHelper
# await_empty_ajax_queue
#
def await_empty_ajax_queue
+ # page.evaluate_script silently discards any present alerts, which is not desired.
+ begin
+ return if page.driver.browser.switch_to.alert
+ rescue Selenium::WebDriver::Error::NoSuchAlertError # rubocop:disable Lint/SuppressedException
+ end
+
wait(5, interval: 0.1).until_constant do
page.evaluate_script('App.Ajax.queue().length').zero?
end
diff --git a/spec/support/custom_matchers/system/form_matchers/have_validation_message.rb b/spec/support/custom_matchers/system/form_matchers/have_validation_message.rb
new file mode 100644
index 000000000..bf016bec7
--- /dev/null
+++ b/spec/support/custom_matchers/system/form_matchers/have_validation_message.rb
@@ -0,0 +1,53 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+module FormMatchers
+ module HaveValidationMessage
+ extend RSpec::Matchers::DSL
+
+ matcher :have_validation_message_for do |field|
+
+ match { check_field(field) && form_field_found? && validation_message_found? }
+ description { 'have a non empty validation message' }
+
+ failure_message do
+ if form_field_found? && !validation_message_found?
+ %(expected to find the field '#{field}' with a validation message, found #{field} with no validation message)
+ else
+ %(expected to find the field '#{field}' with a validation message)
+ end
+ end
+
+ failure_message_when_negated do
+ if form_field_found? && validation_message_found?
+ %(expected not to find the field '#{field}' with a validation message, but did)
+ else
+ %(expected not to find a validation message)
+ end
+ end
+
+ def validation_message_found?
+ actual
+ .find(field)
+ .native
+ .attribute('validationMessage')
+ .present?
+ end
+
+ def form_field_found?
+ actual.has_css?(field)
+ end
+
+ def field
+ @check_field
+ end
+
+ def check_field(field)
+ @check_field ||= field
+ end
+ end
+ end
+end
+
+RSpec.configure do |config|
+ config.include FormMatchers::HaveValidationMessage, type: :system
+end
diff --git a/spec/system/form_spec.rb b/spec/system/form_spec.rb
new file mode 100644
index 000000000..f98732249
--- /dev/null
+++ b/spec/system/form_spec.rb
@@ -0,0 +1,175 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+require 'rails_helper'
+
+RSpec.describe 'Form', type: :system, authenticated_as: true do
+
+ shared_examples 'validating form fields' do
+ it 'validate name input' do
+ within form_context do
+ fill_in 'Email', with: 'discard@znuny.com'
+ fill_in 'Message', with: 'message here'
+ click_on 'Submit'
+
+ expect(page).to have_validation_message_for(name_input)
+ end
+ end
+
+ it 'validate email input' do
+ within form_context do
+ fill_in 'Name', with: 'some sender'
+ fill_in 'Message', with: 'message here'
+ click_on 'Submit'
+
+ expect(page).to have_validation_message_for(email_input)
+ end
+ end
+
+ it 'validate message input' do
+ within form_context do
+ fill_in 'Name', with: 'some sender'
+ fill_in 'Email', with: 'discard@znuny.com'
+ click_on 'Submit'
+
+ expect(page).to have_validation_message_for(body_input)
+ end
+ end
+
+ it 'validate email format' do
+ within form_context do
+ fill_in 'Name', with: 'some sender'
+ fill_in 'Email', with: 'invalidformat'
+ click_on 'Submit'
+
+ expect(page).to have_validation_message_for(email_input)
+ end
+ end
+
+ it 'validate email field with non existing domain space' do
+ within form_context do
+ fill_in 'Name', with: 'some sender'
+ fill_in 'Message', with: 'message here'
+ fill_in 'Email', with: 'somebody@notexistinginanydomainspacealsonothere.nowhere'
+ sleep 10
+ click_on 'Submit'
+
+ expect(page).to have_selector('.has-error [name=email]').and have_no_selector('button[type="submit"][disabled]')
+ end
+ end
+ end
+
+ shared_examples 'submitting valid form fields' do
+ it 'submits form filled slowly succesfully' do
+ within form_context do
+ fill_in 'Name', with: 'some sender'
+ fill_in 'Message', with: 'message here'
+ fill_in 'Email', with: 'discard@znuny.com'
+ sleep 10
+ click_on 'Submit'
+
+ expect(page).to have_text('Thank you for your inquiry')
+ end
+ end
+
+ it 'fails to submit form filled too fast' do
+ within form_context do
+ fill_in 'Name', with: 'some sender'
+ fill_in 'Message', with: 'message here'
+ fill_in 'Email', with: 'discard@znuny.com'
+ click_on 'Submit'
+ accept_alert('Sorry, you look like an robot!')
+ end
+ end
+ end
+
+ context 'with in-app form' do
+ let(:path) { 'channels/form' }
+ let(:feedback_modal_button) { '.js-formBtn' }
+
+ context 'when form is inline' do
+ let(:form_context) { '.js-formInline form.zammad-form' }
+ let(:name_input) { '#zammad-form-name-inline' }
+ let(:body_input) { '#zammad-form-body-inline' }
+ let(:email_input) { '#zammad-form-email-inline' }
+
+ before do
+ visit path
+ uncheck 'Start modal dialog for form.', { allow_label_click: true }
+ end
+
+ it_behaves_like 'validating form fields'
+ end
+
+ context 'when form is modal' do
+ let(:form_context) { '.js-zammad-form-modal-body form.zammad-form' }
+ let(:name_input) { '#zammad-form-name-modal' }
+ let(:body_input) { '#zammad-form-body-modal' }
+ let(:email_input) { '#zammad-form-email-modal' }
+
+ before do
+ visit path
+ find(feedback_modal_button).click
+ end
+
+ it_behaves_like 'validating form fields'
+ end
+
+ it 'shows an inline form' do
+ visit path
+ uncheck 'Start modal dialog for form.', { allow_label_click: true }
+ expect(page).to have_selector('.js-formInline').and have_no_selector('.js-formInline.hide')
+ end
+ end
+
+ context 'with external form' do
+ let(:path) { '/assets/form/form.html' }
+ let(:feedback_modal_button) { '#feedback-form-modal' }
+ let(:form_inline_selector) { '#feedback-form-inline form.zammad-form' }
+
+ context 'when feature is enabled' do
+ before do
+ visit 'channels/form'
+ check 'form_ticket_create', { allow_label_click: true }
+ end
+
+ context 'when form is inline' do
+ let(:form_context) { form_inline_selector }
+ let(:name_input) { '#zammad-form-name-inline' }
+ let(:body_input) { '#zammad-form-body-inline' }
+ let(:email_input) { '#zammad-form-email-inline' }
+
+ before { visit path }
+
+ it_behaves_like 'validating form fields'
+ it_behaves_like 'submitting valid form fields'
+ end
+
+ context 'when form is modal' do
+ let(:form_context) { '.js-zammad-form-modal-body form.zammad-form' }
+ let(:name_input) { '#zammad-form-name-modal' }
+ let(:body_input) { '#zammad-form-body-modal' }
+ let(:email_input) { '#zammad-form-email-modal' }
+
+ before do
+ visit path
+ find(feedback_modal_button).click
+ end
+
+ it_behaves_like 'validating form fields'
+ it_behaves_like 'submitting valid form fields'
+ end
+ end
+
+ context 'when feature is disabled' do
+ before do
+ visit 'channels/form'
+ uncheck 'form_ticket_create', { allow_label_click: true }
+ visit path
+ end
+
+ it 'fails to load form' do
+ expect(page).to have_text('Faild to load form config, feature is disabled')
+ end
+ end
+ end
+end
diff --git a/test/browser/form_test.rb b/test/browser/form_test.rb
deleted file mode 100644
index 22f3be877..000000000
--- a/test/browser/form_test.rb
+++ /dev/null
@@ -1,353 +0,0 @@
-# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
-
-require 'browser_test_helper'
-
-class FormTest < TestCase
-
- def test_basic
- agent = browser_instance
- login(
- browser: agent,
- username: 'master@example.com',
- password: 'test',
- url: browser_url,
- )
- tasks_close_all(
- browser: agent,
- )
-
- # disable form
- click(
- browser: agent,
- css: 'a[href="#manage"]',
- )
- click(
- browser: agent,
- css: '.content.active a[href="#channels/form"]',
- )
- switch(
- browser: agent,
- css: '.content.active .js-formSetting',
- type: 'off',
- )
-
- # admin preview test
- sleep 1
- click(
- browser: agent,
- css: '.content.active .js-formBtn',
- )
-
- sleep 10
- set(
- browser: agent,
- css: 'body div.zammad-form-modal [name="name"]',
- value: 'some sender',
- )
- set(
- browser: agent,
- css: 'body div.zammad-form-modal [name="body"]',
- value: '',
- )
- click(
- browser: agent,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: agent,
- css: 'body div.zammad-form-modal .has-error [name="body"]',
- )
- watch_for_disappear(
- browser: agent,
- css: 'body div.zammad-form-modal button[type="submit"][disabled]',
- )
- set(
- browser: agent,
- css: 'body div.zammad-form-modal [name="body"]',
- value: 'new body',
- )
- set(
- browser: agent,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'somebody@notexistinginanydomainspacealsonothere.nowhere',
- )
- click(
- browser: agent,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: agent,
- css: 'body div.zammad-form-modal .has-error [name="email"]',
- )
- watch_for_disappear(
- browser: agent,
- css: 'body div.zammad-form-modal button[type="submit"][disabled]',
- )
- set(
- browser: agent,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'discard@znuny.com',
- )
- click(
- browser: agent,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: agent,
- css: 'body div.zammad-form-modal',
- value: 'Thank you for your inquiry',
- )
- # click on backgroud (not on thank you dialog)
- element = agent.find_elements({ css: 'body div.zammad-form-modal' })[0]
- agent.action.move_to(element, 200, 200).perform
- agent.action.click.perform
-
- customer = browser_instance
- location(
- browser: customer,
- url: "#{browser_url}/assets/form/form.html",
- )
- watch_for(
- browser: customer,
- css: '.js-logDisplay',
- value: 'Faild to load form config, feature is disabled',
- )
- switch(
- browser: agent,
- css: '.content.active .js-formSetting',
- type: 'on',
- )
-
- reload(
- browser: customer,
- )
- sleep 4
- match_not(
- browser: customer,
- css: '.js-logDisplay',
- value: 'Faild to load form config, feature is disabled',
- )
-
- exists_not(
- browser: customer,
- css: 'body div.zammad-form-modal',
- )
-
- # modal dialog
- click(
- browser: customer,
- css: '#feedback-form-modal',
- )
- watch_for(
- browser: customer,
- css: 'body div.zammad-form-modal',
- )
-
- # fill form valid data - but too fast
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="name"]',
- value: 'some name',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'discard@znuny.com',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="body"]',
- value: "some text\nnew line",
- )
- click(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"]',
- expect_alert: true,
- )
-
- sleep 10
-
- # fill form invalid data - within correct time
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="name"]',
- value: 'some name',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'invalid_email',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="body"]',
- value: "some text\nnew line",
- )
- click(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- sleep 10
- exists(
- browser: customer,
- css: 'body div.zammad-form-modal',
- )
-
- # fill form valid data
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'discard@znuny.com',
- )
- click(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: customer,
- css: 'body div.zammad-form-modal',
- value: 'Thank you for your inquiry',
- )
-
- # click on backgroud (not on thank you dialog)
- element = customer.find_elements({ css: 'body div.zammad-form-modal' })[0]
- customer.action.move_to(element, 200, 200).perform
- customer.action.click.perform
-
- sleep 1
- exists_not(
- browser: customer,
- css: 'body div.zammad-form-modal',
- )
-
- # fill form invalid data - within correct time
- click(
- browser: customer,
- css: '#feedback-form-modal',
- )
- sleep 10
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="name"]',
- value: '',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'discard@znuny.com',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="body"]',
- value: "some text\nnew line",
- )
- click(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: customer,
- css: 'body div.zammad-form-modal .has-error [name="name"]',
- )
- watch_for_disappear(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"][disabled]',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="name"]',
- value: 'some sender',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="body"]',
- value: '',
- )
- click(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: customer,
- css: 'body div.zammad-form-modal .has-error [name="body"]',
- )
- watch_for_disappear(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"][disabled]',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="body"]',
- value: 'new body',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'somebody@notexistinginanydomainspacealsonothere.nowhere',
- )
- click(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: customer,
- css: 'body div.zammad-form-modal .has-error [name="email"]',
- )
- watch_for_disappear(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"][disabled]',
- )
- set(
- browser: customer,
- css: 'body div.zammad-form-modal [name="email"]',
- value: 'discard@znuny.com',
- )
- click(
- browser: customer,
- css: 'body div.zammad-form-modal button[type="submit"]',
- )
- watch_for(
- browser: customer,
- css: 'body div.zammad-form-modal',
- value: 'Thank you for your inquiry',
- )
-
- # click on backgroud (not on thank you dialog)
- element = customer.find_elements({ css: 'body div.zammad-form-modal' })[0]
- customer.action.move_to(element, 200, 200).perform
- customer.action.click.perform
-
- sleep 1
- exists_not(
- browser: customer,
- css: 'body div.zammad-form-modal',
- )
-
- # inline form
- set(
- browser: customer,
- css: '.zammad-form [name="name"]',
- value: 'Some Name',
- )
- set(
- browser: customer,
- css: '.zammad-form [name="email"]',
- value: 'discard@znuny.com',
- )
- set(
- browser: customer,
- css: '.zammad-form [name="body"]',
- value: 'some text',
- )
- click(
- browser: customer,
- css: '.zammad-form button[type="submit"]',
- )
- watch_for(
- browser: customer,
- css: '.zammad-form',
- value: 'Thank you for your inquiry',
- )
- end
-
-end