mirror of https://github.com/docusealco/docuseal
				
				
				
			
						commit
						fa2d86b20a
					
				| @ -0,0 +1,17 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class SubmissionsFiltersController < ApplicationController | ||||
|   ALLOWED_NAMES = %w[ | ||||
|     author | ||||
|     completed_at | ||||
|     created_at | ||||
|   ].freeze | ||||
| 
 | ||||
|   skip_authorization_check | ||||
| 
 | ||||
|   def show | ||||
|     return head :not_found unless ALLOWED_NAMES.include?(params[:name]) | ||||
| 
 | ||||
|     render params[:name] | ||||
|   end | ||||
| end | ||||
| @ -0,0 +1,20 @@ | ||||
| export default class extends HTMLElement { | ||||
|   connectedCallback () { | ||||
|     this.button.addEventListener('click', () => { | ||||
|       this.fromInput.value = this.dataset.fromValue || '' | ||||
|       this.toInput.value = this.dataset.toValue || '' | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   get button () { | ||||
|     return this.querySelector('button') | ||||
|   } | ||||
| 
 | ||||
|   get fromInput () { | ||||
|     return document.getElementById(this.dataset.fromId) | ||||
|   } | ||||
| 
 | ||||
|   get toInput () { | ||||
|     return document.getElementById(this.dataset.toId) | ||||
|   } | ||||
| } | ||||
| After Width: | Height: | Size: 464 B | 
| After Width: | Height: | Size: 400 B | 
| After Width: | Height: | Size: 290 B | 
| @ -0,0 +1,50 @@ | ||||
| <% query_params = params.permit(:q, :status).merge(filter_params) %> | ||||
| <% if query_params[:completed_at_from].present? || query_params[:completed_at_to].present? %> | ||||
|   <div class="tooltip tooltip-bottom flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-34 border-neutral-700" data-tip="<%= t('completed_at') %>"> | ||||
|     <%= link_to submissions_filter_path('completed_at', query_params.merge(path: url_for, with_remove: true)), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 w-full pr-1 md:max-w-[140px]' do %> | ||||
|       <%= svg_icon('calendar_check', class: 'w-5 h-5 shrink-0') %> | ||||
|       <span class="flex flex-row md:flex-col font-normal text-left md:text-center md:text-xs"> | ||||
|         <% if query_params[:completed_at_from] == query_params[:completed_at_to] %> | ||||
|           <span><%= l(Date.parse(query_params[:completed_at_from]), locale: current_account.locale) %></span> | ||||
|         <% else %> | ||||
|           <span><%= query_params[:completed_at_from].present? ? l(Date.parse(query_params[:completed_at_from]), locale: current_account.locale) : '∞' %></span> | ||||
|           <span class="px-1 md:px-0 md:hidden">-</span> | ||||
|           <span><%= query_params[:completed_at_to].present? ? l(Date.parse(query_params[:completed_at_to]), locale: current_account.locale) : t('today') %></span> | ||||
|         <% end %> | ||||
|       </span> | ||||
|     <% end %> | ||||
|     <%= link_to url_for(params.to_unsafe_h.except(:completed_at_from, :completed_at_to)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> | ||||
|       <%= svg_icon('x', class: 'w-5 h-5') %> | ||||
|     <% end %> | ||||
|   </div> | ||||
| <% end %> | ||||
| <% if query_params[:created_at_from].present? || query_params[:created_at_to].present? %> | ||||
|   <div class="tooltip tooltip-bottom flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-34 border-neutral-700" data-tip="<%= t('created_at') %>"> | ||||
|     <%= link_to submissions_filter_path('created_at', query_params.merge(path: url_for, with_remove: true)), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 w-full pr-1 md:max-w-[140px]' do %> | ||||
|       <%= svg_icon('calendar', class: 'w-5 h-5 shrink-0') %> | ||||
|       <span class="flex flex-row md:flex-col font-normal text-left md:text-center md:text-xs"> | ||||
|         <% if query_params[:created_at_from] == query_params[:created_at_to] %> | ||||
|           <span><%= l(Date.parse(query_params[:created_at_from]), locale: current_account.locale) %></span> | ||||
|         <% else %> | ||||
|           <span><%= query_params[:created_at_from].present? ? l(Date.parse(query_params[:created_at_from]), locale: current_account.locale) : '∞' %></span> | ||||
|           <span class="px-1 md:px-0 md:hidden">-</span> | ||||
|           <span><%= query_params[:created_at_to].present? ? l(Date.parse(query_params[:created_at_to]), locale: current_account.locale) : t('today') %></span> | ||||
|         <% end %> | ||||
|       </span> | ||||
|     <% end %> | ||||
|     <%= link_to url_for(params.to_unsafe_h.except(:created_at_to, :created_at_from)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> | ||||
|       <%= svg_icon('x', class: 'w-5 h-5') %> | ||||
|     <% end %> | ||||
|   </div> | ||||
| <% end %> | ||||
| <% if params[:author].present? %> | ||||
|   <div class="tooltip tooltip-bottom flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-34 border-neutral-700" data-tip="<%= t('author') %>"> | ||||
|     <%= link_to submissions_filter_path('author', query_params.merge(path: url_for, with_remove: true)), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 w-full pr-1 md:max-w-[140px]' do %> | ||||
|       <%= svg_icon('user', class: 'w-5 h-5 shrink-0') %> | ||||
|       <span class="font-normal truncate"><%= current_account.users.accessible_by(current_ability).where(account: current_account).find_by(email: params[:author])&.full_name || 'NA' %></span> | ||||
|     <% end %> | ||||
|     <%= link_to url_for(params.to_unsafe_h.except(:author)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> | ||||
|       <%= svg_icon('x', class: 'w-5 h-5') %> | ||||
|     <% end %> | ||||
|   </div> | ||||
| <% end %> | ||||
| @ -0,0 +1,39 @@ | ||||
| <% current_time = Time.current.in_time_zone(current_account.timezone) %> | ||||
| <% week_start = TimeUtils.timezone_abbr(current_account.timezone, current_time).in?(TimeUtils::US_TIMEZONES) ? :sunday : :monday %> | ||||
| <div class="flex flex-wrap gap-2 mt-4 md:mt-2"> | ||||
|   <set-date-button data-from-value="<%= current_time.to_date %>" data-to-value="<%= current_time.to_date %>" data-from-id="date_from" data-to-id="date_to"> | ||||
|     <button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button"> | ||||
|       <%= t('today') %> | ||||
|     </button> | ||||
|   </set-date-button> | ||||
|   <set-date-button data-from-value="<%= (current_time - 1.day).to_date %>" data-to-value="<%= (current_time - 1.day).to_date %>" data-from-id="date_from" data-to-id="date_to"> | ||||
|     <button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button"> | ||||
|       <%= t('yesterday') %> | ||||
|     </button> | ||||
|   </set-date-button> | ||||
|   <set-date-button data-from-value="<%= current_time.beginning_of_week(week_start).to_date %>" data-to-value="<%= current_time.end_of_week(week_start).to_date %>" data-from-id="date_from" data-to-id="date_to"> | ||||
|     <button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button"> | ||||
|       <%= t('this_week') %> | ||||
|     </button> | ||||
|   </set-date-button> | ||||
|   <set-date-button data-from-value="<%= (current_time - 1.week).beginning_of_week(week_start).to_date %>" data-to-value="<%= (current_time - 1.week).end_of_week(week_start).to_date %>" data-from-id="date_from" data-to-id="date_to"> | ||||
|     <button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button"> | ||||
|       <%= t('last_week') %> | ||||
|     </button> | ||||
|   </set-date-button> | ||||
|   <set-date-button data-from-value="<%= current_time.beginning_of_month.to_date %>" data-to-value="<%= current_time.end_of_month.to_date %>" data-from-id="date_from" data-to-id="date_to"> | ||||
|     <button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button"> | ||||
|       <%= t('this_month') %> | ||||
|     </button> | ||||
|   </set-date-button> | ||||
|   <set-date-button data-from-value="<%= (current_time - 1.month).beginning_of_month.to_date %>" data-to-value="<%= (current_time - 1.month).end_of_month.to_date %>" data-from-id="date_from" data-to-id="date_to"> | ||||
|     <button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button"> | ||||
|       <%= t('last_month') %> | ||||
|     </button> | ||||
|   </set-date-button> | ||||
|   <set-date-button data-from-value="<%= current_time.beginning_of_year.to_date %>" data-to-value="<%= current_time.end_of_year.to_date %>" data-from-id="date_from" data-to-id="date_to"> | ||||
|     <button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button"> | ||||
|       <%= t('this_year') %> | ||||
|     </button> | ||||
|   </set-date-button> | ||||
| </div> | ||||
| @ -0,0 +1,27 @@ | ||||
| <% query_params = params.permit(:q, :status).merge(filter_params) %> | ||||
| <div class="dropdown dropdown-end"> | ||||
|   <label tabindex="0" class="cursor-pointer flex h-10 px-3 py-1 space-x-1 text-lg items-center justify-between border text-center text-neutral rounded-xl border-neutral-300 hover:border-neutral-700"> | ||||
|     <%= svg_icon('filter', class: 'w-5 h-5 flex-shrink-0 stroke-2') %> | ||||
|     <span class="<%= filter_params.present? ? 'md:hidden' : '' %>">Filter</span> | ||||
|   </label> | ||||
|   <ul tabindex="0" class="z-10 dropdown-content p-2 mt-2 shadow menu text-base bg-base-100 rounded-box min-w-[180px] text-right"> | ||||
|     <li class="flex"> | ||||
|       <%= link_to submissions_filter_path('completed_at', query_params.merge(path: url_for)), data: { turbo_frame: 'modal' } do %> | ||||
|         <%= svg_icon('calendar_check', class: 'w-5 h-5 flex-shrink-0 stroke-2') %> | ||||
|         <span><%= t('completed_at') %></span> | ||||
|       <% end %> | ||||
|     </li> | ||||
|     <li class="flex"> | ||||
|       <%= link_to submissions_filter_path('created_at', query_params.merge(path: url_for)), data: { turbo_frame: 'modal' } do %> | ||||
|         <%= svg_icon('calendar', class: 'w-5 h-5 flex-shrink-0 stroke-2') %> | ||||
|         <span><%= t('created_at') %></span> | ||||
|       <% end %> | ||||
|     </li> | ||||
|     <li class="flex"> | ||||
|       <%= link_to submissions_filter_path('author', query_params.merge(path: url_for)), data: { turbo_frame: 'modal' } do %> | ||||
|         <%= svg_icon('user', class: 'w-5 h-5 flex-shrink-0 stroke-2') %> | ||||
|         <span><%= t('author') %></span> | ||||
|       <% end %> | ||||
|     </li> | ||||
|   </ul> | ||||
| </div> | ||||
| @ -0,0 +1,18 @@ | ||||
| <%= render 'shared/turbo_modal', title: local_assigns[:title] do %> | ||||
|   <%= form_for '', url: params[:path], method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %> | ||||
|     <%= hidden_field_tag :status, params[:status] if params[:status].present? %> | ||||
|     <%= hidden_field_tag :q, params[:q] if params[:q].present? %> | ||||
|     <% local_assigns[:default_params].each do |key, value| %> | ||||
|       <%= hidden_field_tag(key, value) if value.present? %> | ||||
|     <% end %> | ||||
|     <%= yield %> | ||||
|     <div class="form-control mt-4"> | ||||
|       <%= f.button button_title(title: t('apply'), disabled_with: t('applying')), name: nil, class: 'base-button' %> | ||||
|     </div> | ||||
|     <% if params[:with_remove] %> | ||||
|       <div class="text-center w-full mt-4"> | ||||
|         <%= link_to t('remove_filter'), "#{params[:path]}?#{params.to_unsafe_h.slice(:q, :status).merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %> | ||||
|       </div> | ||||
|     <% end %> | ||||
|   <% end %> | ||||
| <% end %> | ||||
| @ -0,0 +1,7 @@ | ||||
| <%= render 'filter_modal', title: t('author'), default_params: params.permit(*(Submissions::Filter::ALLOWED_PARAMS - ['author'])) do %> | ||||
|   <div class="space-y-2"> | ||||
|     <div class="form-control mt-6"> | ||||
|       <%= select_tag :author, options_for_select(current_account.users.accessible_by(current_ability).where.not(role: :integration).where(account: current_account).map { |u| [u.full_name, u.email] }, params[:author].presence || current_user.email), required: true, class: 'base-select' %> | ||||
|     </div> | ||||
|   </div> | ||||
| <% end %> | ||||
| @ -0,0 +1,15 @@ | ||||
| <%= render 'filter_modal', title: t('completed_at'), default_params: params.permit(*(Submissions::Filter::ALLOWED_PARAMS - %w[completed_at_to completed_at_from])) do %> | ||||
|   <div class="space-y-3"> | ||||
|     <div class="flex flex-col md:flex-row gap-2"> | ||||
|       <div class="form-control w-full"> | ||||
|         <%= label_tag 'completed_at_from', t('from'), for: 'date_from', class: 'label text-sm' %> | ||||
|         <%= date_field_tag 'completed_at_from', params[:completed_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %> | ||||
|       </div> | ||||
|       <div class="form-control w-full"> | ||||
|         <%= label_tag 'completed_at_to', t('to'), for: 'date_to', class: 'label text-sm' %> | ||||
|         <%= date_field_tag 'completed_at_to', params[:completed_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %> | ||||
|       </div> | ||||
|     </div> | ||||
|     <%= render 'date_buttons' %> | ||||
|   </div> | ||||
| <% end %> | ||||
| @ -0,0 +1,15 @@ | ||||
| <%= render 'filter_modal', title: t('created_at'), default_params: params.permit(*(Submissions::Filter::ALLOWED_PARAMS - %w[created_at_to created_at_from])) do %> | ||||
|   <div class="space-y-3"> | ||||
|     <div class="flex flex-col md:flex-row gap-2"> | ||||
|       <div class="form-control w-full"> | ||||
|         <%= label_tag 'created_at_from', t('from'), for: 'date_from', class: 'label text-sm' %> | ||||
|         <%= date_field_tag 'created_at_from', params[:created_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %> | ||||
|       </div> | ||||
|       <div class="form-control w-full"> | ||||
|         <%= label_tag 'created_at_to', t('to'), for: 'date_to', class: 'label text-sm' %> | ||||
|         <%= date_field_tag 'created_at_to', params[:created_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %> | ||||
|       </div> | ||||
|     </div> | ||||
|     <%= render 'date_buttons' %> | ||||
|   </div> | ||||
| <% end %> | ||||
| @ -0,0 +1,64 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Submissions | ||||
|   module Filter | ||||
|     ALLOWED_PARAMS = %w[ | ||||
|       author | ||||
|       completed_at_from | ||||
|       completed_at_to | ||||
|       created_at_from | ||||
|       created_at_to | ||||
|     ].freeze | ||||
| 
 | ||||
|     DATE_PARAMS = %w[ | ||||
|       completed_at_from | ||||
|       completed_at_to | ||||
|       created_at_from | ||||
|       created_at_to | ||||
|     ].freeze | ||||
| 
 | ||||
|     module_function | ||||
| 
 | ||||
|     def call(submissions, current_user, params) | ||||
|       filters = normalize_filter_params(params, current_user) | ||||
| 
 | ||||
|       if filters[:author].present? | ||||
|         user = current_user.account.users.find_by(email: filters[:author]) | ||||
|         submissions = submissions.where(created_by_user_id: user&.id || -1) | ||||
|       end | ||||
| 
 | ||||
|       submissions = submissions.where(created_at: filters[:created_at_from]..) if filters[:created_at_from].present? | ||||
| 
 | ||||
|       if filters[:created_at_to].present? | ||||
|         submissions = submissions.where(created_at: ..filters[:created_at_to].end_of_day) | ||||
|       end | ||||
| 
 | ||||
|       if filters[:completed_at_from].present? || filters[:completed_at_to].present? | ||||
|         completed_arel = Submitter.arel_table[:completed_at].maximum | ||||
|         submissions = submissions.completed.joins(:submitters).group(:id) | ||||
| 
 | ||||
|         if filters[:completed_at_from].present? | ||||
|           submissions = submissions.having(completed_arel.gteq(filters[:completed_at_from])) | ||||
|         end | ||||
| 
 | ||||
|         if filters[:completed_at_to].present? | ||||
|           submissions = submissions.having(completed_arel.lteq(filters[:completed_at_to].end_of_day)) | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       submissions | ||||
|     end | ||||
| 
 | ||||
|     def normalize_filter_params(params, current_user) | ||||
|       tz = ActiveSupport::TimeZone[current_user.account.timezone] || Time.zone | ||||
| 
 | ||||
|       ALLOWED_PARAMS.each_with_object({}) do |key, acc| | ||||
|         next if params[key].blank? | ||||
| 
 | ||||
|         value = DATE_PARAMS.include?(key) ? tz.parse(params[key]) : params[key] | ||||
| 
 | ||||
|         acc[key.to_sym] = value | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
| After Width: | Height: | Size: 129 KiB | 
| @ -0,0 +1,34 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module SigningFormHelper | ||||
|   module_function | ||||
| 
 | ||||
|   def draw_canvas | ||||
|     page.find('canvas').click([], { x: 150, y: 100 }) | ||||
|     page.execute_script <<~JS | ||||
|       const canvas = document.getElementsByTagName('canvas')[0]; | ||||
|       const ctx = canvas.getContext('2d'); | ||||
| 
 | ||||
|       ctx.beginPath(); | ||||
|       ctx.moveTo(150, 100); | ||||
|       ctx.lineTo(450, 100); | ||||
|       ctx.stroke(); | ||||
| 
 | ||||
|       ctx.beginPath(); | ||||
|       ctx.moveTo(150, 100); | ||||
|       ctx.lineTo(150, 150); | ||||
|       ctx.stroke(); | ||||
|     JS | ||||
|     sleep 1 | ||||
|   end | ||||
| 
 | ||||
|   def field_value(submitter, field_name) | ||||
|     field = template_field(submitter.template, field_name) | ||||
| 
 | ||||
|     submitter.values[field['uuid']] | ||||
|   end | ||||
| 
 | ||||
|   def template_field(template, field_name) | ||||
|     template.fields.find { |f| f['name'] == field_name || f['title'] == field_name } || {} | ||||
|   end | ||||
| end | ||||
| @ -0,0 +1,598 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require 'rails_helper' | ||||
| 
 | ||||
| RSpec.describe 'Signing Form', type: :system do | ||||
|   let(:account) { create(:account) } | ||||
|   let(:author) { create(:user, account:) } | ||||
| 
 | ||||
|   context 'when the template form link is opened' do | ||||
|     let(:template) { create(:template, account:, author:, except_field_types: %w[phone payment stamp]) } | ||||
| 
 | ||||
|     before do | ||||
|       visit start_form_path(slug: template.slug) | ||||
|     end | ||||
| 
 | ||||
|     it 'shows the email step', type: :system do | ||||
|       expect(page).to have_content('You have been invited to submit a form') | ||||
|       expect(page).to have_content("Invited by #{account.name}") | ||||
|       expect(page).to have_field('Email', type: 'email') | ||||
|       expect(page).to have_button('Start') | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form' do | ||||
|       # Submit's email step | ||||
|       fill_in 'Email', with: 'john.dou@example.com' | ||||
|       click_button 'Start' | ||||
| 
 | ||||
|       # Text step | ||||
|       fill_in 'First Name', with: 'John' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Date step | ||||
|       fill_in 'Birthday', with: I18n.l(20.years.ago, format: '%Y-%m-%d') | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Checkbox step | ||||
|       check 'Do you agree?' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Radio step | ||||
|       choose 'Boy' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Signature step | ||||
|       draw_canvas | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Number step | ||||
|       fill_in 'House number', with: '123' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Multiple choice step | ||||
|       %w[Red Blue].each { |color| check color } | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Select step | ||||
|       select 'Male', from: 'Gender' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Initials step | ||||
|       draw_canvas | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Image step | ||||
|       find('#dropzone').click | ||||
|       find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-image.png')) | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # File step | ||||
|       find('#dropzone').click | ||||
|       find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-document.pdf')) | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Cell step | ||||
|       fill_in 'Cell code', with: '123' | ||||
|       click_on 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_button('Download') | ||||
|       expect(page).to have_content('Document has been signed!') | ||||
| 
 | ||||
|       submitter = template.submissions.last.submitters.last | ||||
| 
 | ||||
|       expect(submitter.email).to eq('john.dou@example.com') | ||||
|       expect(submitter.ip).to eq('127.0.0.1') | ||||
|       expect(submitter.ua).to be_present | ||||
|       expect(submitter.opened_at).to be_present | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(submitter.declined_at).to be_nil | ||||
| 
 | ||||
|       expect(field_value(submitter, 'First Name')).to eq 'John' | ||||
|       expect(field_value(submitter, 'Birthday')).to eq 20.years.ago.strftime('%Y-%m-%d') | ||||
|       expect(field_value(submitter, 'Do you agree?')).to be_truthy | ||||
|       expect(field_value(submitter, 'First child')).to eq 'Boy' | ||||
|       expect(field_value(submitter, 'Signature')).to be_present | ||||
|       expect(field_value(submitter, 'House number')).to eq 123 | ||||
|       expect(field_value(submitter, 'Colors')).to contain_exactly('Red', 'Blue') | ||||
|       expect(field_value(submitter, 'Gender')).to eq 'Male' | ||||
|       expect(field_value(submitter, 'Initials')).to be_present | ||||
|       expect(field_value(submitter, 'Avatar')).to be_present | ||||
|       expect(field_value(submitter, 'Attachment')).to be_present | ||||
|       expect(field_value(submitter, 'Cell code')).to eq '123' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the submitter form link is opened' do | ||||
|     let(:template) { create(:template, account:, author:, except_field_types: %w[phone payment stamp]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:, email: 'robin@example.com') | ||||
|     end | ||||
| 
 | ||||
|     before do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
|     end | ||||
| 
 | ||||
|     it 'complete the form' do | ||||
|       # Text step | ||||
|       fill_in 'First Name', with: 'John' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Date step | ||||
|       fill_in 'Birthday', with: I18n.l(20.years.ago, format: '%Y-%m-%d') | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Checkbox step | ||||
|       check 'Do you agree?' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Radio step | ||||
|       choose 'Boy' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Signature step | ||||
|       draw_canvas | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Number step | ||||
|       fill_in 'House number', with: '123' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Multiple choice step | ||||
|       %w[Red Blue].each { |color| check color } | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Select step | ||||
|       select 'Male', from: 'Gender' | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Initials step | ||||
|       draw_canvas | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Image step | ||||
|       find('#dropzone').click | ||||
|       find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-image.png')) | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # File step | ||||
|       find('#dropzone').click | ||||
|       find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-document.pdf')) | ||||
|       click_button 'next' | ||||
| 
 | ||||
|       # Cell step | ||||
|       fill_in 'Cell code', with: '123' | ||||
|       click_on 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_button('Download') | ||||
|       expect(page).to have_content('Document has been signed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.email).to eq 'robin@example.com' | ||||
|       expect(submitter.ip).to eq('127.0.0.1') | ||||
|       expect(submitter.ua).to be_present | ||||
|       expect(submitter.opened_at).to be_present | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(submitter.declined_at).to be_nil | ||||
| 
 | ||||
|       expect(field_value(submitter, 'First Name')).to eq 'John' | ||||
|       expect(field_value(submitter, 'Birthday')).to eq 20.years.ago.strftime('%Y-%m-%d') | ||||
|       expect(field_value(submitter, 'Do you agree?')).to be_truthy | ||||
|       expect(field_value(submitter, 'First child')).to eq 'Boy' | ||||
|       expect(field_value(submitter, 'Signature')).to be_present | ||||
|       expect(field_value(submitter, 'House number')).to eq 123 | ||||
|       expect(field_value(submitter, 'Colors')).to contain_exactly('Red', 'Blue') | ||||
|       expect(field_value(submitter, 'Gender')).to eq 'Male' | ||||
|       expect(field_value(submitter, 'Initials')).to be_present | ||||
|       expect(field_value(submitter, 'Avatar')).to be_present | ||||
|       expect(field_value(submitter, 'Attachment')).to be_present | ||||
|       expect(field_value(submitter, 'Cell code')).to eq '123' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the text step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[text]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the field is filled' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       input = find_field('First Name') | ||||
| 
 | ||||
|       expect(input[:required]).to be_truthy | ||||
|       expect(input[:placeholder]).to eq 'Type here...' | ||||
| 
 | ||||
|       fill_in 'First Name', with: 'Mary' | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'First Name')).to eq 'Mary' | ||||
|     end | ||||
| 
 | ||||
|     it 'toggle multiple text button' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       input = find_field('First Name') | ||||
| 
 | ||||
|       expect(input.tag_name).to eq('input') | ||||
| 
 | ||||
|       find(:css, 'div[data-tip="Toggle Multiline Text"]').click | ||||
| 
 | ||||
|       input = find_field('First Name') | ||||
| 
 | ||||
|       expect(input.tag_name).to eq('textarea') | ||||
|       expect(page).not_to have_selector(:css, 'div[data-tip="Toggle Multiline Text"]') | ||||
| 
 | ||||
|       fill_in 'First Name', with: 'Very long text' | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(field_value(submitter, 'First Name')).to eq 'Very long text' | ||||
|       expect(submitter.completed_at).to be_present | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the date step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[date]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the field is filled' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       input = find_field('Birthday') | ||||
| 
 | ||||
|       expect(input[:required]).to be_truthy | ||||
| 
 | ||||
|       fill_in 'Birthday', with: I18n.l(25.years.ago, format: '%Y-%m-%d') | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Birthday')).to eq 25.years.ago.strftime('%Y-%m-%d') | ||||
|     end | ||||
| 
 | ||||
|     it 'pre-fills the current date into the form field' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       input = find_field('Birthday') | ||||
| 
 | ||||
|       expect(input[:value]).to eq '' | ||||
| 
 | ||||
|       click_button 'Set Today' | ||||
| 
 | ||||
|       input = find_field('Birthday') | ||||
| 
 | ||||
|       expect(input[:value]).to eq Time.zone.now.strftime('%Y-%m-%d') | ||||
| 
 | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Birthday')).to eq Time.zone.now.strftime('%Y-%m-%d') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the checkbox step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[checkbox]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the checkbox is checked' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       check 'Do you agree?' | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Do you agree?')).to be true | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the radio step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[radio]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the checkbox is checked' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       %w[Girl Boy].map { |v| find_field(v) }.each { |input| expect(input[:required]).to be_truthy } | ||||
| 
 | ||||
|       choose 'Boy' | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'First child')).to eq 'Boy' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the signature step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[signature]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the canvas is drawn' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       find('#expand_form_button').click | ||||
|       draw_canvas | ||||
|       click_button 'Sign and Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Document has been signed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Signature')).to be_present | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the canvas is typed' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       find('#expand_form_button').click | ||||
|       click_link 'Type' | ||||
|       fill_in 'signature_text_input', with: 'John Doe' | ||||
|       click_button 'Sign and Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Document has been signed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Signature')).to be_present | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the number step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[number]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the field is filled' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       input = find_field('House number') | ||||
| 
 | ||||
|       expect(input[:required]).to be_truthy | ||||
|       expect(input[:placeholder]).to eq 'Type here...' | ||||
| 
 | ||||
|       fill_in 'House number', with: '4' | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'House number')).to eq 4 | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the multiple choice step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[multiple]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the multiple choice is checked' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       %w[Red Green].each { |color| check color } | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Colors')).to contain_exactly('Red', 'Green') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the select step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[select]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the multiple choice is checked' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       select 'Female', from: 'Gender' | ||||
| 
 | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Gender')).to eq 'Female' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the initials step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[initials]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the canvas is typed' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       find('#expand_form_button').click | ||||
