diff --git a/app/assets/javascripts/forms.js.coffee b/app/assets/javascripts/forms.js.coffee index edf4c525f..3562335a4 100644 --- a/app/assets/javascripts/forms.js.coffee +++ b/app/assets/javascripts/forms.js.coffee @@ -23,8 +23,29 @@ App.Forms = false ) + synchronizeInputs: -> + $("[name='progress_bar[percentage]']").on + input: -> + $("[name='#{this.name}']").val($(this).val()) + + $("[name='progress_bar[percentage]'][type='range']").trigger("input") + + hideOrShowFieldsAfterSelection: -> + $("[name='progress_bar[kind]']").on + change: -> + title_field = $("[name^='progress_bar'][name$='[title]']").parent() + + if this.value == "primary" + title_field.hide() + else + title_field.show() + + $("[name='progress_bar[kind]']").change() + initialize: -> App.Forms.disableEnter() App.Forms.submitOnChange() App.Forms.toggleLink() + App.Forms.synchronizeInputs() + App.Forms.hideOrShowFieldsAfterSelection() false diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index f08d14fda..95f29e862 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -251,6 +251,13 @@ $sidebar-active: #f4fcd0; max-width: none; } + form { + + .input-group-label { + height: $line-height * 2; + } + } + .menu.simple { margin-bottom: $line-height / 2; diff --git a/app/controllers/admin/budget_investment_progress_bars_controller.rb b/app/controllers/admin/budget_investment_progress_bars_controller.rb new file mode 100644 index 000000000..bb4db0d79 --- /dev/null +++ b/app/controllers/admin/budget_investment_progress_bars_controller.rb @@ -0,0 +1,8 @@ +class Admin::BudgetInvestmentProgressBarsController < Admin::ProgressBarsController + + private + + def progressable + Budget::Investment.find(params[:budget_investment_id]) + end +end diff --git a/app/controllers/admin/legislation/progress_bars_controller.rb b/app/controllers/admin/legislation/progress_bars_controller.rb new file mode 100644 index 000000000..ba00d5e91 --- /dev/null +++ b/app/controllers/admin/legislation/progress_bars_controller.rb @@ -0,0 +1,14 @@ +class Admin::Legislation::ProgressBarsController < Admin::ProgressBarsController + include FeatureFlags + feature_flag :legislation + + def index + @process = progressable + end + + private + + def progressable + ::Legislation::Process.find(params[:process_id]) + end +end diff --git a/app/controllers/admin/progress_bars_controller.rb b/app/controllers/admin/progress_bars_controller.rb new file mode 100644 index 000000000..a9611b364 --- /dev/null +++ b/app/controllers/admin/progress_bars_controller.rb @@ -0,0 +1,69 @@ +class Admin::ProgressBarsController < Admin::BaseController + include Translatable + + before_action :load_progressable + before_action :load_progress_bar, only: [:edit, :update, :destroy] + helper_method :progress_bars_index + + def index + end + + def new + @progress_bar = @progressable.progress_bars.new + end + + def create + @progress_bar = @progressable.progress_bars.new(progress_bar_params) + if @progress_bar.save + redirect_to progress_bars_index, notice: t("admin.progress_bars.create.notice") + else + render :new + end + end + + def edit + end + + def update + if @progress_bar.update(progress_bar_params) + redirect_to progress_bars_index, notice: t('admin.progress_bars.update.notice') + else + render :edit + end + end + + def destroy + @progress_bar.destroy + redirect_to progress_bars_index, notice: t('admin.progress_bars.delete.notice') + end + + private + + def progress_bar_params + params.require(:progress_bar).permit(allowed_params) + end + + def allowed_params + [ + :kind, + :percentage, + translation_params(ProgressBar) + ] + end + + def load_progressable + @progressable = progressable + end + + def progressable + raise "This method must be implemented in subclass #{self.class.name}" + end + + def load_progress_bar + @progress_bar = progressable.progress_bars.find(params[:id]) + end + + def progress_bars_index + polymorphic_path([:admin, *resource_hierarchy_for(@progressable), ProgressBar.new]) + end +end diff --git a/app/controllers/admin/proposal_progress_bars_controller.rb b/app/controllers/admin/proposal_progress_bars_controller.rb new file mode 100644 index 000000000..9259acc4b --- /dev/null +++ b/app/controllers/admin/proposal_progress_bars_controller.rb @@ -0,0 +1,7 @@ +class Admin::ProposalProgressBarsController < Admin::ProgressBarsController + + private + def progressable + Proposal.find(params[:proposal_id]) + end +end diff --git a/app/models/concerns/milestoneable.rb b/app/models/concerns/milestoneable.rb index 2e961c613..7f58a77bb 100644 --- a/app/models/concerns/milestoneable.rb +++ b/app/models/concerns/milestoneable.rb @@ -5,5 +5,7 @@ module Milestoneable has_many :milestones, as: :milestoneable, dependent: :destroy scope :with_milestones, -> { joins(:milestones).distinct } + + has_many :progress_bars, as: :progressable end end diff --git a/app/models/progress_bar.rb b/app/models/progress_bar.rb new file mode 100644 index 000000000..7a7973723 --- /dev/null +++ b/app/models/progress_bar.rb @@ -0,0 +1,28 @@ +class ProgressBar < ActiveRecord::Base + self.inheritance_column = nil + RANGE = 0..100 + + enum kind: %i[primary secondary] + + belongs_to :progressable, polymorphic: true + + translates :title, touch: true + include Globalizable + + validates :progressable, presence: true + validates :kind, presence: true, + uniqueness: { + scope: [:progressable_type, :progressable_id], + conditions: -> { primary } + } + validates :percentage, presence: true, inclusion: RANGE, numericality: { only_integer: true } + + before_validation :assign_progress_bar_to_translations + validates_translation :title, presence: true, unless: :primary? + + private + + def assign_progress_bar_to_translations + translations.each { |translation| translation.globalized_model = self } + end +end diff --git a/app/models/progress_bar/translation.rb b/app/models/progress_bar/translation.rb new file mode 100644 index 000000000..d61f1d47b --- /dev/null +++ b/app/models/progress_bar/translation.rb @@ -0,0 +1,3 @@ +class ProgressBar::Translation < Globalize::ActiveRecord::Translation + delegate :primary?, to: :globalized_model +end diff --git a/app/views/admin/legislation/progress_bars/index.html.erb b/app/views/admin/legislation/progress_bars/index.html.erb new file mode 100644 index 000000000..b84717689 --- /dev/null +++ b/app/views/admin/legislation/progress_bars/index.html.erb @@ -0,0 +1,12 @@ +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{t("admin.menu.legislation")}" %> - + <%= "#{@process.title} - #{t("admin.progress_bars.index.title")}" %> +<% end %> + +<%= back_link_to admin_legislation_process_milestones_path(@progressable), + t("admin.legislation.processes.edit.back") %> + +

