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