|       fill_in 'initials_text_input', with: 'John Doe' | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Document has been signed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Initials')).to be_present | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the canvas is drawn' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       find('#expand_form_button').click | ||||
|       click_link 'Draw' | ||||
|       draw_canvas | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Document has been signed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Initials')).to be_present | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the initials is uploaded' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       find('#expand_form_button').click | ||||
|       find('span[data-tip="Click to upload"]').click | ||||
|       find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-image.png')) | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Document has been signed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Initials')).to be_present | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the image step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[image]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the image is uploaded' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       find('#expand_form_button').click | ||||
|       find('#dropzone').click | ||||
|       find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-image.png')) | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Avatar')).to be_present | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the file step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[file]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the file is uploaded' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       find('#expand_form_button').click | ||||
|       find('#dropzone').click | ||||
|       find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-document.pdf')) | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Attachment')).to be_present | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when the cells step' do | ||||
|     let(:template) { create(:template, account:, author:, only_field_types: %w[cells]) } | ||||
|     let(:submission) { create(:submission, template:) } | ||||
|     let(:submitter) do | ||||
|       create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form if the field is filled' do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|       input = find_field('Cell code') | ||||
| 
 | ||||
|       expect(input[:required]).to be_truthy | ||||
|       expect(input[:placeholder]).to eq 'Type here...' | ||||
| 
 | ||||