<%= @process.title %>

+ +<%= render "admin/legislation/processes/subnav", process: @process, active: "milestones" %> +<%= render "admin/progress_bars/progress_bars", progressable: @process %> diff --git a/app/views/admin/milestones/_milestones.html.erb b/app/views/admin/milestones/_milestones.html.erb index f2ef31216..1b5a4933b 100644 --- a/app/views/admin/milestones/_milestones.html.erb +++ b/app/views/admin/milestones/_milestones.html.erb @@ -1,4 +1,8 @@ -

<%= t("admin.milestones.index.milestone") %>

+

<%= t("admin.milestones.index.milestone") %>

+ +<%= link_to t("admin.progress_bars.manage"), + polymorphic_path([:admin, *resource_hierarchy_for(milestoneable.progress_bars.new)]), + class: "button hollow float-right" %> <% if milestoneable.milestones.any? %> diff --git a/app/views/admin/progress_bars/_form.html.erb b/app/views/admin/progress_bars/_form.html.erb new file mode 100644 index 000000000..cdc6af59e --- /dev/null +++ b/app/views/admin/progress_bars/_form.html.erb @@ -0,0 +1,31 @@ +<%= render "admin/shared/globalize_locales", resource: @progress_bar %> + +<%= translatable_form_for [:admin, *resource_hierarchy_for(@progress_bar)] do |f| %> + +
+ <%= f.enum_select :kind %> +
+ + <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_field :title %> +
+ <% end %> + + <% progress_options = { min: ProgressBar::RANGE.min, max: ProgressBar::RANGE.max, step: 1 } %> +
+ <%= f.text_field :percentage, { type: :range, + id: "percentage_range", + class: "column" }.merge(progress_options) %> +
+
+
+ <%= f.text_field :percentage, { type: :number, + label: false, + class: "input-group-field" }.merge(progress_options) %> + % +
+
+ + <%= f.submit nil, class: "button success" %> +<% end %> diff --git a/app/views/admin/progress_bars/_progress_bars.html.erb b/app/views/admin/progress_bars/_progress_bars.html.erb new file mode 100644 index 000000000..3715c2f35 --- /dev/null +++ b/app/views/admin/progress_bars/_progress_bars.html.erb @@ -0,0 +1,57 @@ +