|       fill_in 'Cell code', with: '456' | ||||
|       click_button 'Complete' | ||||
| 
 | ||||
|       expect(page).to have_content('Form has been completed!') | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(field_value(submitter, 'Cell code')).to eq '456' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   it 'sends completed email' do | ||||
|     template = create(:template, account:, author:, only_field_types: %w[text signature]) | ||||
|     submission = create(:submission, template:) | ||||
|     submitter = create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:) | ||||
| 
 | ||||
|     visit submit_form_path(slug: submitter.slug) | ||||
| 
 | ||||
|     fill_in 'First Name', with: 'Adam' | ||||
|     click_on 'next' | ||||
|     click_link 'Type' | ||||
|     fill_in 'signature_text_input', with: 'Adam' | ||||
| 
 | ||||
|     expect do | ||||
|       click_on 'Sign and Complete' | ||||
|     end.to change(ProcessSubmitterCompletionJob.jobs, :size).by(1) | ||||
|   end | ||||
| end | ||||
| @ -1,87 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require 'rails_helper' | ||||
| 
 | ||||
| RSpec.describe 'Submit Form' do | ||||
|   let(:account) { create(:account) } | ||||
|   let(:user) { create(:user, account:) } | ||||
|   let(:template) { create(:template, account:, author: user) } | ||||
| 
 | ||||