<%= t("admin.progress_bars.index.title") %>

+ +<%= link_to t("admin.progress_bars.index.new_progress_bar"), + polymorphic_path( + [:admin, *resource_hierarchy_for(ProgressBar.new(progressable: progressable))], + action: :new + ), + class: "button float-right" %> + +<% if progressable.progress_bars.any? %> +
+ + + + + + + + + + + <% progressable.progress_bars.each do |progress_bar| %> + + + + + + + + <% end %> + +
<%= t("admin.progress_bars.index.table_id") %><%= t("admin.progress_bars.index.table_kind") %><%= t("admin.progress_bars.index.table_title") %><%= t("admin.progress_bars.index.table_percentage") %><%= t("admin.actions.actions") %>
+ <%= progress_bar.id %> + <%= ProgressBar.human_attribute_name("kind.#{progress_bar.kind}") %> + <% if progress_bar.title.present? %> + <%= progress_bar.title %> + <% else %> + <%= t("admin.progress_bars.index.primary") %> + <% end %> + + <%= number_to_percentage(progress_bar.percentage, strip_insignificant_zeros: true) %> + + <%= link_to t("admin.actions.edit"), + polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)], + action: :edit), + class: "button hollow" %> + + <%= link_to t("admin.actions.delete"), + polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)]), + method: :delete, + class: "button hollow alert" %> +
+<% else %> +
+ <%= t("admin.progress_bars.index.no_progress_bars") %> +
+<% end %> diff --git a/app/views/admin/progress_bars/edit.html.erb b/app/views/admin/progress_bars/edit.html.erb new file mode 100644 index 000000000..21dd27d9a --- /dev/null +++ b/app/views/admin/progress_bars/edit.html.erb @@ -0,0 +1,15 @@ +<% if @progress_bar.primary? %> + <% bar_title = t("admin.progress_bars.edit.title.primary") %> +<% else %> + <% bar_title = t("admin.progress_bars.edit.title.secondary", title: @progress_bar.title) %> +<% end %> + +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{bar_title}" %> +<% end %> + +<%= back_link_to progress_bars_index %> + +

<%= bar_title %>

+ +<%= render "form" %> diff --git a/app/views/admin/progress_bars/index.html.erb b/app/views/admin/progress_bars/index.html.erb new file mode 100644 index 000000000..bcac8d7a4 --- /dev/null +++ b/app/views/admin/progress_bars/index.html.erb @@ -0,0 +1,9 @@ +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{t("admin.progress_bars.index.title")}" %> +<% end %> + +<%= back_link_to polymorphic_path([:admin, *resource_hierarchy_for(@progressable)]) %> + +
+ +<%= render "admin/progress_bars/progress_bars", progressable: @progressable %> diff --git a/app/views/admin/progress_bars/new.html.erb b/app/views/admin/progress_bars/new.html.erb new file mode 100644 index 000000000..8c379ac3a --- /dev/null +++ b/app/views/admin/progress_bars/new.html.erb @@ -0,0 +1,9 @@ +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{t("admin.progress_bars.new.creating")}" %> +<% end %> + +<%= back_link_to progress_bars_index %> + +

<%= t("admin.progress_bars.new.creating") %>