|   before do | ||||
|     sign_in(user) | ||||
|   end | ||||
| 
 | ||||
|   context 'when initialized by shared link' do | ||||
|     before do | ||||
|       visit start_form_path(slug: template.slug) | ||||
|     end | ||||
| 
 | ||||
|     it 'shows start form page' do | ||||
|       expect(page).to have_content('You have been invited to submit a form') | ||||
|       expect(page).to have_content(template.name) | ||||
|       expect(page).to have_content("Invited by #{template.account.name}") | ||||
|     end | ||||
| 
 | ||||
|     it 'complete the form' do | ||||
|       fill_in 'Email', with: 'john.dou@example.com' | ||||
|       click_button 'Start' | ||||
| 
 | ||||
|       fill_in 'First Name', with: 'Adam' | ||||
|       click_on 'next' | ||||
|       click_on 'type_text_button' | ||||
|       fill_in 'signature_text_input', with: 'Adam' | ||||
| 
 | ||||
|       expect do | ||||
|         click_on 'Sign and Complete' | ||||
|       end.not_to(change(Submitter, :count)) | ||||
| 
 | ||||
|       submitter = Submitter.find_by(email: 'john.dou@example.com') | ||||
| 
 | ||||
|       expect(page).to have_button('Download') | ||||
|       expect(submitter.email).to eq('john.dou@example.com') | ||||
|       expect(submitter.ip).to eq('127.0.0.1') | ||||
|       expect(submitter.ua).to be_present | ||||
|       expect(submitter.opened_at).to be_present | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(submitter.values.values).to include('Adam') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when initialized by shared email address' do | ||||
|     let(:submission) { create(:submission, template:, created_by_user: user) } | ||||
|     let(:submitters) { template.submitters.map { |s| create(:submitter, submission:, uuid: s['uuid']) } } | ||||
|     let(:submitter) { submitters.first } | ||||
| 
 | ||||
|     before do | ||||
|       visit submit_form_path(slug: submitter.slug) | ||||
|     end | ||||
| 
 | ||||
|     it 'completes the form' do | ||||
|       fill_in 'First Name', with: 'Sally' | ||||
|       click_on 'next' | ||||
|       click_on 'type_text_button' | ||||
|       fill_in 'signature_text_input', with: 'Sally' | ||||
|       click_on 'Sign and Complete' | ||||
| 
 | ||||
|       submitter.reload | ||||
| 
 | ||||
|       expect(page).to have_button('Download') | ||||
|       expect(submitter.ip).to eq('127.0.0.1') | ||||
|       expect(submitter.ua).to be_present | ||||
|       expect(submitter.opened_at).to be_present | ||||
|       expect(submitter.completed_at).to be_present | ||||
|       expect(submitter.values.values).to include('Sally') | ||||
|     end | ||||
| 
 | ||||
|     it 'sends completed email' do | ||||
|       fill_in 'First Name', with: 'Adam' | ||||
|       click_on 'next' | ||||
|       click_on 'type_text_button' | ||||
|       fill_in 'signature_text_input', with: 'Adam' | ||||
| 
 | ||||
|       expect do | ||||
|         click_on 'Sign and Complete' | ||||
|       end.to change(ProcessSubmitterCompletionJob.jobs, :size).by(1) | ||||
|     end | ||||
|   end | ||||
| end | ||||
					Loading…
					
					
				
		Reference in new issue