+ +<%= render "form" %> diff --git a/config/initializers/foundation_rails_helper.rb b/config/initializers/foundation_rails_helper.rb index ff5ae4618..3e121f0d9 100644 --- a/config/initializers/foundation_rails_helper.rb +++ b/config/initializers/foundation_rails_helper.rb @@ -5,5 +5,13 @@ module FoundationRailsHelper super(attribute, opts) end end + + def enum_select(attribute, options = {}, html_options = {}) + choices = object.class.send(attribute.to_s.pluralize).keys.map do |name| + [object.class.human_attribute_name("#{attribute}.#{name}"), name] + end + + select attribute, choices, options, html_options + end end end diff --git a/config/initializers/routes_hierarchy.rb b/config/initializers/routes_hierarchy.rb index 0a712f923..06a7acc74 100644 --- a/config/initializers/routes_hierarchy.rb +++ b/config/initializers/routes_hierarchy.rb @@ -9,6 +9,8 @@ module ActionDispatch::Routing::UrlFor [resource.budget, resource] when "Milestone" [*resource_hierarchy_for(resource.milestoneable), resource] + when "ProgressBar" + [*resource_hierarchy_for(resource.progressable), resource] when "Legislation::Annotation" [resource.draft_version.process, resource.draft_version, resource] when "Legislation::Proposal", "Legislation::Question", "Legislation::DraftVersion" diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index aab700334..90e726039 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -16,6 +16,9 @@ en: milestone/status: one: "Milestone Status" other: "Milestone Statuses" + progress_bar: + one: "Progress bar" + other: "Progress bars" comment: one: "Comment" other: "Comments" @@ -136,6 +139,13 @@ en: milestone/status: name: "Name" description: "Description (optional)" + progress_bar: + kind: "Type" + title: "Title" + percentage: "Current progress" + progress_bar/kind: + primary: "Primary" + secondary: "Secondary" budget/heading: name: "Heading name" price: "Price" diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 7033fefbf..a86f8a315 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -332,6 +332,29 @@ en: notice: Milestone status created successfully delete: notice: Milestone status deleted successfully + progress_bars: + manage: "Manage progress bars" + index: + title: "Progress bars" + no_progress_bars: "There are no progress bars" + new_progress_bar: "Create new progress bar" + primary: "Primary progress bar" + table_id: "ID" + table_kind: "Type" + table_title: "Title" + table_percentage: "Current progress" + new: + creating: "Create progress bar" + edit: + title: + primary: "Edit primary progress bar" + secondary: "Edit progress bar %{title}" + create: + notice: "Progress bar created successfully!" + update: + notice: "Progress bar updated successfully" + delete: + notice: "Progress bar deleted successfully" comments: index: filter: Filter diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 2c0b210a0..45cfa15b0 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -16,6 +16,9 @@ es: milestone/status: one: "Estado de seguimiento" other: "Estados de seguimiento" + progress_bar: + one: "Barra de progreso" + other: "Barras de progreso" comment: one: "Comentario" other: "Comentarios" @@ -136,6 +139,13 @@ es: milestone/status: name: "Nombre" description: "Descripción (opcional)" + progress_bar: + kind: "Tipo" + title: "Título" + percentage: "Progreso" + progress_bar/kind: + primary: "Principal" + secondary: "Secundaria" budget/heading: name: "Nombre de la partida" price: "Cantidad" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 0075225c7..d33d91211 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -332,6 +332,30 @@ es: notice: Estado de seguimiento creado correctamente delete: notice: Estado de seguimiento eliminado correctamente + progress_bars: + manage: "Gestionar barras de progreso" + index: + title: "Barras de progreso" + no_progress_bars: "No hay barras de progreso" + new_progress_bar: "Crear nueva barra de progreso" + primary: "Barra de progreso principal" + table_id: "ID" + table_kind: "Tipo" + table_title: "Título" + table_percentage: "Progreso" + new: + creating: "Crear barra de progreso" + edit: + title: + primary: "Editar barra de progreso principal" + secondary: "Editar barra de progreso %{title}" + create: + notice: "¡Barra de progreso creada con éxito!" + update: + notice: "Barra de progreso actualizada" + delete: + notice: "Barra de progreso eliminada correctamente" + comments: index: filter: Filtro diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 270a5061c..52740e9d6 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -31,6 +31,7 @@ namespace :admin do resources :proposals, only: [:index, :show] do resources :milestones, controller: "proposal_milestones" + resources :progress_bars, except: :show, controller: "proposal_progress_bars" end resources :hidden_proposals, only: :index do @@ -67,6 +68,7 @@ namespace :admin do resources :budget_investments, only: [:index, :show, :edit, :update] do resources :milestones, controller: 'budget_investment_milestones' + resources :progress_bars, except: :show, controller: "budget_investment_progress_bars" member { patch :toggle_selection } end @@ -203,6 +205,7 @@ namespace :admin do end resources :draft_versions resources :milestones + resources :progress_bars, except: :show resource :homepage, only: [:edit, :update] end end diff --git a/db/migrate/20190103132925_create_progress_bars.rb b/db/migrate/20190103132925_create_progress_bars.rb new file mode 100644 index 000000000..899a4819f --- /dev/null +++ b/db/migrate/20190103132925_create_progress_bars.rb @@ -0,0 +1,23 @@ +class CreateProgressBars < ActiveRecord::Migration + def change + create_table :progress_bars do |t| + t.integer :kind + t.integer :percentage + t.references :progressable, polymorphic: true + + t.timestamps null: false + end + + reversible do |change| + change.up do + ProgressBar.create_translation_table!({ + title: :string + }) + end + + change.down do + ProgressBar.drop_translation_table! + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index e3241fd8d..0d5ed3d1a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20181206153510) do +ActiveRecord::Schema.define(version: 20190103132925) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1088,6 +1088,26 @@ ActiveRecord::Schema.define(version: 20181206153510) do add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree + create_table "progress_bar_translations", force: :cascade do |t| + t.integer "progress_bar_id", null: false + t.string "locale", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "title" + end + + add_index "progress_bar_translations", ["locale"], name: "index_progress_bar_translations_on_locale", using: :btree + add_index "progress_bar_translations", ["progress_bar_id"], name: "index_progress_bar_translations_on_progress_bar_id", using: :btree + + create_table "progress_bars", force: :cascade do |t| + t.integer "kind" + t.integer "percentage" + t.integer "progressable_id" + t.string "progressable_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "proposal_notifications", force: :cascade do |t| t.string "title" t.text "body" diff --git a/spec/factories/budgets.rb b/spec/factories/budgets.rb index da7b0f1b9..e741eb683 100644 --- a/spec/factories/budgets.rb +++ b/spec/factories/budgets.rb @@ -195,19 +195,6 @@ FactoryBot.define do reason "unfeasible" end - factory :milestone_status, class: 'Milestone::Status' do - sequence(:name) { |n| "Milestone status #{n} name" } - sequence(:description) { |n| "Milestone status #{n} description" } - end - - factory :milestone, class: 'Milestone' do - association :milestoneable, factory: :budget_investment - association :status, factory: :milestone_status - sequence(:title) { |n| "Budget investment milestone #{n} title" } - description 'Milestone description' - publication_date { Date.current } - end - factory :valuator_group, class: ValuatorGroup do sequence(:name) { |n| "Valuator Group #{n}" } end diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb new file mode 100644 index 000000000..0e4071d15 --- /dev/null +++ b/spec/factories/milestones.rb @@ -0,0 +1,25 @@ +FactoryBot.define do + factory :milestone_status, class: "Milestone::Status" do + sequence(:name) { |n| "Milestone status #{n} name" } + sequence(:description) { |n| "Milestone status #{n} description" } + end + + factory :milestone do + association :milestoneable, factory: :budget_investment + association :status, factory: :milestone_status + sequence(:title) { |n| "Milestone #{n} title" } + description "Milestone description" + publication_date { Date.current } + end + + factory :progress_bar do + association :progressable, factory: :budget_investment + percentage { rand(0..100) } + kind :primary + + trait(:secondary) do + kind :secondary + sequence(:title) { |n| "Progress bar #{n} title" } + end + end +end diff --git a/spec/models/progress_bar_spec.rb b/spec/models/progress_bar_spec.rb new file mode 100644 index 000000000..46b0ce08b --- /dev/null +++ b/spec/models/progress_bar_spec.rb @@ -0,0 +1,97 @@ +require "rails_helper" + +describe ProgressBar do + let(:progress_bar) { build(:progress_bar) } + + it "is valid" do + expect(progress_bar).to be_valid + end + + it "is valid without a title" do + progress_bar.title = nil + + expect(progress_bar).to be_valid + end + + it "is not valid with a custom type" do + expect { progress_bar.kind = "terciary" }.to raise_exception(ArgumentError) + end + + it "is not valid without a percentage" do + progress_bar.percentage = nil + + expect(progress_bar).not_to be_valid + end + + it "is not valid with a non-numeric percentage" do + progress_bar.percentage = "High" + + expect(progress_bar).not_to be_valid + end + + it "is not valid with a non-integer percentage" do + progress_bar.percentage = 22.83 + + expect(progress_bar).not_to be_valid + end + + it "is not valid with a negative percentage" do + progress_bar.percentage = -1 + + expect(progress_bar).not_to be_valid + end + + it "is not valid with a percentage bigger than 100" do + progress_bar.percentage = 101 + + expect(progress_bar).not_to be_valid + end + + it "is valid with an integer percentage within the limits" do + progress_bar.percentage = 0 + + expect(progress_bar).to be_valid + + progress_bar.percentage = 100 + + expect(progress_bar).to be_valid + + progress_bar.percentage = 83 + + expect(progress_bar).to be_valid + end + + it "is not valid without a progressable" do + progress_bar.progressable = nil + + expect(progress_bar).not_to be_valid + end + + it "cannot have another primary progress bar for the same progressable" do + progress_bar.save + duplicate = build(:progress_bar, progressable: progress_bar.progressable) + + expect(duplicate).not_to be_valid + end + + describe "secondary progress bar" do + let(:progress_bar) { build(:progress_bar, :secondary) } + + it "is valid" do + expect(progress_bar).to be_valid + end + + it "is invalid without a title" do + progress_bar.title = nil + + expect(progress_bar).not_to be_valid + end + + it "can have another secondary progress bar for the same progressable" do + progress_bar.save + duplicate = build(:progress_bar, progressable: progress_bar.progressable) + + expect(duplicate).to be_valid + end + end +end diff --git a/spec/shared/features/admin_milestoneable.rb b/spec/shared/features/admin_milestoneable.rb index 17f43a012..c12fd7624 100644 --- a/spec/shared/features/admin_milestoneable.rb +++ b/spec/shared/features/admin_milestoneable.rb @@ -1,4 +1,5 @@ shared_examples "admin_milestoneable" do |factory_name, path_name| + it_behaves_like "progressable", factory_name, path_name feature "Admin milestones" do let!(:milestoneable) { create(factory_name) } diff --git a/spec/shared/features/progressable.rb b/spec/shared/features/progressable.rb new file mode 100644 index 000000000..b28c383c6 --- /dev/null +++ b/spec/shared/features/progressable.rb @@ -0,0 +1,115 @@ +shared_examples "progressable" do |factory_name, path_name| + let!(:progressable) { create(factory_name) } + + feature "Manage progress bars" do + let(:progressable_path) { send(path_name, *resource_hierarchy_for(progressable)) } + + let(:path) do + polymorphic_path([:admin, *resource_hierarchy_for(progressable.progress_bars.new)]) + end + + context "Index" do + scenario "Link to index path" do + create(:progress_bar, :secondary, progressable: progressable, + title: "Reading documents", + percentage: 20) + + visit progressable_path + click_link "Manage progress bars" + + expect(page).to have_content "Reading documents" + end + + scenario "No progress bars" do + visit path + + expect(page).to have_content("There are no progress bars") + end + end + + context "New" do + scenario "Primary progress bar", :js do + visit path + click_link "Create new progress bar" + + select "Primary", from: "Type" + + expect(page).not_to have_field "Title" + + fill_in "Current progress", with: 43 + click_button "Create Progress bar" + + expect(page).to have_content "Progress bar created successfully" + expect(page).to have_content "43%" + expect(page).to have_content "Primary" + expect(page).to have_content "Primary progress bar" + end + + scenario "Secondary progress bar", :js do + visit path + click_link "Create new progress bar" + + select "Secondary", from: "Type" + fill_in "Current progress", with: 36 + fill_in "Title", with: "Plant trees" + click_button "Create Progress bar" + + expect(page).to have_content "Progress bar created successfully" + expect(page).to have_content "36%" + expect(page).to have_content "Secondary" + expect(page).to have_content "Plant trees" + end + end + + context "Edit" do + scenario "Primary progress bar", :js do + bar = create(:progress_bar, progressable: progressable) + + visit path + within("#progress_bar_#{bar.id}") { click_link "Edit" } + + expect(page).to have_field "Current progress" + expect(page).not_to have_field "Title" + + fill_in "Current progress", with: 44 + click_button "Update Progress bar" + + expect(page).to have_content "Progress bar updated successfully" + + within("#progress_bar_#{bar.id}") do + expect(page).to have_content "44%" + end + end + + scenario "Secondary progress bar", :js do + bar = create(:progress_bar, :secondary, progressable: progressable) + + visit path + within("#progress_bar_#{bar.id}") { click_link "Edit" } + + fill_in "Current progress", with: 76 + fill_in "Title", with: "Updated title" + click_button "Update Progress bar" + + expect(page).to have_content "Progress bar updated successfully" + + within("#progress_bar_#{bar.id}") do + expect(page).to have_content "76%" + expect(page).to have_content "Updated title" + end + end + end + + context "Delete" do + scenario "Remove progress bar" do + bar = create(:progress_bar, progressable: progressable, percentage: 34) + + visit path + within("#progress_bar_#{bar.id}") { click_link "Delete" } + + expect(page).to have_content "Progress bar deleted successfully" + expect(page).not_to have_content "34%" + end + end + end +end