- <%= t("welcome.debates.title") %>
- <%= t("welcome.debates.description") %>
-
- <%= t("welcome.proposal.title") %>
- <%= t("welcome.proposal.description") %>
-
<%= t("welcome.debates.title") %>
+<%= t("welcome.debates.description") %>
+<%= t("welcome.proposal.title") %>
+<%= t("welcome.proposal.description") %>
+<%= t("welcome.decide.title") %>
+<%= t("welcome.decide.description") %>
+<%= t("welcome.do.title") %>
+<%= t("welcome.do.description") %>
+
- <%= t("welcome.decide.title") %>
- <%= t("welcome.decide.description") %>
-
- <%= t("welcome.do.title") %>
- <%= t("welcome.do.description") %>
-
#{Faker::Lorem.paragraphs.join('
')}
" open_at = rand(2.months.ago..2.months.from_now) + answers = Faker::Lorem.words((2..4).to_a.sample).map { |answer| answer.capitalize } question = Poll::Question.create!(author: author, title: Faker::Lorem.sentence(3).truncate(60), - description: description, - valid_answers: Faker::Lorem.words((2..7).to_a.sample).join(', '), + valid_answers: answers.join(', '), poll: poll) + answers.each do |answer| + Poll::Question::Answer.create!(question: question, title: answer, description: Faker::ChuckNorris.fact) + end end puts " ✅" diff --git a/db/migrate/20170627113331_create_images.rb b/db/migrate/20170627113331_create_images.rb new file mode 100644 index 000000000..66567845a --- /dev/null +++ b/db/migrate/20170627113331_create_images.rb @@ -0,0 +1,14 @@ +class CreateImages < ActiveRecord::Migration + def up + create_table :images do |t| + t.references :imageable, polymorphic: true, index: true + t.string :title, limit: 80 + t.timestamps null: false + end + add_attachment :images, :attachment + end + + def down + remove_attachment :images, :attachment + end +end diff --git a/db/migrate/20170805132736_create_map_locations.rb b/db/migrate/20170805132736_create_map_locations.rb new file mode 100644 index 000000000..a75820d54 --- /dev/null +++ b/db/migrate/20170805132736_create_map_locations.rb @@ -0,0 +1,11 @@ +class CreateMapLocations < ActiveRecord::Migration + def change + create_table :map_locations do |t| + t.float :latitude + t.float :longitude + t.integer :zoom + t.integer :proposal_id, index: true + t.integer :investment_id, index: true + end + end +end diff --git a/db/migrate/20170911110109_add_user_id_to_images.rb b/db/migrate/20170911110109_add_user_id_to_images.rb new file mode 100644 index 000000000..31467acee --- /dev/null +++ b/db/migrate/20170911110109_add_user_id_to_images.rb @@ -0,0 +1,5 @@ +class AddUserIdToImages < ActiveRecord::Migration + def change + add_reference :images, :user, index: true, foreign_key: true + end +end diff --git a/db/migrate/20170927110953_add_shift_task.rb b/db/migrate/20170927110953_add_shift_task.rb new file mode 100644 index 000000000..8adf23dd1 --- /dev/null +++ b/db/migrate/20170927110953_add_shift_task.rb @@ -0,0 +1,5 @@ +class AddShiftTask < ActiveRecord::Migration + def change + add_column :poll_shifts, :task, :integer, null: false, default: 0 + end +end diff --git a/db/migrate/20170928132402_add_summary_and_description_to_polls.rb b/db/migrate/20170928132402_add_summary_and_description_to_polls.rb new file mode 100644 index 000000000..6fb965346 --- /dev/null +++ b/db/migrate/20170928132402_add_summary_and_description_to_polls.rb @@ -0,0 +1,6 @@ +class AddSummaryAndDescriptionToPolls < ActiveRecord::Migration + def change + add_column :polls, :summary, :text + add_column :polls, :description, :text + end +end diff --git a/db/migrate/20171002103314_add_poll_shift_task_index.rb b/db/migrate/20171002103314_add_poll_shift_task_index.rb new file mode 100644 index 000000000..d15275556 --- /dev/null +++ b/db/migrate/20171002103314_add_poll_shift_task_index.rb @@ -0,0 +1,7 @@ +class AddPollShiftTaskIndex < ActiveRecord::Migration + def change + remove_index "poll_shifts", name: "index_poll_shifts_on_booth_id_and_officer_id" + add_index :poll_shifts, :task + add_index :poll_shifts, [:booth_id, :officer_id, :task], unique: true + end +end diff --git a/db/migrate/20171002121658_add_origin_to_poll_voters.rb b/db/migrate/20171002121658_add_origin_to_poll_voters.rb new file mode 100644 index 000000000..845c1b774 --- /dev/null +++ b/db/migrate/20171002121658_add_origin_to_poll_voters.rb @@ -0,0 +1,5 @@ +class AddOriginToPollVoters < ActiveRecord::Migration + def change + add_column :poll_voters, :origin, :string + end +end diff --git a/db/migrate/20171002122312_create_poll_recount.rb b/db/migrate/20171002122312_create_poll_recount.rb new file mode 100644 index 000000000..807f1c84e --- /dev/null +++ b/db/migrate/20171002122312_create_poll_recount.rb @@ -0,0 +1,24 @@ +class CreatePollRecount < ActiveRecord::Migration + def change + create_table :poll_recounts do |t| + t.integer :author_id + t.string :origin + t.date :date + t.integer :booth_assignment_id + t.integer :officer_assignment_id + t.text :officer_assignment_id_log, default: "" + t.text :author_id_log, default: "" + t.integer :white_amount + t.text :white_amount_log, default: "" + t.integer :null_amount + t.text :null_amount_log, default: "" + t.integer :total_amount + t.text :total_amount_log, default: "" + end + + add_index :poll_recounts, :booth_assignment_id + add_index :poll_recounts, :officer_assignment_id + add_foreign_key :poll_recounts, :poll_booth_assignments, column: :booth_assignment_id + add_foreign_key :poll_recounts, :poll_officer_assignments, column: :officer_assignment_id + end +end diff --git a/db/migrate/20171002191347_add_default_to_recount_amounts.rb b/db/migrate/20171002191347_add_default_to_recount_amounts.rb new file mode 100644 index 000000000..b90e86aae --- /dev/null +++ b/db/migrate/20171002191347_add_default_to_recount_amounts.rb @@ -0,0 +1,7 @@ +class AddDefaultToRecountAmounts < ActiveRecord::Migration + def change + change_column_default :poll_recounts, :white_amount, 0 + change_column_default :poll_recounts, :null_amount, 0 + change_column_default :poll_recounts, :total_amount, 0 + end +end diff --git a/db/migrate/20171003095936_remove_officer_assigment_composed_index.rb b/db/migrate/20171003095936_remove_officer_assigment_composed_index.rb new file mode 100644 index 000000000..874672f84 --- /dev/null +++ b/db/migrate/20171003095936_remove_officer_assigment_composed_index.rb @@ -0,0 +1,5 @@ +class RemoveOfficerAssigmentComposedIndex < ActiveRecord::Migration + def change + remove_index "poll_officer_assignments", name: "index_poll_officer_assignments_on_officer_id_and_date" + end +end diff --git a/db/migrate/20171003170029_remove_description_from_poll_questions.rb b/db/migrate/20171003170029_remove_description_from_poll_questions.rb new file mode 100644 index 000000000..31e1b9578 --- /dev/null +++ b/db/migrate/20171003170029_remove_description_from_poll_questions.rb @@ -0,0 +1,5 @@ +class RemoveDescriptionFromPollQuestions < ActiveRecord::Migration + def change + remove_column :poll_questions, :description + end +end diff --git a/db/migrate/20171003212958_add_date_to_poll_shift_composed_index.rb b/db/migrate/20171003212958_add_date_to_poll_shift_composed_index.rb new file mode 100644 index 000000000..b59a859c1 --- /dev/null +++ b/db/migrate/20171003212958_add_date_to_poll_shift_composed_index.rb @@ -0,0 +1,7 @@ +class AddDateToPollShiftComposedIndex < ActiveRecord::Migration + def change + remove_index "poll_shifts", name: "index_poll_shifts_on_booth_id_and_officer_id_and_task" + remove_index "poll_shifts", name: "index_poll_shifts_on_task" + add_index :poll_shifts, [:booth_id, :officer_id, :date, :task], unique: true + end +end diff --git a/db/migrate/20171003223152_add_officer_to_poll_voter.rb b/db/migrate/20171003223152_add_officer_to_poll_voter.rb new file mode 100644 index 000000000..99f9cd3e3 --- /dev/null +++ b/db/migrate/20171003223152_add_officer_to_poll_voter.rb @@ -0,0 +1,5 @@ +class AddOfficerToPollVoter < ActiveRecord::Migration + def change + add_column :poll_voters, :officer_id, :integer + end +end diff --git a/db/migrate/20171004025903_create_poll_question_answers.rb b/db/migrate/20171004025903_create_poll_question_answers.rb new file mode 100644 index 000000000..834421f5f --- /dev/null +++ b/db/migrate/20171004025903_create_poll_question_answers.rb @@ -0,0 +1,9 @@ +class CreatePollQuestionAnswers < ActiveRecord::Migration + def change + create_table :poll_question_answers do |t| + t.string :title + t.text :description + t.references :poll_question, index: true, foreign_key: true + end + end +end diff --git a/db/migrate/20171004151553_rename_poll_question_id_to_question_id.rb b/db/migrate/20171004151553_rename_poll_question_id_to_question_id.rb new file mode 100644 index 000000000..c53298bfb --- /dev/null +++ b/db/migrate/20171004151553_rename_poll_question_id_to_question_id.rb @@ -0,0 +1,5 @@ +class RenamePollQuestionIdToQuestionId < ActiveRecord::Migration + def change + rename_column :poll_question_answers, :poll_question_id, :question_id + end +end diff --git a/db/migrate/20171004210108_create_poll_question_answer_videos.rb b/db/migrate/20171004210108_create_poll_question_answer_videos.rb new file mode 100644 index 000000000..7cce33b29 --- /dev/null +++ b/db/migrate/20171004210108_create_poll_question_answer_videos.rb @@ -0,0 +1,11 @@ +class CreatePollQuestionAnswerVideos < ActiveRecord::Migration + def change + create_table :poll_question_answer_videos do |t| + t.string :title + t.string :url + t.integer :answer_id, index: true + end + + add_foreign_key :poll_question_answer_videos, :poll_question_answers, column: :answer_id + end +end diff --git a/db/migrate/20171006145053_add_token_to_poll_voters.rb b/db/migrate/20171006145053_add_token_to_poll_voters.rb new file mode 100644 index 000000000..5d07f5065 --- /dev/null +++ b/db/migrate/20171006145053_add_token_to_poll_voters.rb @@ -0,0 +1,5 @@ +class AddTokenToPollVoters < ActiveRecord::Migration + def change + add_column :poll_voters, :token, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index df544e28a..9aa04f187 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: 20170922101247) do +ActiveRecord::Schema.define(version: 20171006145053) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -388,6 +388,22 @@ ActiveRecord::Schema.define(version: 20170922101247) do add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree + create_table "images", force: :cascade do |t| + t.integer "imageable_id" + t.string "imageable_type" + t.string "title", limit: 80 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "attachment_file_name" + t.string "attachment_content_type" + t.integer "attachment_file_size" + t.datetime "attachment_updated_at" + t.integer "user_id" + end + + add_index "images", ["imageable_type", "imageable_id"], name: "index_images_on_imageable_type_and_imageable_id", using: :btree + add_index "images", ["user_id"], name: "index_images_on_user_id", using: :btree + create_table "legacy_legislations", force: :cascade do |t| t.string "title" t.text "body" @@ -567,6 +583,17 @@ ActiveRecord::Schema.define(version: 20170922101247) do add_index "managers", ["user_id"], name: "index_managers_on_user_id", using: :btree + create_table "map_locations", force: :cascade do |t| + t.float "latitude" + t.float "longitude" + t.integer "zoom" + t.integer "proposal_id" + t.integer "investment_id" + end + + add_index "map_locations", ["investment_id"], name: "index_map_locations_on_investment_id", using: :btree + add_index "map_locations", ["proposal_id"], name: "index_map_locations_on_proposal_id", using: :btree + create_table "moderators", force: :cascade do |t| t.integer "user_id" end @@ -646,7 +673,6 @@ ActiveRecord::Schema.define(version: 20170922101247) do end add_index "poll_officer_assignments", ["booth_assignment_id"], name: "index_poll_officer_assignments_on_booth_assignment_id", using: :btree - add_index "poll_officer_assignments", ["officer_id", "date"], name: "index_poll_officer_assignments_on_officer_id_and_date", using: :btree add_index "poll_officer_assignments", ["officer_id"], name: "index_poll_officer_assignments_on_officer_id", using: :btree create_table "poll_officers", force: :cascade do |t| @@ -676,6 +702,22 @@ ActiveRecord::Schema.define(version: 20170922101247) do add_index "poll_partial_results", ["origin"], name: "index_poll_partial_results_on_origin", using: :btree add_index "poll_partial_results", ["question_id"], name: "index_poll_partial_results_on_question_id", using: :btree + create_table "poll_question_answer_videos", force: :cascade do |t| + t.string "title" + t.string "url" + t.integer "answer_id" + end + + add_index "poll_question_answer_videos", ["answer_id"], name: "index_poll_question_answer_videos_on_answer_id", using: :btree + + create_table "poll_question_answers", force: :cascade do |t| + t.string "title" + t.text "description" + t.integer "question_id" + end + + add_index "poll_question_answers", ["question_id"], name: "index_poll_question_answers_on_question_id", using: :btree + create_table "poll_questions", force: :cascade do |t| t.integer "proposal_id" t.integer "poll_id" @@ -683,7 +725,6 @@ ActiveRecord::Schema.define(version: 20170922101247) do t.string "author_visible_name" t.string "title" t.string "valid_answers" - t.text "description" t.integer "comments_count" t.datetime "hidden_at" t.datetime "created_at" @@ -697,6 +738,25 @@ ActiveRecord::Schema.define(version: 20170922101247) do add_index "poll_questions", ["proposal_id"], name: "index_poll_questions_on_proposal_id", using: :btree add_index "poll_questions", ["tsv"], name: "index_poll_questions_on_tsv", using: :gin + create_table "poll_recounts", force: :cascade do |t| + t.integer "author_id" + t.string "origin" + t.date "date" + t.integer "booth_assignment_id" + t.integer "officer_assignment_id" + t.text "officer_assignment_id_log", default: "" + t.text "author_id_log", default: "" + t.integer "white_amount", default: 0 + t.text "white_amount_log", default: "" + t.integer "null_amount", default: 0 + t.text "null_amount_log", default: "" + t.integer "total_amount", default: 0 + t.text "total_amount_log", default: "" + end + + add_index "poll_recounts", ["booth_assignment_id"], name: "index_poll_recounts_on_booth_assignment_id", using: :btree + add_index "poll_recounts", ["officer_assignment_id"], name: "index_poll_recounts_on_officer_assignment_id", using: :btree + create_table "poll_shifts", force: :cascade do |t| t.integer "booth_id" t.integer "officer_id" @@ -705,9 +765,10 @@ ActiveRecord::Schema.define(version: 20170922101247) do t.datetime "updated_at" t.string "officer_name" t.string "officer_email" + t.integer "task", default: 0, null: false end - add_index "poll_shifts", ["booth_id", "officer_id"], name: "index_poll_shifts_on_booth_id_and_officer_id", using: :btree + add_index "poll_shifts", ["booth_id", "officer_id", "date", "task"], name: "index_poll_shifts_on_booth_id_and_officer_id_and_date_and_task", unique: true, using: :btree add_index "poll_shifts", ["booth_id"], name: "index_poll_shifts_on_booth_id", using: :btree add_index "poll_shifts", ["officer_id"], name: "index_poll_shifts_on_officer_id", using: :btree @@ -739,6 +800,9 @@ ActiveRecord::Schema.define(version: 20170922101247) do t.integer "answer_id" t.integer "officer_assignment_id" t.integer "user_id" + t.string "origin" + t.integer "officer_id" + t.string "token" end add_index "poll_voters", ["booth_assignment_id"], name: "index_poll_voters_on_booth_assignment_id", using: :btree @@ -769,6 +833,8 @@ ActiveRecord::Schema.define(version: 20170922101247) do t.datetime "ends_at" t.boolean "published", default: false t.boolean "geozone_restricted", default: false + t.text "summary" + t.text "description" end add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree @@ -1117,6 +1183,7 @@ ActiveRecord::Schema.define(version: 20170922101247) do add_foreign_key "geozones_polls", "geozones" add_foreign_key "geozones_polls", "polls" add_foreign_key "identities", "users" + add_foreign_key "images", "users" add_foreign_key "legislation_draft_versions", "legislation_processes" add_foreign_key "legislation_proposals", "legislation_processes" add_foreign_key "locks", "users" @@ -1133,9 +1200,13 @@ ActiveRecord::Schema.define(version: 20170922101247) do add_foreign_key "poll_partial_results", "poll_officer_assignments", column: "officer_assignment_id" add_foreign_key "poll_partial_results", "poll_questions", column: "question_id" add_foreign_key "poll_partial_results", "users", column: "author_id" + add_foreign_key "poll_question_answer_videos", "poll_question_answers", column: "answer_id" + add_foreign_key "poll_question_answers", "poll_questions", column: "question_id" add_foreign_key "poll_questions", "polls" add_foreign_key "poll_questions", "proposals" add_foreign_key "poll_questions", "users", column: "author_id" + add_foreign_key "poll_recounts", "poll_booth_assignments", column: "booth_assignment_id" + add_foreign_key "poll_recounts", "poll_officer_assignments", column: "officer_assignment_id" add_foreign_key "poll_voters", "polls" add_foreign_key "poll_white_results", "poll_booth_assignments", column: "booth_assignment_id" add_foreign_key "poll_white_results", "poll_officer_assignments", column: "officer_assignment_id" diff --git a/db/seeds.rb b/db/seeds.rb index 96916f29a..fcfa6340c 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -79,7 +79,9 @@ Setting['feature.public_stats'] = true Setting['feature.budgets'] = true Setting['feature.signature_sheets'] = true Setting['feature.legislation'] = true +Setting['feature.user.recommendations'] = true Setting['feature.community'] = true +Setting['feature.map'] = nil # Spending proposals feature flags Setting['feature.spending_proposal_features.voting_allowed'] = nil @@ -108,3 +110,8 @@ Setting['min_age_to_participate'] = 16 # Proposal improvement url path ('/more-information/proposal-improvement') Setting['proposal_improvement_path'] = nil + +# City map feature default configuration (Greenwich) +Setting['map_latitude'] = 51.48 +Setting['map_longitude'] = 0.0 +Setting['map_zoom'] = 10 diff --git a/lib/census_api.rb b/lib/census_api.rb index 066c0be95..931781c6d 100644 --- a/lib/census_api.rb +++ b/lib/census_api.rb @@ -119,7 +119,7 @@ class CensusApi {get_habita_datos_response: {get_habita_datos_return: {datos_habitante: {}, datos_vivienda: {}}}} end - def is_dni?(document_type) + def dni?(document_type) document_type.to_s == "1" end diff --git a/lib/document_parser.rb b/lib/document_parser.rb index c60b180dc..9e59c6b75 100644 --- a/lib/document_parser.rb +++ b/lib/document_parser.rb @@ -5,7 +5,7 @@ module DocumentParser document_number = document_number.to_s.gsub(/[^0-9A-Za-z]/i, '') variants = [] - if is_dni?(document_type) + if dni?(document_type) document_number, letter = split_letter_from(document_number) number_variants = get_number_variants_with_leading_zeroes_from(document_number) letter_variants = get_letter_variants(number_variants, letter) diff --git a/lib/local_census.rb b/lib/local_census.rb index 6c6e8fe12..1a0428787 100644 --- a/lib/local_census.rb +++ b/lib/local_census.rb @@ -63,7 +63,7 @@ class LocalCensus LocalCensusRecord.find_by(document_type: document_type, document_number: document_number) end - def is_dni?(document_type) + def dni?(document_type) document_type.to_s == "1" end diff --git a/spec/factories.rb b/spec/factories.rb index b90f68175..a28471efc 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -52,6 +52,12 @@ FactoryGirl.define do trait :verified do verified_at Time.current end + + trait :in_census do + document_number "12345678Z" + document_type "1" + verified_at Time.current + end end factory :identity do @@ -318,6 +324,21 @@ FactoryGirl.define do feasibility "feasible" valuation_finished true end + + end + + factory :image do + attachment { File.new("spec/fixtures/files/clippy.jpg") } + title "Lorem ipsum dolor sit amet" + association :user, factory: :user + + trait :proposal_image do + association :imageable, factory: :proposal + end + + trait :budget_investment_image do + association :imageable, factory: :budget_investment + end end factory :budget_ballot, class: 'Budget::Ballot' do @@ -477,10 +498,15 @@ FactoryGirl.define do poll association :author, factory: :user sequence(:title) { |n| "Question title #{n}" } - sequence(:description) { |n| "Question description #{n}" } valid_answers { Faker::Lorem.words(3).join(', ') } end + factory :poll_question_answer, class: 'Poll::Question::Answer' do + association :question, factory: :poll_question + sequence(:title) { |n| "Question title #{n}" } + sequence(:description) { |n| "Question description #{n}" } + end + factory :poll_booth, class: 'Poll::Booth' do sequence(:name) { |n| "Booth #{n}" } sequence(:location) { |n| "Street #{n}" } @@ -510,6 +536,8 @@ FactoryGirl.define do factory :poll_voter, class: 'Poll::Voter' do poll association :user, :level_two + association :officer, factory: :poll_officer + origin "web" trait :from_booth do association :booth_assignment, factory: :poll_booth_assignment @@ -554,6 +582,11 @@ FactoryGirl.define do origin { 'web' } end + factory :poll_recount, class: 'Poll::Recount' do + association :author, factory: :user + origin { 'web' } + end + factory :officing_residence, class: 'Officing::Residence' do user association :officer, factory: :poll_officer @@ -804,4 +837,39 @@ LOREM_IPSUM association :author, factory: :user end + factory :direct_upload do + user + + trait :proposal do + resource_type "Proposal" + end + trait :budget_investment do + resource_type "Budget::Investment" + end + + trait :documents do + resource_relation "documents" + attachment { File.new("spec/fixtures/files/empty.pdf") } + end + trait :image do + resource_relation "image" + attachment { File.new("spec/fixtures/files/clippy.jpg") } + end + initialize_with { new(attributes) } + end + + factory :map_location do + latitude 51.48 + longitude 0.0 + zoom 10 + + trait :proposal_map_location do + proposal + end + + trait :budget_investment_map_location do + association :investment, factory: :budget_investment + end + end + end diff --git a/spec/features/admin/organizations_spec.rb b/spec/features/admin/organizations_spec.rb index 814aa9df2..58375f569 100644 --- a/spec/features/admin/organizations_spec.rb +++ b/spec/features/admin/organizations_spec.rb @@ -95,7 +95,7 @@ feature 'Admin::Organizations' do click_on 'Verify' end expect(current_path).to eq(admin_organizations_path) - expect(page).to have_content ('Verified') + expect(page).to have_content 'Verified' expect(organization.reload.verified?).to eq(true) end @@ -108,18 +108,18 @@ feature 'Admin::Organizations' do click_on "Verified" within("#organization_#{organization.id}") do - expect(page).to have_content ('Verified') + expect(page).to have_content 'Verified' expect(page).to_not have_link('Verify') expect(page).to have_link('Reject') click_on 'Reject' end expect(current_path).to eq(admin_organizations_path) - expect(page).to_not have_content (organization.name) + expect(page).to_not have_content organization.name click_on 'Rejected' - expect(page).to have_content ('Rejected') - expect(page).to have_content (organization.name) + expect(page).to have_content 'Rejected' + expect(page).to have_content organization.name expect(organization.reload.rejected?).to eq(true) end @@ -137,10 +137,10 @@ feature 'Admin::Organizations' do click_on 'Verify' end expect(current_path).to eq(admin_organizations_path) - expect(page).to_not have_content (organization.name) + expect(page).to_not have_content organization.name click_on('Verified') - expect(page).to have_content (organization.name) + expect(page).to have_content organization.name expect(organization.reload.verified?).to eq(true) end diff --git a/spec/features/admin/poll/booth_assigments_spec.rb b/spec/features/admin/poll/booth_assigments_spec.rb index 09a21dd72..77881efaa 100644 --- a/spec/features/admin/poll/booth_assigments_spec.rb +++ b/spec/features/admin/poll/booth_assigments_spec.rb @@ -97,11 +97,8 @@ feature 'Admin booths assignments' do officer_assignment_2 = create(:poll_officer_assignment, booth_assignment: booth_assignment, date: poll.ends_at) final_officer_assignment = create(:poll_officer_assignment, :final, booth_assignment: booth_assignment, date: poll.ends_at) - total_recount = create(:poll_total_result, - booth_assignment: booth_assignment, - officer_assignment: final_officer_assignment, - date: final_officer_assignment.date, - amount: 5678) + create(:poll_voter, poll: poll, booth_assignment: booth_assignment, created_at: poll.starts_at.to_date) + create(:poll_voter, poll: poll, booth_assignment: booth_assignment, created_at: poll.ends_at.to_date) booth_assignment_2 = create(:poll_booth_assignment, poll: poll) @@ -111,9 +108,20 @@ feature 'Admin booths assignments' do within('#assigned_booths_list') { click_link booth.name } click_link 'Recounts' + + within('#totals') do + within("#total_system") { expect(page).to have_content "2" } + end + within('#recounts_list') do - within("#recounting_#{total_recount.date.strftime('%Y%m%d')}") do - expect(page).to have_content total_recount.amount + within("#recounting_#{poll.starts_at.to_date.strftime('%Y%m%d')}") do + expect(page).to have_content 1 + end + within("#recounting_#{(poll.ends_at.to_date - 5.days).strftime('%Y%m%d')}") do + expect(page).to have_content '-' + end + within("#recounting_#{poll.ends_at.to_date.strftime('%Y%m%d')}") do + expect(page).to have_content 1 end end end diff --git a/spec/features/admin/poll/booths_spec.rb b/spec/features/admin/poll/booths_spec.rb index 13f3af2ff..22b77b397 100644 --- a/spec/features/admin/poll/booths_spec.rb +++ b/spec/features/admin/poll/booths_spec.rb @@ -87,9 +87,11 @@ feature 'Admin booths' do end scenario "Edit" do + poll = create(:poll, :current) booth = create(:poll_booth) + assignment = create(:poll_booth_assignment, poll: poll, booth: booth) - visit admin_booths_path + visit available_admin_booths_path within("#booth_#{booth.id}") do click_link "Edit" @@ -109,4 +111,4 @@ feature 'Admin booths' do end end -end \ No newline at end of file +end diff --git a/spec/features/admin/poll/polls_spec.rb b/spec/features/admin/poll/polls_spec.rb index 6eb64f6e1..d69e7ad75 100644 --- a/spec/features/admin/poll/polls_spec.rb +++ b/spec/features/admin/poll/polls_spec.rb @@ -58,6 +58,8 @@ feature 'Admin polls' do fill_in "poll_name", with: "Upcoming poll" fill_in 'poll_starts_at', with: start_date.strftime("%d/%m/%Y") fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y") + fill_in 'poll_summary', with: "Upcoming poll's summary. This poll..." + fill_in 'poll_description', with: "Upcomming poll's description. This poll..." click_button "Create poll" expect(page).to have_content "Poll created successfully" @@ -68,14 +70,18 @@ feature 'Admin polls' do scenario "Edit" do poll = create(:poll) + create(:image, imageable: poll) visit admin_poll_path(poll) click_link "Edit" end_date = 1.year.from_now + expect(page).to have_css("img[alt='#{poll.image.title}']") + fill_in "poll_name", with: "Next Poll" fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y") + click_button "Update poll" expect(page).to have_content "Poll updated successfully" @@ -181,54 +187,6 @@ feature 'Admin polls' do expect(page).to_not have_content "There are no questions assigned to this poll" end - scenario 'Add question to poll', :js do - poll = create(:poll) - question = create(:poll_question, title: 'Should we rebuild the city?') - - visit admin_poll_path(poll) - - expect(page).to have_content 'Questions (0)' - expect(page).to have_content 'There are no questions assigned to this poll' - - fill_in 'search-questions', with: 'rebuild' - click_button 'Search' - - within('#search-questions-results') do - click_link 'Include question' - end - - expect(page).to have_content 'Question added to this poll' - - visit admin_poll_path(poll) - - expect(page).to have_content 'Questions (1)' - expect(page).to_not have_content 'There are no questions assigned to this poll' - expect(page).to have_content question.title - end - - scenario 'Remove question from poll', :js do - poll = create(:poll) - question = create(:poll_question, poll: poll) - - visit admin_poll_path(poll) - - expect(page).to have_content 'Questions (1)' - expect(page).to_not have_content 'There are no questions assigned to this poll' - expect(page).to have_content question.title - - within("#poll_question_#{question.id}") do - click_link 'Remove question from poll' - end - - expect(page).to have_content 'Question removed from this poll' - - visit admin_poll_path(poll) - - expect(page).to have_content 'Questions (0)' - expect(page).to have_content 'There are no questions assigned to this poll' - expect(page).to_not have_content question.title - end - end end @@ -249,18 +207,18 @@ feature 'Admin polls' do booth_assignment_final_recounted = create(:poll_booth_assignment, poll: poll) 3.times do |i| - create(:poll_total_result, + create(:poll_recount, booth_assignment: booth_assignment, date: poll.starts_at + i.days, - amount: 21) + total_amount: 21) end 2.times { create(:poll_voter, booth_assignment: booth_assignment_final_recounted) } - create(:poll_total_result, + create(:poll_recount, booth_assignment: booth_assignment_final_recounted, date: poll.ends_at, - amount: 55555) + total_amount: 55555) visit admin_poll_path(poll) @@ -318,12 +276,10 @@ feature 'Admin polls' do answer: 'Tomorrow', amount: 5) end - create(:poll_white_result, + create(:poll_recount, booth_assignment: booth_assignment_1, - amount: 21) - create(:poll_null_result, - booth_assignment: booth_assignment_3, - amount: 44) + white_amount: 21, + null_amount: 44) visit admin_poll_path(poll) diff --git a/spec/features/admin/poll/questions/answers/answers_spec.rb b/spec/features/admin/poll/questions/answers/answers_spec.rb new file mode 100644 index 000000000..66918c4d8 --- /dev/null +++ b/spec/features/admin/poll/questions/answers/answers_spec.rb @@ -0,0 +1,51 @@ +require 'rails_helper' + +feature 'Answers' do + + background do + admin = create(:administrator) + login_as (admin.user) + end + + scenario 'Create' do + question = create(:poll_question) + title = 'Whatever the question may be, the answer is always 42' + description = "The Hitchhiker's Guide To The Universe" + + visit admin_question_path(question) + click_link 'Add answer' + + fill_in 'poll_question_answer_title', with: title + fill_in 'poll_question_answer_description', with: description + + click_button 'Save' + + expect(page).to have_content(title) + expect(page).to have_content(description) + end + + scenario 'Update' do + question = create(:poll_question) + answer = create(:poll_question_answer, question: question, title: "Answer title") + + visit admin_answer_path(answer) + + click_link 'Edit' + + old_title = answer.title + new_title = 'Ex Machina' + + fill_in 'poll_question_answer_title', with: new_title + + click_button 'Save' + + expect(page).to have_content('Changes saved') + expect(page).to have_content(new_title) + + visit admin_question_path(question) + + expect(page).to have_content(new_title) + expect(page).to_not have_content(old_title) + end + +end diff --git a/spec/features/admin/poll/questions/answers/images/images_spec.rb b/spec/features/admin/poll/questions/answers/images/images_spec.rb new file mode 100644 index 000000000..915c8d6b0 --- /dev/null +++ b/spec/features/admin/poll/questions/answers/images/images_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +feature 'Images' do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + pending "Index" + pending "Create" + pending "Destroy" + +end \ No newline at end of file diff --git a/spec/features/admin/poll/questions/answers/videos/videos_spec.rb b/spec/features/admin/poll/questions/answers/videos/videos_spec.rb new file mode 100644 index 000000000..35d07f454 --- /dev/null +++ b/spec/features/admin/poll/questions/answers/videos/videos_spec.rb @@ -0,0 +1,33 @@ +require 'rails_helper' + +feature 'Videos' do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario "Create" do + question = create(:poll_question) + answer = create(:poll_question_answer, question: question) + video_title = "'Magical' by Junko Ohashi" + video_url = "https://www.youtube.com/watch?v=-JMf43st-1A" + + visit admin_question_path(question) + + within("#poll_question_answer_#{answer.id}") do + click_link "Video list" + end + + click_link "Add video" + + fill_in 'poll_question_answer_video_title', with: video_title + fill_in 'poll_question_answer_video_url', with: video_url + + click_button "Save" + + expect(page).to have_content(video_title) + expect(page).to have_content(video_url) + end + +end diff --git a/spec/features/admin/poll/questions_spec.rb b/spec/features/admin/poll/questions_spec.rb index 392b2aabf..5c8cba9c1 100644 --- a/spec/features/admin/poll/questions_spec.rb +++ b/spec/features/admin/poll/questions_spec.rb @@ -24,9 +24,7 @@ feature 'Admin poll questions' do visit admin_question_path(question) expect(page).to have_content(question.title) - expect(page).to have_content(question.description) expect(page).to have_content(question.author.name) - expect(page).to have_content(question.valid_answers.join(" ")) end scenario 'Create' do @@ -45,13 +43,11 @@ feature 'Admin poll questions' do select 'Movies', from: 'poll_question_poll_id' fill_in 'poll_question_title', with: title - fill_in 'poll_question_description', with: description fill_in 'poll_question_video_url', with: video_url click_button 'Save' expect(page).to have_content(title) - expect(page).to have_content(description) expect(page).to have_content(video_url) end @@ -64,15 +60,12 @@ feature 'Admin poll questions' do expect(current_path).to eq(new_admin_question_path) expect(page).to have_field('poll_question_title', with: proposal.title) - expect(page).to have_field('poll_question_description', with: proposal.description) - expect(page).to have_field('poll_question_valid_answers', with: "Yes, No") select 'Proposals', from: 'poll_question_poll_id' click_button 'Save' expect(page).to have_content(proposal.title) - expect(page).to have_content(proposal.description) expect(page).to have_link(proposal.title, href: proposal_path(proposal)) expect(page).to have_link(proposal.author.name, href: user_path(proposal.author)) end diff --git a/spec/features/admin/poll/shifts_spec.rb b/spec/features/admin/poll/shifts_spec.rb index 1e5bb6328..2ac290216 100644 --- a/spec/features/admin/poll/shifts_spec.rb +++ b/spec/features/admin/poll/shifts_spec.rb @@ -30,12 +30,17 @@ feature 'Admin shifts' do expect(page).to have_content officer.name end - scenario "Create", :js do - poll = create(:poll) + scenario "Create Vote Collection Shift and Recount & Scrutiny Shift on same date", :js do + create(:poll) + create(:poll, :incoming) + poll = create(:poll, :current) booth = create(:poll_booth) + assignment = create(:poll_booth_assignment, poll: poll, booth: booth) officer = create(:poll_officer) + vote_collection_dates = (poll.starts_at.to_date..poll.ends_at.to_date).to_a.map { |date| I18n.l(date, format: :long) } + recount_scrutiny_dates = (poll.ends_at.to_date..poll.ends_at.to_date + 1.week).to_a.map { |date| I18n.l(date, format: :long) } - visit admin_booths_path + visit available_admin_booths_path within("#booth_#{booth.id}") do click_link "Manage shifts" @@ -45,7 +50,9 @@ feature 'Admin shifts' do click_button "Search" click_link "Edit shifts" - select I18n.l(poll.starts_at.to_date, format: :long), from: 'shift_date' + expect(page).to have_select('shift_date_vote_collection_date', options: ["Select day", *vote_collection_dates]) + expect(page).not_to have_select('shift_date_recount_scrutiny_date') + select I18n.l(poll.starts_at.to_date, format: :long), from: 'shift_date_vote_collection_date' click_button "Add shift" expect(page).to have_content "Shift added" @@ -53,16 +60,44 @@ feature 'Admin shifts' do within("#shifts") do expect(page).to have_css(".shift", count: 1) expect(page).to have_content(I18n.l(poll.starts_at.to_date, format: :long)) + expect(page).to have_content("Collect Votes") + expect(page).to have_content(officer.name) + end + + visit available_admin_booths_path + + within("#booth_#{booth.id}") do + click_link "Manage shifts" + end + + fill_in "search", with: officer.email + click_button "Search" + click_link "Edit shifts" + + select "Recount & Scrutiny", from: 'shift_task' + + expect(page).to have_select('shift_date_recount_scrutiny_date', options: ["Select day", *recount_scrutiny_dates]) + expect(page).not_to have_select('shift_date_vote_collection_date') + select I18n.l(poll.ends_at.to_date + 4.days, format: :long), from: 'shift_date_recount_scrutiny_date' + click_button "Add shift" + + expect(page).to have_content "Shift added" + + within("#shifts") do + expect(page).to have_css(".shift", count: 2) + expect(page).to have_content(I18n.l(poll.ends_at.to_date + 4.days, format: :long)) + expect(page).to have_content("Recount & Scrutiny") expect(page).to have_content(officer.name) end end - scenario "Erros on create", :js do - poll = create(:poll) + scenario "Error on create", :js do + poll = create(:poll, :current) booth = create(:poll_booth) + assignment = create(:poll_booth_assignment, poll: poll, booth: booth) officer = create(:poll_officer) - visit admin_booths_path + visit available_admin_booths_path within("#booth_#{booth.id}") do click_link "Manage shifts" @@ -73,17 +108,18 @@ feature 'Admin shifts' do click_link "Edit shifts" click_button "Add shift" - expect(page).to have_content "can't be blank" + expect(page).to have_content "A date must be selected" end scenario "Destroy" do - poll = create(:poll) + poll = create(:poll, :current) booth = create(:poll_booth) + assignment = create(:poll_booth_assignment, poll: poll, booth: booth) officer = create(:poll_officer) shift = create(:poll_shift, officer: officer, booth: booth) - visit admin_booths_path + visit available_admin_booths_path within("#booth_#{booth.id}") do click_link "Manage shifts" diff --git a/spec/features/admin/settings_spec.rb b/spec/features/admin/settings_spec.rb index c92b4b525..73d190cb9 100644 --- a/spec/features/admin/settings_spec.rb +++ b/spec/features/admin/settings_spec.rb @@ -28,4 +28,66 @@ feature 'Admin settings' do expect(page).to have_content 'Value updated' end -end \ No newline at end of file + describe "Update map" do + + scenario "Should not be able when map feature deactivated" do + Setting['feature.map'] = false + admin = create(:administrator).user + login_as(admin) + visit admin_settings_path + + expect(page).not_to have_content "Map configuration" + end + + scenario "Should be able when map feature activated" do + Setting['feature.map'] = true + admin = create(:administrator).user + login_as(admin) + visit admin_settings_path + + expect(page).to have_content "Map configuration" + end + + scenario "Should show successful notice" do + Setting['feature.map'] = true + admin = create(:administrator).user + login_as(admin) + visit admin_settings_path + + within "#map-form" do + click_on "Update" + end + + expect(page).to have_content "Map configuration updated succesfully" + end + + scenario "Should display marker by default", :js do + Setting['feature.map'] = true + admin = create(:administrator).user + login_as(admin) + + visit admin_settings_path + + expect(find("#latitude", visible: false).value).to eq "51.48" + expect(find("#longitude", visible: false).value).to eq "0.0" + end + + scenario "Should update marker", :js do + Setting['feature.map'] = true + admin = create(:administrator).user + login_as(admin) + + visit admin_settings_path + find("#admin-map").click + within "#map-form" do + click_on "Update" + end + + expect(find("#latitude", visible: false).value).not_to eq "51.48" + expect(page).to have_content "Map configuration updated succesfully" + end + + + end + +end diff --git a/spec/features/admin/site_customization/images_spec.rb b/spec/features/admin/site_customization/images_spec.rb index 6d180fe8e..fc81bf246 100644 --- a/spec/features/admin/site_customization/images_spec.rb +++ b/spec/features/admin/site_customization/images_spec.rb @@ -20,7 +20,7 @@ feature "Admin custom images" do end expect(page).to have_css("tr.logo_header img[src*='logo_header.png']") - expect(page).to have_css("img[src*='logo_header.png']", count: 2) # one in the admin form an one in the page header + expect(page).to have_css("img[src*='logo_header.png']", count: 1) end scenario "Upload invalid image" do diff --git a/spec/features/admin_spec.rb b/spec/features/admin_spec.rb index 9ea2c2390..f2374f183 100644 --- a/spec/features/admin_spec.rb +++ b/spec/features/admin_spec.rb @@ -12,7 +12,7 @@ feature 'Admin' do visit admin_root_path expect(current_path).not_to eq(admin_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -22,7 +22,7 @@ feature 'Admin' do visit admin_root_path expect(current_path).not_to eq(admin_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -32,7 +32,7 @@ feature 'Admin' do visit admin_root_path expect(current_path).not_to eq(admin_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -42,7 +42,7 @@ feature 'Admin' do visit admin_root_path expect(current_path).not_to eq(admin_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -52,7 +52,7 @@ feature 'Admin' do visit admin_root_path expect(current_path).not_to eq(admin_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 820ebb520..d17bd9c91 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -28,6 +28,21 @@ feature 'Budget Investments' do end end + scenario 'Index should show investment descriptive image only when is defined' do + investment = create(:budget_investment, heading: heading) + investment_with_image = create(:budget_investment, heading: heading) + image = create(:image, imageable: investment_with_image) + + visit budget_investments_path(budget, heading_id: heading.id) + + within("#budget_investment_#{investment.id}") do + expect(page).to have_css("div.no-image") + end + within("#budget_investment_#{investment_with_image.id}") do + expect(page).to have_css("img[alt='#{investment_with_image.image.title}']") + end + end + context("Search") do scenario 'Search by text' do @@ -264,7 +279,7 @@ feature 'Budget Investments' do fill_in "budget_investment_title", with: "search" within("div#js-suggest") do - expect(page).to have_content ("You are seeing 5 of 6 investments containing the term 'search'") + expect(page).to have_content "You are seeing 5 of 6 investments containing the term 'search'" end end @@ -279,7 +294,7 @@ feature 'Budget Investments' do fill_in "budget_investment_title", with: "item" within('div#js-suggest') do - expect(page).to_not have_content ('You are seeing') + expect(page).to_not have_content 'You are seeing' end end @@ -294,7 +309,7 @@ feature 'Budget Investments' do fill_in "budget_investment_title", with: "search" within('div#js-suggest') do - expect(page).to_not have_content ('You are seeing') + expect(page).to_not have_content 'You are seeing' end end end @@ -449,16 +464,35 @@ feature 'Budget Investments' do it_behaves_like "followable", "budget_investment", "budget_investment_path", { "budget_id": "budget_id", "id": "id" } - it_behaves_like "documentable", "budget_investment", "budget_investment_path", {"budget_id": "budget_id", "id": "id"} + it_behaves_like "imageable", "budget_investment", "budget_investment_path", { "budget_id": "budget_id", "id": "id" } - it_behaves_like "nested documentable", + it_behaves_like "nested imageable", "budget_investment", "new_budget_investment_path", { "budget_id": "budget_id" }, - "fill_new_valid_budget_investment", + "imageable_fill_new_valid_budget_investment", "Create Investment", "Budget Investment created successfully." + it_behaves_like "documentable", "budget_investment", "budget_investment_path", { "budget_id": "budget_id", "id": "id" } + + it_behaves_like "nested documentable", + "user", + "budget_investment", + "new_budget_investment_path", + { "budget_id": "budget_id" }, + "documentable_fill_new_valid_budget_investment", + "Create Investment", + "Budget Investment created successfully." + + it_behaves_like "mappable", + "budget_investment", + "investment", + "new_budget_investment_path", + "", + "budget_investment_path", + { "budget_id": "budget_id" } + context "Destroy" do scenario "Admin cannot destroy budget investments" do diff --git a/spec/features/campaigns_spec.rb b/spec/features/campaigns_spec.rb index 6dba2ff09..6e9897a6f 100644 --- a/spec/features/campaigns_spec.rb +++ b/spec/features/campaigns_spec.rb @@ -27,7 +27,7 @@ feature 'Email campaigns' do visit admin_stats_path expect(page).to have_content "#{@campaign1.name} (1)" - expect(page).to_not have_content (@campaign2.name).to_s + expect(page).to_not have_content @campaign2.name.to_s end end \ No newline at end of file diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 749c7a373..3d7c6acf8 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -66,7 +66,7 @@ feature 'Debates' do first(:link, debate.title).click link_text = find_link('Go back')[:href] - expect(link_text).to include(debates_path order: :hot_score, page: 1) + expect(link_text).to include(debates_path(order: :hot_score, page: 1)) end context "Show" do @@ -219,7 +219,7 @@ feature 'Debates' do visit edit_debate_path(debate) expect(current_path).not_to eq(edit_debate_path(debate)) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to carry out the action 'edit' on debate." end @@ -234,7 +234,7 @@ feature 'Debates' do visit edit_debate_path(debate) expect(current_path).not_to eq(edit_debate_path(debate)) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content 'You do not have permission to' end @@ -351,6 +351,69 @@ feature 'Debates' do expect(current_url).to include('order=created_at') expect(current_url).to include('page=1') end + + context 'Recommendations' do + + background do + Setting['feature.user.recommendations'] = true + create(:debate, title: 'Best', cached_votes_total: 10, tag_list: "Sport") + create(:debate, title: 'Medium', cached_votes_total: 5, tag_list: "Sport") + create(:debate, title: 'Worst', cached_votes_total: 1, tag_list: "Sport") + end + + after do + Setting['feature.user.recommendations'] = nil + end + + scenario 'Debates can not ordered by recommendations when there is not an user logged', :js do + visit debates_path + + expect(page).not_to have_selector('a', text: 'recommendations') + end + + scenario 'Should display text when there are not recommendeds results', :js do + user = create(:user) + proposal = create(:proposal, tag_list: "Distinct_to_sport") + create(:follow, followable: proposal, user: user) + login_as(user) + visit debates_path + + click_link 'recommendations' + + expect(page).to have_content "There are not debates related to your interests" + end + + scenario 'Should display text when user has not related interests', :js do + user = create(:user) + login_as(user) + visit debates_path + + click_link 'recommendations' + + expect(page).to have_content "Follow proposals so we can give you recommendations" + end + + scenario 'Debates are ordered by recommendations when there is a user logged', :js do + proposal = create(:proposal, tag_list: "Sport" ) + user = create(:user) + create(:follow, followable: proposal, user: user) + login_as(user) + + visit debates_path + + click_link 'recommendations' + + expect(page).to have_selector('a.active', text: 'recommendations') + + within '#debates' do + expect('Best').to appear_before('Medium') + expect('Medium').to appear_before('Worst') + end + + expect(current_url).to include('order=recommendations') + expect(current_url).to include('page=1') + end + end end context "Search" do @@ -759,6 +822,32 @@ feature 'Debates' do end end + scenario "Reorder by recommendations results maintaing search", :js do + Setting['feature.user.recommendations'] = true + user = create(:user) + login_as(user) + debate1 = create(:debate, title: "Show you got", cached_votes_total: 10, tag_list: "Sport") + debate2 = create(:debate, title: "Show what you got", cached_votes_total: 1, tag_list: "Sport") + debate3 = create(:debate, title: "Do not display with same tag", cached_votes_total: 100, tag_list: "Sport") + debate4 = create(:debate, title: "Do not display", cached_votes_total: 1) + proposal1 = create(:proposal, tag_list: "Sport") + create(:follow, followable: proposal1, user: user) + + visit debates_path + fill_in "search", with: "Show you got" + click_button "Search" + click_link 'recommendations' + expect(page).to have_selector("a.active", text: "recommendations") + + within("#debates") do + expect(all(".debate")[0].text).to match "Show you got" + expect(all(".debate")[1].text).to match "Show what you got" + expect(page).to_not have_content "Do not display with same tag" + expect(page).to_not have_content "Do not display" + end + Setting['feature.user.recommendations'] = nil + end + scenario 'After a search do not show featured debates' do featured_debates = create_featured_debates debate = create(:debate, title: "Abcdefghi") @@ -879,7 +968,7 @@ feature 'Debates' do check "debate_terms_of_service" within('div#js-suggest') do - expect(page).to have_content ("You are seeing 5 of 6 debates containing the term 'debate'") + expect(page).to have_content "You are seeing 5 of 6 debates containing the term 'debate'" end end @@ -895,7 +984,7 @@ feature 'Debates' do check "debate_terms_of_service" within('div#js-suggest') do - expect(page).to_not have_content ('You are seeing') + expect(page).to_not have_content 'You are seeing' end end end diff --git a/spec/features/emails_spec.rb b/spec/features/emails_spec.rb index af7674101..21fdf8a64 100644 --- a/spec/features/emails_spec.rb +++ b/spec/features/emails_spec.rb @@ -335,9 +335,9 @@ feature 'Emails' do reset_mailer budget.email_selected - expect(find_email investment1.author.email).to be - expect(find_email investment2.author.email).to be - expect(find_email investment3.author.email).to_not be + expect(find_email(investment1.author.email)).to be + expect(find_email(investment2.author.email)).to be + expect(find_email(investment3.author.email)).to_not be email = open_last_email investment = investment2 @@ -358,9 +358,9 @@ feature 'Emails' do reset_mailer budget.email_unselected - expect(find_email investment1.author.email).to be - expect(find_email investment2.author.email).to be - expect(find_email investment3.author.email).to_not be + expect(find_email(investment1.author.email)).to be + expect(find_email(investment2.author.email)).to be + expect(find_email(investment3.author.email)).to_not be email = open_last_email investment = investment2 diff --git a/spec/features/home_spec.rb b/spec/features/home_spec.rb index 4deed36bb..cb5349814 100644 --- a/spec/features/home_spec.rb +++ b/spec/features/home_spec.rb @@ -3,20 +3,138 @@ require 'rails_helper' feature "Home" do feature "For not logged users" do + scenario 'Welcome message' do visit root_path expect(page).to have_content "Love the city, and it will become a city you love" end + + scenario 'Not display recommended section' do + debate = create(:debate) + + visit root_path + + expect(page).not_to have_content "Recommendations that may interest you" + end + end feature "For signed in users" do - scenario 'Redirect to proposals' do - login_as(create(:user)) - visit root_path - expect(current_path).to eq proposals_path + feature "Recommended" do + + background do + Setting['feature.user.recommendations'] = true + user = create(:user) + proposal = create(:proposal, tag_list: "Sport" ) + create(:follow, followable: proposal, user: user) + login_as(user) + end + + after do + Setting['feature.user.recommendations'] = nil + end + + scenario 'Display recommended section' do + debate = create(:debate, tag_list: "Sport") + visit root_path + expect(page).to have_content "Recommendations that may interest you" + end + + scenario 'Display recommended section when feature flag recommended is active' do + debate = create(:debate, tag_list: "Sport") + visit root_path + expect(page).to have_content "Recommendations that may interest you" + end + + scenario 'Not display recommended section when feature flag recommended is not active' do + debate = create(:debate, tag_list: "Sport") + Setting['feature.user.recommendations'] = false + + visit root_path + + expect(page).not_to have_content "Recommendations that may interest you" + end + + scenario 'Display debates' do + debate = create(:debate, tag_list: "Sport") + + visit root_path + + expect(page).to have_content debate.title + expect(page).to have_content debate.description + end + + scenario 'Display all recommended debates link' do + debate = create(:debate, tag_list: "Sport") + visit root_path + expect(page).to have_link("All recommended debates", href: debates_path(order: "recommendations")) + end + + scenario 'Display proposal' do + proposal = create(:proposal, tag_list: "Sport") + + visit root_path + + expect(page).to have_content proposal.title + expect(page).to have_content proposal.description + end + + scenario 'Display all recommended proposals link' do + debate = create(:proposal, tag_list: "Sport") + visit root_path + expect(page).to have_link("All recommended proposals", href: proposals_path(order: "recommendations")) + end + + scenario 'Display orbit carrousel' do + create_list(:debate, 3, tag_list: "Sport") + + visit root_path + + expect(page).to have_selector('li[data-slide="0"]') + expect(page).to have_selector('li[data-slide="1"]', visible: false) + expect(page).to have_selector('li[data-slide="2"]', visible: false) + end + + scenario 'Display recommended show when click on carousel' do + debate = create(:debate, tag_list: "Sport") + + visit root_path + click_on debate.title + + expect(current_path).to eq debate_path(debate) + end + + scenario 'Do not display recommended section when there are not debates and proposals' do + visit root_path + expect(page).not_to have_content "Recommendations that may interest you" + end + + feature 'Carousel size' do + + scenario 'Display debates centered when there are no proposals' do + debate = create(:debate, tag_list: "Sport") + visit root_path + expect(page).to have_selector('.medium-centered.large-centered') + end + + scenario 'Correct display debates and proposals' do + proposal = create(:proposal, tag_list: "Sport") + debates = create(:debate, tag_list: "Sport") + + visit root_path + + expect(page).to have_selector('.debates.medium-offset-2.large-offset-2') + expect(page).not_to have_selector('.proposals.medium-offset-2.large-offset-2') + expect(page).not_to have_selector('.debates.end') + expect(page).to have_selector('.proposals.end') + expect(page).not_to have_selector('.medium-centered.large-centered') + end + + end end + end feature 'IE alert' do diff --git a/spec/features/management/managed_users_spec.rb b/spec/features/management/managed_users_spec.rb index ef3c539d9..68b9777a3 100644 --- a/spec/features/management/managed_users_spec.rb +++ b/spec/features/management/managed_users_spec.rb @@ -24,9 +24,9 @@ feature 'Managed User' do within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s - expect(page).to have_content (user.email).to_s - expect(page).to have_content (user.document_number).to_s + expect(page).to have_content user.username.to_s + expect(page).to have_content user.email.to_s + expect(page).to have_content user.document_number.to_s end end @@ -45,9 +45,9 @@ feature 'Managed User' do within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s - expect(page).to have_content (user.email).to_s - expect(page).to have_content (user.document_number).to_s + expect(page).to have_content user.username.to_s + expect(page).to have_content user.email.to_s + expect(page).to have_content user.document_number.to_s end end @@ -78,9 +78,9 @@ feature 'Managed User' do within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s - expect(page).to have_content (user.email).to_s - expect(page).to have_content (user.document_number).to_s + expect(page).to have_content user.username.to_s + expect(page).to have_content user.email.to_s + expect(page).to have_content user.document_number.to_s end end @@ -106,9 +106,9 @@ feature 'Managed User' do user = User.last within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s - expect(page).to have_content (user.email).to_s - expect(page).to have_content (user.document_number).to_s + expect(page).to have_content user.username.to_s + expect(page).to have_content user.email.to_s + expect(page).to have_content user.document_number.to_s end end @@ -134,8 +134,8 @@ feature 'Managed User' do user = User.last within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s - expect(page).to have_content (user.document_number).to_s + expect(page).to have_content user.username.to_s + expect(page).to have_content user.document_number.to_s end end end @@ -151,14 +151,14 @@ feature 'Managed User' do within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s + expect(page).to have_content user.username.to_s click_link "Change user" end expect(page).to have_content "User session signed out successfully." expect(page).to_not have_content "Identified as" - expect(page).to_not have_content (user.username).to_s + expect(page).to_not have_content user.username.to_s expect(current_path).to eq(management_root_path) end diff --git a/spec/features/management/proposals_spec.rb b/spec/features/management/proposals_spec.rb index 349a4f904..ed24de172 100644 --- a/spec/features/management/proposals_spec.rb +++ b/spec/features/management/proposals_spec.rb @@ -16,9 +16,9 @@ feature 'Proposals' do within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s - expect(page).to have_content (user.email).to_s - expect(page).to have_content (user.document_number).to_s + expect(page).to have_content user.username.to_s + expect(page).to have_content user.email.to_s + expect(page).to have_content user.document_number.to_s end fill_in 'proposal_title', with: 'Help refugees' @@ -119,9 +119,9 @@ feature 'Proposals' do within(".account-info") do expect(page).to have_content "Identified as" - expect(page).to have_content (user.username).to_s - expect(page).to have_content (user.email).to_s - expect(page).to have_content (user.document_number).to_s + expect(page).to have_content user.username.to_s + expect(page).to have_content user.email.to_s + expect(page).to have_content user.document_number.to_s end within(".proposals-list") do diff --git a/spec/features/management/users_spec.rb b/spec/features/management/users_spec.rb index f50728bfc..8060f33cb 100644 --- a/spec/features/management/users_spec.rb +++ b/spec/features/management/users_spec.rb @@ -29,7 +29,7 @@ feature 'Users' do expect(user).to be_level_three_verified expect(user).to be_residence_verified expect(user).to_not be_confirmed - expect(user.date_of_birth).to have_content (Date.new(1980, 12, 31)) + expect(user.date_of_birth).to have_content Date.new(1980, 12, 31) sent_token = /.*confirmation_token=(.*)".*/.match(ActionMailer::Base.deliveries.last.body.to_s)[1] visit user_confirmation_path(confirmation_token: sent_token) @@ -69,7 +69,7 @@ feature 'Users' do expect(user).to be_level_three_verified expect(user).to be_residence_verified expect(user).to be_confirmed - expect(user.date_of_birth).to have_content (Date.new(1980, 12, 31)) + expect(user.date_of_birth).to have_content Date.new(1980, 12, 31) end scenario 'Delete a level 2 user account from document verification page', :js do diff --git a/spec/features/moderation_spec.rb b/spec/features/moderation_spec.rb index fedcb105d..ad4042425 100644 --- a/spec/features/moderation_spec.rb +++ b/spec/features/moderation_spec.rb @@ -11,7 +11,7 @@ feature 'Moderation' do visit moderation_root_path expect(current_path).not_to eq(moderation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -25,7 +25,7 @@ feature 'Moderation' do visit moderation_root_path expect(current_path).not_to eq(moderation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -39,7 +39,7 @@ feature 'Moderation' do visit moderation_root_path expect(current_path).not_to eq(moderation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -53,7 +53,7 @@ feature 'Moderation' do visit moderation_root_path expect(current_path).not_to eq(moderation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end diff --git a/spec/features/notifications_spec.rb b/spec/features/notifications_spec.rb index 7b044e18a..9925b0d56 100644 --- a/spec/features/notifications_spec.rb +++ b/spec/features/notifications_spec.rb @@ -15,16 +15,7 @@ feature "Notifications" do let(:legislation_annotation) { create(:legislation_annotation, author: author) } scenario "User commented on my debate", :js do - login_as user - visit debate_path debate - - fill_in "comment-body-debate_#{debate.id}", with: "I commented on your debate" - click_button "Publish comment" - within "#comments" do - expect(page).to have_content "I commented on your debate" - end - - logout + create(:notification, notifiable: debate, user: author) login_as author visit root_path @@ -37,17 +28,7 @@ feature "Notifications" do end scenario "User commented on my legislation question", :js do - verified_user = create(:user, :level_two) - login_as verified_user - visit legislation_process_question_path legislation_question.process, legislation_question - - fill_in "comment-body-legislation_question_#{legislation_question.id}", with: "I answered your question" - click_button "Publish answer" - within "#comments" do - expect(page).to have_content "I answered your question" - end - - logout + create(:notification, notifiable: legislation_question, user: administrator) login_as administrator visit root_path @@ -82,6 +63,7 @@ feature "Notifications" do logout login_as author visit root_path + visit root_path find(".icon-notification").click @@ -107,8 +89,10 @@ feature "Notifications" do end logout + login_as author visit root_path + visit root_path find(".icon-notification").click @@ -137,6 +121,7 @@ feature "Notifications" do login_as author visit root_path + visit root_path find(".icon-notification").click @@ -208,6 +193,7 @@ feature "Notifications" do logout login_as user1 visit root_path + visit root_path find(".icon-notification").click @@ -219,6 +205,7 @@ feature "Notifications" do logout login_as user2 visit root_path + visit root_path find(".icon-notification").click @@ -230,6 +217,7 @@ feature "Notifications" do logout login_as user3 visit root_path + visit root_path find(".icon-no-notification").click diff --git a/spec/features/officing/results_spec.rb b/spec/features/officing/results_spec.rb index 835903ab9..f7e1ad8ef 100644 --- a/spec/features/officing/results_spec.rb +++ b/spec/features/officing/results_spec.rb @@ -127,21 +127,13 @@ feature 'Officing Results' do date: @poll.ends_at, question: @question_1, amount: 33) - white_result = create(:poll_white_result, + poll_recount = create(:poll_recount, officer_assignment: @officer_assignment, booth_assignment: @officer_assignment.booth_assignment, date: @poll.ends_at, - amount: 21) - null_result = create(:poll_null_result, - officer_assignment: @officer_assignment, - booth_assignment: @officer_assignment.booth_assignment, - date: @poll.ends_at, - amount: 44) - total_result = create(:poll_total_result, - officer_assignment: @officer_assignment, - booth_assignment: @officer_assignment.booth_assignment, - date: @poll.ends_at, - amount: 66) + white_amount: 21, + null_amount: 44, + total_amount: 66) visit officing_poll_results_path(@poll, date: I18n.l(@poll.ends_at.to_date), diff --git a/spec/features/officing/voters_spec.rb b/spec/features/officing/voters_spec.rb index 0a23a6a27..2c4b17d37 100644 --- a/spec/features/officing/voters_spec.rb +++ b/spec/features/officing/voters_spec.rb @@ -2,16 +2,19 @@ require 'rails_helper' feature 'Voters' do + let(:poll) { create(:poll, :current) } + let(:booth) { create(:poll_booth) } let(:officer) { create(:poll_officer) } background do login_as(officer.user) create(:geozone, :in_census) + create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection) + booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth) + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment) end scenario "Can vote", :js do - poll = create(:poll_officer_assignment, officer: officer).booth_assignment.poll - visit new_officing_residence_path officing_verify_residence @@ -26,18 +29,21 @@ feature 'Voters' do page.evaluate_script("window.location.reload()") expect(page).to have_content "Has already participated in this poll" expect(page).to_not have_button "Confirm vote" + + expect(Poll::Voter.last.officer_id).to eq(officer.id) end scenario "Already voted", :js do - poll1 = create(:poll) - poll2 = create(:poll) + poll2 = create(:poll, :current) + booth_assignment = create(:poll_booth_assignment, poll: poll2, booth: booth) + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment) user = create(:user, :level_two) - voter = create(:poll_voter, poll: poll1, user: user) + voter = create(:poll_voter, poll: poll, user: user) visit new_officing_voter_path(id: voter.user.id) - within("#poll_#{poll1.id}") do + within("#poll_#{poll.id}") do expect(page).to have_content "Has already participated in this poll" expect(page).to_not have_button "Confirm vote" end @@ -50,7 +56,6 @@ feature 'Voters' do scenario "Had already verified his residence, but is not level 2 yet", :js do user = create(:user, residence_verified_at: Time.current, document_type: "1", document_number: "12345678Z") expect(user).to_not be_level_two_verified - poll = create(:poll_officer_assignment, officer: officer).booth_assignment.poll visit new_officing_residence_path officing_verify_residence @@ -59,6 +64,37 @@ feature 'Voters' do expect(page).to have_content poll.name end - #Fix and use answerable_by(user) - xscenario "Display only answerable polls" + scenario "Display only current polls on which officer has a voting shift today, and user can answer", :js do + poll_current = create(:poll, :current) + second_booth = create(:poll_booth) + booth_assignment = create(:poll_booth_assignment, poll: poll_current, booth: second_booth) + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment) + create(:poll_shift, officer: officer, booth: second_booth, date: Date.current, task: :recount_scrutiny) + create(:poll_shift, officer: officer, booth: second_booth, date: Date.tomorrow, task: :vote_collection) + + poll_expired = create(:poll, :expired) + create(:poll_officer_assignment, officer: officer, booth_assignment: create(:poll_booth_assignment, poll: poll_expired, booth: booth)) + + poll_incoming = create(:poll, :incoming) + create(:poll_officer_assignment, officer: officer, booth_assignment: create(:poll_booth_assignment, poll: poll_incoming, booth: booth)) + + poll_geozone_restricted_in = create(:poll, :current, geozone_restricted: true, geozones: [Geozone.first]) + booth_assignment = create(:poll_booth_assignment, poll: poll_geozone_restricted_in, booth: booth) + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment) + + poll_geozone_restricted_out = create(:poll, :current, geozone_restricted: true, geozones: [create(:geozone, census_code: "02")]) + booth_assignment = create(:poll_booth_assignment, poll: poll_geozone_restricted_out, booth: booth) + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment) + + visit new_officing_residence_path + officing_verify_residence + + expect(page).to have_content "Polls" + expect(page).to have_content poll.name + expect(page).not_to have_content poll_current.name + expect(page).not_to have_content poll_expired.name + expect(page).not_to have_content poll_incoming.name + expect(page).to have_content poll_geozone_restricted_in.name + expect(page).not_to have_content poll_geozone_restricted_out.name + end end diff --git a/spec/features/officing_spec.rb b/spec/features/officing_spec.rb index d4cb416a1..aff3eac4e 100644 --- a/spec/features/officing_spec.rb +++ b/spec/features/officing_spec.rb @@ -11,7 +11,7 @@ feature 'Poll Officing' do visit officing_root_path expect(current_path).not_to eq(officing_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -24,7 +24,7 @@ feature 'Poll Officing' do visit officing_root_path expect(current_path).not_to eq(officing_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -37,7 +37,7 @@ feature 'Poll Officing' do visit officing_root_path expect(current_path).not_to eq(officing_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -50,7 +50,7 @@ feature 'Poll Officing' do visit officing_root_path expect(current_path).not_to eq(officing_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end diff --git a/spec/features/polls/answers_spec.rb b/spec/features/polls/answers_spec.rb new file mode 100644 index 000000000..f7dfd4d38 --- /dev/null +++ b/spec/features/polls/answers_spec.rb @@ -0,0 +1,57 @@ +require 'rails_helper' + +feature 'Answers' do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario "Index" do + question = create(:poll_question) + answer1 = create(:poll_question_answer, question: question) + answer2 = create(:poll_question_answer, question: question) + + visit admin_question_path(question) + + expect(page).to have_css(".poll_question_answer", count: 2) + + within("#poll_question_answer_#{answer1.id}") do + expect(page).to have_content answer1.title + expect(page).to have_content answer1.description + end + end + + scenario "Create" do + question = create(:poll_question) + + visit admin_question_path(question) + + click_link "Add answer" + fill_in "poll_question_answer_title", with: "¿Would you like to reform Central Park?" + fill_in "poll_question_answer_description", with: "Adding more trees, creating a play area..." + click_button "Save" + + expect(page).to have_content "Answer created successfully" + + expect(page).to have_css(".poll_question_answer", count: 1) + expect(page).to have_content "¿Would you like to reform Central Park?" + expect(page).to have_content "Adding more trees, creating a play area..." + end + + pending "Update" + pending "Destroy" + + context "Gallery" do + + it_behaves_like "nested imageable", + "poll_question_answer", + "new_admin_answer_image_path", + { "answer_id": "id" }, + nil, + "Save image", + "Image uploaded successfully", + true + end + +end \ No newline at end of file diff --git a/spec/features/polls/polls_spec.rb b/spec/features/polls/polls_spec.rb index 047c71146..9fdb07255 100644 --- a/spec/features/polls/polls_spec.rb +++ b/spec/features/polls/polls_spec.rb @@ -6,11 +6,15 @@ feature 'Polls' do scenario 'Polls can be listed' do polls = create_list(:poll, 3) + create(:image, imageable: polls[0]) + create(:image, imageable: polls[1]) + create(:image, imageable: polls[2]) visit polls_path polls.each do |poll| expect(page).to have_content(poll.name) + expect(page).to have_css("img[alt='#{poll.image.title}']") expect(page).to have_link("Participate in this poll") end end @@ -59,7 +63,7 @@ feature 'Polls' do context 'Show' do let(:geozone) { create(:geozone) } - let(:poll) { create(:poll) } + let(:poll) { create(:poll, summary: "Summary", description: "Description") } scenario 'Lists questions from proposals as well as regular ones' do normal_question = create(:poll_question, poll: poll) @@ -67,13 +71,18 @@ feature 'Polls' do visit poll_path(poll) expect(page).to have_content(poll.name) + expect(page).to have_content(poll.summary) + expect(page).to have_content(poll.description) expect(page).to have_content(normal_question.title) expect(page).to have_content(proposal_question.title) end scenario 'Non-logged in users' do - create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') + visit poll_path(poll) expect(page).to have_content('Han Solo') @@ -85,9 +94,16 @@ feature 'Polls' do end scenario 'Level 1 users' do + visit polls_path + expect(page).to_not have_selector('.already-answer') + poll.update(geozone_restricted: true) poll.geozones << geozone - create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') + + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') + login_as(create(:user, geozone: geozone)) visit poll_path(poll) @@ -103,7 +119,11 @@ feature 'Polls' do scenario 'Level 2 users in an incoming poll' do incoming_poll = create(:poll, :incoming, geozone_restricted: true) incoming_poll.geozones << geozone - create(:poll_question, poll: incoming_poll, valid_answers: 'Rey, Finn') + + question = create(:poll_question, poll: incoming_poll) + answer1 = create(:poll_question_answer, question: question, title: 'Rey') + answer2 = create(:poll_question_answer, question: question, title: 'Finn') + login_as(create(:user, :level_two, geozone: geozone)) visit poll_path(incoming_poll) @@ -119,7 +139,11 @@ feature 'Polls' do scenario 'Level 2 users in an expired poll' do expired_poll = create(:poll, :expired, geozone_restricted: true) expired_poll.geozones << geozone - create(:poll_question, poll: expired_poll, valid_answers: 'Luke, Leia') + + question = create(:poll_question, poll: expired_poll) + answer1 = create(:poll_question_answer, question: question, title: 'Luke') + answer2 = create(:poll_question_answer, question: question, title: 'Leia') + login_as(create(:user, :level_two, geozone: geozone)) visit poll_path(expired_poll) @@ -135,7 +159,11 @@ feature 'Polls' do scenario 'Level 2 users in a poll with questions for a geozone which is not theirs' do poll.update(geozone_restricted: true) poll.geozones << create(:geozone) - create(:poll_question, poll: poll, valid_answers: 'Vader, Palpatine') + + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Vader') + answer2 = create(:poll_question_answer, question: question, title: 'Palpatine') + login_as(create(:user, :level_two)) visit poll_path(poll) @@ -149,7 +177,11 @@ feature 'Polls' do scenario 'Level 2 users reading a same-geozone poll' do poll.update(geozone_restricted: true) poll.geozones << geozone - create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') + + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') + login_as(create(:user, :level_two, geozone: geozone)) visit poll_path(poll) @@ -158,7 +190,10 @@ feature 'Polls' do end scenario 'Level 2 users reading a all-geozones poll' do - create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') + login_as(create(:user, :level_two)) visit poll_path(poll) @@ -167,7 +202,9 @@ feature 'Polls' do end scenario 'Level 2 users who have already answered' do - question = create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') user = create(:user, :level_two) create(:poll_answer, question: question, author: user, answer: 'Chewbacca') @@ -175,15 +212,19 @@ feature 'Polls' do visit poll_path(poll) expect(page).to have_link('Han Solo') - expect(page).to_not have_link('Chewbacca') - expect(page).to have_content('Chewbacca') + expect(page).to have_link('Chewbacca') end scenario 'Level 2 users answering', :js do poll.update(geozone_restricted: true) poll.geozones << geozone - create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') + + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') + user = create(:user, :level_two, geozone: geozone) + login_as user visit poll_path(poll) @@ -193,5 +234,103 @@ feature 'Polls' do expect(page).to have_link('Chewbacca') end + scenario 'Level 2 users changing answer', :js do + poll.update(geozone_restricted: true) + poll.geozones << geozone + + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') + + user = create(:user, :level_two, geozone: geozone) + + login_as user + visit poll_path(poll) + + click_link 'Han Solo' + + expect(page).to_not have_link('Han Solo') + expect(page).to have_link('Chewbacca') + + click_link 'Chewbacca' + + expect(page).to_not have_link('Chewbacca') + expect(page).to have_link('Han Solo') + end + + scenario 'Level 2 votes, signs out, signs in, votes again', :js do + poll.update(geozone_restricted: true) + poll.geozones << geozone + + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Han Solo') + answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca') + + user = create(:user, :level_two, geozone: geozone) + + login_as user + visit poll_path(poll) + click_link 'Han Solo' + + expect(page).to_not have_link('Han Solo') + expect(page).to have_link('Chewbacca') + + click_link "Sign out" + login_as user + visit poll_path(poll) + click_link 'Han Solo' + + expect(page).to_not have_link('Han Solo') + expect(page).to have_link('Chewbacca') + + click_link "Sign out" + login_as user + visit poll_path(poll) + click_link 'Chewbacca' + + expect(page).to_not have_link('Chewbacca') + expect(page).to have_link('Han Solo') + end + end + + context 'Booth & Website' do + + let(:poll) { create(:poll, summary: "Summary", description: "Description") } + let(:booth) { create(:poll_booth) } + let(:officer) { create(:poll_officer) } + + scenario 'Already voted on booth cannot vote on website', :js do + + create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection) + booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth) + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment) + question = create(:poll_question, poll: poll) + create(:poll_question_answer, question: question, title: 'Han Solo') + create(:poll_question_answer, question: question, title: 'Chewbacca') + user = create(:user, :level_two, :in_census) + + login_as(officer.user) + visit new_officing_residence_path + officing_verify_residence + click_button "Confirm vote" + + expect(page).to have_content "Vote introduced!" + + visit new_officing_residence_path + click_link "Sign out" + login_as user + visit poll_path(poll) + + expect(page).to have_content "You have already participated in a physical booth. You can not participate again." + + within("#poll_question_#{question.id}_answers") do + expect(page).to have_content('Han Solo') + expect(page).to have_content('Chewbacca') + + expect(page).to_not have_link('Han Solo') + expect(page).to_not have_link('Chewbacca') + end + end + end end diff --git a/spec/features/polls/questions_spec.rb b/spec/features/polls/questions_spec.rb index 1563ca81a..9e7efeedc 100644 --- a/spec/features/polls/questions_spec.rb +++ b/spec/features/polls/questions_spec.rb @@ -11,121 +11,4 @@ feature 'Poll Questions' do expect(proposal_question.title).to appear_before(normal_question.title) end - - scenario 'shows the author visible name instead of a link to the author' do - poll = create(:poll) - question_with_author = create(:poll_question, poll: poll) - question_with_author_visible_name = create(:poll_question, poll: poll, author_visible_name: 'potato') - - visit question_path(question_with_author) - expect(page).to have_link(question_with_author.author.name) - - visit question_path(question_with_author_visible_name) - expect(page).to_not have_link(question_with_author_visible_name.author.name) - expect(page).to have_content(question_with_author_visible_name.author_visible_name) - end - - scenario '#show view has video_url present' do - poll = create(:poll) - normal_question = create(:poll_question, poll: poll, video_url: "https://puppyvideos.com") - - visit question_path(normal_question) - - expect(page).to have_link(normal_question.video_url) - end - - scenario '#show view has document present' do - poll = create(:poll) - normal_question = create(:poll_question, poll: poll) - document = create(:document, documentable: normal_question) - - visit question_path(normal_question) - - expect(page).to have_content(document.title) - end - - context 'Answering' do - let(:geozone) { create(:geozone) } - let(:poll) { create(:poll, geozone_restricted: true, geozone_ids: [geozone.id]) } - - scenario 'Non-logged in users' do - question = create(:poll_question, valid_answers: 'Han Solo, Chewbacca') - - visit question_path(question) - - expect(page).to have_content('You must Sign in or Sign up to participate') - end - - scenario 'Level 1 users' do - question = create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') - - login_as(create(:user, geozone: geozone)) - visit question_path(question) - - expect(page).to have_content('You must verify your account in order to answer') - end - - scenario 'Level 2 users in an poll question for a geozone which is not theirs' do - - other_poll = create(:poll, geozone_restricted: true, geozone_ids: [create(:geozone).id]) - question = create(:poll_question, poll: other_poll, valid_answers: 'Vader, Palpatine') - - login_as(create(:user, :level_two, geozone: geozone)) - visit question_path(question) - - expect(page).to have_content('This question is not available on your geozone') - end - - scenario 'Level 2 users who can answer' do - question = create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') - - login_as(create(:user, :level_two, geozone: geozone)) - visit question_path(question) - - expect(page).to have_link('Answer this question') - end - - scenario 'Level 2 users who have already answered' do - question = create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') - - user = create(:user, :level_two, geozone: geozone) - create(:poll_answer, question: question, author: user, answer: 'Chewbacca') - - login_as user - visit question_path(question) - - expect(page).to have_link('Answer this question') - end - - scenario 'Level 2 users answering', :js do - question = create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') - user = create(:user, :level_two, geozone: geozone) - - login_as user - visit question_path(question) - - expect(page).to have_link('Answer this question') - end - - scenario 'Records participation', :js do - question = create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca') - user = create(:user, :level_two, geozone: geozone, gender: 'female', date_of_birth: 33.years.ago) - - login_as user - visit question_path(question) - - click_link 'Answer this question' - click_link 'Han Solo' - - expect(page).to_not have_link('Han Solo') - - voter = poll.voters.first - expect(voter.document_number).to eq(user.document_number) - expect(voter.geozone_id).to eq(user.geozone_id) - expect(voter.gender).to eq(user.gender) - expect(voter.age).to eq(33) - expect(voter.poll_id).to eq(poll.id) - end - - end end diff --git a/spec/features/polls/voter_spec.rb b/spec/features/polls/voter_spec.rb new file mode 100644 index 000000000..256807928 --- /dev/null +++ b/spec/features/polls/voter_spec.rb @@ -0,0 +1,131 @@ +require 'rails_helper' + +feature "Voter" do + + context "Origin" do + + let(:poll) { create(:poll, :current) } + let(:booth) { create(:poll_booth) } + let(:officer) { create(:poll_officer) } + + background do + create(:geozone, :in_census) + create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection) + booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth) + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment) + end + + scenario "Voting via web - Standard", :js do + poll = create(:poll) + + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, question: question, title: 'Yes') + answer2 = create(:poll_question_answer, question: question, title: 'No') + + user = create(:user, :level_two) + + login_as user + visit poll_path(poll) + + within("#poll_question_#{question.id}_answers") do + click_link 'Yes' + expect(page).to_not have_link('Yes') + end + + find(:css, ".js-token-message").should be_visible + token = find(:css, ".js-question-answer")[:href].gsub(/.+?(?=token)/, '').gsub('token=', '') + + expect(page).to have_content "You can write down this vote identifier, to check your vote on the final results: #{token}" + + expect(Poll::Voter.count).to eq(1) + expect(Poll::Voter.first.origin).to eq("web") + end + + scenario "Voting in booth", :js do + user = create(:user, :in_census) + + login_through_form_as_officer(officer.user) + + visit new_officing_residence_path + officing_verify_residence + + expect(page).to have_content poll.name + + first(:button, "Confirm vote").click + expect(page).to have_content "Vote introduced!" + + expect(Poll::Voter.count).to eq(1) + expect(Poll::Voter.first.origin).to eq("booth") + end + + context "Trying to vote the same poll in booth and web" do + + let(:poll) { create(:poll) } + + let(:question) { create(:poll_question, poll: poll) } + let!(:answer1) { create(:poll_question_answer, question: question, title: 'Yes') } + let!(:answer2) { create(:poll_question_answer, question: question, title: 'No') } + + let!(:user) { create(:user, :in_census) } + + scenario "Trying to vote in web and then in booth", :js do + login_as user + vote_for_poll_via_web(poll, question) + + click_link "Sign out" + + login_through_form_as_officer(officer.user) + + visit new_officing_residence_path + officing_verify_residence + + expect(page).to have_content poll.name + expect(page).to_not have_button "Confirm vote" + expect(page).to have_content "Has already participated in this poll" + end + + scenario "Trying to vote in booth and then in web", :js do + login_through_form_as_officer(officer.user) + + vote_for_poll_via_booth + + visit root_path + click_link "Sign out" + + login_as user + visit poll_path(poll) + + expect(page).to_not have_link('Yes') + expect(page).to have_content "You have already participated in a physical booth. You can not participate again." + expect(Poll::Voter.count).to eq(1) + end + + scenario "Trying to vote in web again", :js do + login_as user + vote_for_poll_via_web(poll, question) + + visit poll_path(poll) + + expect(page).to_not have_selector('.js-token-message') + + expect(page).to have_content "You have already participated in this poll. If you vote again it will be overwritten." + within("#poll_question_#{question.id}_answers") do + expect(page).to_not have_link('Yes') + end + + click_link "Sign out" + + login_as user + visit poll_path(poll) + + within("#poll_question_#{question.id}_answers") do + expect(page).to have_link('Yes') + expect(page).to have_link('No') + end + + end + end + + end + +end diff --git a/spec/features/proposal_notifications_spec.rb b/spec/features/proposal_notifications_spec.rb index 4756a1903..1e93f7e13 100644 --- a/spec/features/proposal_notifications_spec.rb +++ b/spec/features/proposal_notifications_spec.rb @@ -189,7 +189,7 @@ feature 'Proposal Notifications' do login_as(user) visit new_proposal_notification_path(proposal_id: proposal.id) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content("You do not have permission to carry out the action") end diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index d297a294b..81f7fb998 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -45,6 +45,22 @@ feature 'Proposals' do expect(page).to have_selector('#proposals .proposal', count: 2) end + + scenario 'Index should show proposal descriptive image only when is defined' do + featured_proposals = create_featured_proposals + proposal = create(:proposal) + proposal_with_image = create(:proposal) + image = create(:image, imageable: proposal_with_image) + + visit proposals_path(proposal) + + within("#proposal_#{proposal.id}") do + expect(page).to have_css("div.no-image") + end + within("#proposal_#{proposal_with_image.id}") do + expect(page).to have_css("img[alt='#{proposal_with_image.image.title}']") + end + end end scenario 'Show' do @@ -540,7 +556,7 @@ feature 'Proposals' do visit edit_proposal_path(proposal) expect(current_path).not_to eq(edit_proposal_path(proposal)) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content 'You do not have permission' end @@ -555,7 +571,7 @@ feature 'Proposals' do visit edit_proposal_path(proposal) expect(current_path).not_to eq(edit_proposal_path(proposal)) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content 'You do not have permission' Setting["max_votes_for_proposal_edit"] = 1000 end @@ -647,6 +663,69 @@ feature 'Proposals' do expect(current_url).to include('order=created_at') expect(current_url).to include('page=1') end + + context 'Recommendations' do + + before do + Setting['feature.user.recommendations'] = true + create(:proposal, title: 'Best', cached_votes_up: 10, tag_list: "Sport") + create(:proposal, title: 'Medium', cached_votes_up: 5, tag_list: "Sport") + create(:proposal, title: 'Worst', cached_votes_up: 1, tag_list: "Sport") + end + + after do + Setting['feature.user.recommendations'] = nil + end + + scenario 'Proposals can not ordered by recommendations when there is not an user logged', :js do + visit proposals_path + + expect(page).not_to have_selector('a', text: 'recommendations') + end + + scenario 'Should display text when there are not recommendeds results', :js do + user = create(:user) + proposal = create(:proposal, tag_list: "Distinct_to_sport") + create(:follow, followable: proposal, user: user) + login_as(user) + visit proposals_path + + click_link 'recommendations' + + expect(page).to have_content "There are not proposals related to your interests" + end + + scenario 'Should display text when user has not related interests', :js do + user = create(:user) + login_as(user) + visit proposals_path + + click_link 'recommendations' + + expect(page).to have_content "Follow proposals so we can give you recommendations" + end + + scenario 'Proposals are ordered by recommendations when there is an user logged', :js do + user = create(:user) + proposal = create(:proposal, tag_list: "Sport") + create(:follow, followable: proposal, user: user) + login_as(user) + + visit proposals_path + + click_link 'recommendations' + + expect(page).to have_selector('a.active', text: 'recommendations') + + within '#proposals-list' do + expect('Best').to appear_before('Medium') + expect('Medium').to appear_before('Worst') + end + + expect(current_url).to include('order=recommendations') + expect(current_url).to include('page=1') + end + end end feature 'Archived proposals' do @@ -1182,6 +1261,32 @@ feature 'Proposals' do end end + scenario "Reorder by recommendations results maintaing search", :js do + Setting['feature.user.recommendations'] = true + user = create(:user) + login_as(user) + proposal1 = create(:proposal, title: "Show you got", cached_votes_up: 10, tag_list: "Sport") + proposal2 = create(:proposal, title: "Show what you got", cached_votes_up: 1, tag_list: "Sport") + proposal3 = create(:proposal, title: "Do not display with same tag", cached_votes_up: 100, tag_list: "Sport") + proposal4 = create(:proposal, title: "Do not display", cached_votes_up: 1) + proposal5 = create(:proposal, tag_list: "Sport") + create(:follow, followable: proposal5, user: user) + + visit proposals_path + fill_in "search", with: "Show you got" + click_button "Search" + click_link 'recommendations' + expect(page).to have_selector("a.active", text: "recommendations") + + within("#proposals") do + expect(all(".proposal")[0].text).to match "Show you got" + expect(all(".proposal")[1].text).to match "Show what you got" + expect(page).to_not have_content "Do not display with same tag" + expect(page).to_not have_content "Do not display" + end + Setting['feature.user.recommendations'] = nil + end + scenario 'After a search do not show featured proposals' do featured_proposals = create_featured_proposals proposal = create(:proposal, title: "Abcdefghi") @@ -1274,17 +1379,17 @@ feature 'Proposals' do it_behaves_like "followable", "proposal", "proposal_path", { "id": "id" } - it_behaves_like "documentable", "proposal", "proposal_path", { "id": "id" } + it_behaves_like "imageable", "proposal", "proposal_path", { "id": "id" } - it_behaves_like "nested documentable", + it_behaves_like "nested imageable", "proposal", "new_proposal_path", { }, - "fill_new_valid_proposal", + "imageable_fill_new_valid_proposal", "Create proposal", "Proposal created successfully" - it_behaves_like "nested documentable", + it_behaves_like "nested imageable", "proposal", "edit_proposal_path", { "id": "id" }, @@ -1292,6 +1397,34 @@ feature 'Proposals' do "Save changes", "Proposal updated successfully" + it_behaves_like "documentable", "proposal", "proposal_path", { "id": "id" } + + it_behaves_like "nested documentable", + "user", + "proposal", + "new_proposal_path", + { }, + "documentable_fill_new_valid_proposal", + "Create proposal", + "Proposal created successfully" + + it_behaves_like "nested documentable", + "user", + "proposal", + "edit_proposal_path", + { "id": "id" }, + nil, + "Save changes", + "Proposal updated successfully" + + it_behaves_like "mappable", + "proposal", + "proposal", + "new_proposal_path", + "edit_proposal_path", + "proposal_path", + { } + scenario 'Erased author' do user = create(:user) proposal = create(:proposal, author: user) @@ -1390,7 +1523,7 @@ feature 'Proposals' do check "proposal_terms_of_service" within('div#js-suggest') do - expect(page).to have_content ("You are seeing 5 of 6 proposals containing the term 'search'") + expect(page).to have_content "You are seeing 5 of 6 proposals containing the term 'search'" end end @@ -1406,7 +1539,7 @@ feature 'Proposals' do check "proposal_terms_of_service" within('div#js-suggest') do - expect(page).to_not have_content ('You are seeing') + expect(page).to_not have_content 'You are seeing' end end end diff --git a/spec/features/valuation/budget_investments_spec.rb b/spec/features/valuation/budget_investments_spec.rb index 3f91d8925..a627d9422 100644 --- a/spec/features/valuation/budget_investments_spec.rb +++ b/spec/features/valuation/budget_investments_spec.rb @@ -271,20 +271,20 @@ feature 'Valuation budget investments' do visit valuation_budget_budget_investment_path(@budget, @investment) click_link 'Edit dossier' - expect(find "#budget_investment_feasibility_undecided").to be_checked + expect(find("#budget_investment_feasibility_undecided")).to be_checked choose 'budget_investment_feasibility_feasible' click_button 'Save changes' visit edit_valuation_budget_budget_investment_path(@budget, @investment) - expect(find "#budget_investment_feasibility_undecided").to_not be_checked - expect(find "#budget_investment_feasibility_feasible").to be_checked + expect(find("#budget_investment_feasibility_undecided")).to_not be_checked + expect(find("#budget_investment_feasibility_feasible")).to be_checked choose 'budget_investment_feasibility_undecided' click_button 'Save changes' visit edit_valuation_budget_budget_investment_path(@budget, @investment) - expect(find "#budget_investment_feasibility_undecided").to be_checked + expect(find("#budget_investment_feasibility_undecided")).to be_checked end scenario 'Feasibility selection makes proper fields visible', :js do @@ -295,7 +295,7 @@ feature 'Valuation budget investments' do visit edit_valuation_budget_budget_investment_path(@budget, @investment) - expect(find "#budget_investment_feasibility_undecided").to be_checked + expect(find("#budget_investment_feasibility_undecided")).to be_checked undecided_fields.each do |field| expect(page).to have_content(field) @@ -325,7 +325,7 @@ feature 'Valuation budget investments' do visit edit_valuation_budget_budget_investment_path(@budget, @investment) - expect(find "#budget_investment_feasibility_unfeasible").to be_checked + expect(find("#budget_investment_feasibility_unfeasible")).to be_checked feasible_fields.each do |field| expect(page).to_not have_content(field) end diff --git a/spec/features/valuation_spec.rb b/spec/features/valuation_spec.rb index 5b6cc961c..9e74d9341 100644 --- a/spec/features/valuation_spec.rb +++ b/spec/features/valuation_spec.rb @@ -21,7 +21,7 @@ feature 'Valuation' do visit valuation_root_path expect(current_path).not_to eq(valuation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -34,7 +34,7 @@ feature 'Valuation' do visit valuation_root_path expect(current_path).not_to eq(valuation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -47,7 +47,7 @@ feature 'Valuation' do visit valuation_root_path expect(current_path).not_to eq(valuation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end @@ -60,7 +60,7 @@ feature 'Valuation' do visit valuation_root_path expect(current_path).not_to eq(valuation_root_path) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) expect(page).to have_content "You do not have permission to access this page" end diff --git a/spec/features/welcome_spec.rb b/spec/features/welcome_spec.rb index ce06befcc..245a9923e 100644 --- a/spec/features/welcome_spec.rb +++ b/spec/features/welcome_spec.rb @@ -33,7 +33,7 @@ feature "Welcome screen" do login_through_form_as(user) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) end scenario 'is not shown to organizations' do @@ -41,7 +41,7 @@ feature "Welcome screen" do login_through_form_as(organization.user) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) end scenario 'it is not shown to level-2 users' do @@ -49,7 +49,7 @@ feature "Welcome screen" do login_through_form_as(user) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) end scenario 'it is not shown to level-3 users' do @@ -57,7 +57,7 @@ feature "Welcome screen" do login_through_form_as(user) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) end scenario 'is not shown to administrators' do @@ -65,7 +65,7 @@ feature "Welcome screen" do login_through_form_as(administrator.user) - expect(current_path).to eq(proposals_path) + expect(current_path).to eq(root_path) end end diff --git a/spec/fixtures/files/clippy.gif b/spec/fixtures/files/clippy.gif new file mode 100644 index 000000000..c2c2278af Binary files /dev/null and b/spec/fixtures/files/clippy.gif differ diff --git a/spec/fixtures/files/clippy.jpeg b/spec/fixtures/files/clippy.jpeg new file mode 100644 index 000000000..1edb6659b Binary files /dev/null and b/spec/fixtures/files/clippy.jpeg differ diff --git a/spec/fixtures/files/clippy.jpg b/spec/fixtures/files/clippy.jpg new file mode 100644 index 000000000..1edb6659b Binary files /dev/null and b/spec/fixtures/files/clippy.jpg differ diff --git a/spec/fixtures/files/clippy.png b/spec/fixtures/files/clippy.png new file mode 100644 index 000000000..44e09b4e3 Binary files /dev/null and b/spec/fixtures/files/clippy.png differ diff --git a/spec/fixtures/files/logo_header.gif b/spec/fixtures/files/logo_header.gif new file mode 100644 index 000000000..4bfddd410 Binary files /dev/null and b/spec/fixtures/files/logo_header.gif differ diff --git a/spec/fixtures/files/logo_header.jpg b/spec/fixtures/files/logo_header.jpg new file mode 100644 index 000000000..aeed9e524 Binary files /dev/null and b/spec/fixtures/files/logo_header.jpg differ diff --git a/spec/helpers/comments_helper_spec.rb b/spec/helpers/comments_helper_spec.rb index b1caabe53..040903c96 100644 --- a/spec/helpers/comments_helper_spec.rb +++ b/spec/helpers/comments_helper_spec.rb @@ -14,7 +14,7 @@ RSpec.describe CommentsHelper, type: :helper do describe '#user_level_class' do - def comment_double as_administrator: false, as_moderator: false, official: false + def comment_double(as_administrator: false, as_moderator: false, official: false) user = double official?: official, official_level: 'Y' double as_administrator?: as_administrator, as_moderator?: as_moderator, user: user end diff --git a/spec/helpers/settings_helper_spec.rb b/spec/helpers/settings_helper_spec.rb index 0aa9b8541..0db6fed10 100644 --- a/spec/helpers/settings_helper_spec.rb +++ b/spec/helpers/settings_helper_spec.rb @@ -21,10 +21,10 @@ RSpec.describe SettingsHelper, type: :helper do Setting["feature.f2"] = "" Setting["feature.f3"] = nil - expect(feature? "f1").to eq("active") - expect(feature? "f2").to eq(nil) - expect(feature? "f3").to eq(nil) - expect(feature? "f4").to eq(nil) + expect(feature?("f1")).to eq("active") + expect(feature?("f2")).to eq(nil) + expect(feature?("f3")).to eq(nil) + expect(feature?("f4")).to eq(nil) end end diff --git a/spec/helpers/verification_helper_spec.rb b/spec/helpers/verification_helper_spec.rb index 1673264f7..43df6509f 100644 --- a/spec/helpers/verification_helper_spec.rb +++ b/spec/helpers/verification_helper_spec.rb @@ -4,20 +4,20 @@ describe VerificationHelper do describe "#mask_phone" do it "should mask a phone" do - expect(mask_phone "612345678").to eq("******678") + expect(mask_phone("612345678")).to eq("******678") end end describe "#mask_email" do it "should mask a long email address" do - expect(mask_email "isabel@example.com").to eq("isa***@example.com") - expect(mask_email "antonio.perez@example.com").to eq("ant**********@example.com") + expect(mask_email("isabel@example.com")).to eq("isa***@example.com") + expect(mask_email("antonio.perez@example.com")).to eq("ant**********@example.com") end it "should mask a short email address" do - expect(mask_email "an@example.com").to eq("an@example.com") - expect(mask_email "ana@example.com").to eq("ana@example.com") - expect(mask_email "aina@example.com").to eq("ain*@example.com") + expect(mask_email("an@example.com")).to eq("an@example.com") + expect(mask_email("ana@example.com")).to eq("ana@example.com") + expect(mask_email("aina@example.com")).to eq("ain*@example.com") end end diff --git a/spec/lib/acts_as_taggable_on_spec.rb b/spec/lib/acts_as_taggable_on_spec.rb index 761e90553..de53b35e7 100644 --- a/spec/lib/acts_as_taggable_on_spec.rb +++ b/spec/lib/acts_as_taggable_on_spec.rb @@ -133,6 +133,21 @@ describe 'ActsAsTaggableOn' do expect(ActsAsTaggableOn::Tag.public_for_api).to be_empty end end + + describe "search" do + it "containing the word in the name" do + create(:tag, name: 'Familia') + create(:tag, name: 'Cultura') + create(:tag, name: 'Salud') + create(:tag, name: 'Famosos') + + expect(ActsAsTaggableOn::Tag.pg_search('f').length).to eq(2) + expect(ActsAsTaggableOn::Tag.search('cultura').first.name).to eq('Cultura') + expect(ActsAsTaggableOn::Tag.search('sal').first.name).to eq('Salud') + expect(ActsAsTaggableOn::Tag.search('fami').first.name).to eq('Familia') + end + end + end end diff --git a/spec/models/abilities/administrator_spec.rb b/spec/models/abilities/administrator_spec.rb index dcb099ecd..0934c7cfe 100644 --- a/spec/models/abilities/administrator_spec.rb +++ b/spec/models/abilities/administrator_spec.rb @@ -20,6 +20,9 @@ describe "Abilities::Administrator" do let(:budget_investment_document) { build(:document, documentable: budget_investment) } let(:poll_question_document) { build(:document, documentable: poll_question) } + let(:proposal_image) { build(:image, imageable: proposal) } + let(:budget_investment_image) { build(:image, imageable: budget_investment) } + let(:hidden_debate) { create(:debate, :hidden) } let(:hidden_comment) { create(:comment, :hidden) } let(:hidden_proposal) { create(:proposal, :hidden) } @@ -69,6 +72,7 @@ describe "Abilities::Administrator" do it { should be_able_to(:create, Budget) } it { should be_able_to(:update, Budget) } + it { should be_able_to(:read_results, Budget) } it { should be_able_to(:create, Budget::ValuatorAssignment) } @@ -78,15 +82,11 @@ describe "Abilities::Administrator" do it { should be_able_to(:valuate, create(:budget_investment, budget: create(:budget, phase: 'valuating'))) } it { should be_able_to(:valuate, create(:budget_investment, budget: create(:budget, phase: 'finished'))) } - it { should be_able_to(:new, proposal_document) } - it { should be_able_to(:create, proposal_document) } it { should be_able_to(:destroy, proposal_document) } - - it { should be_able_to(:new, budget_investment_document) } - it { should be_able_to(:create, budget_investment_document) } it { should be_able_to(:destroy, budget_investment_document) } - - it { should be_able_to(:new, poll_question_document) } - it { should be_able_to(:create, poll_question_document) } it { should be_able_to(:destroy, poll_question_document) } + + it { should be_able_to(:destroy, proposal_image) } + it { should be_able_to(:destroy, budget_investment_image) } + end diff --git a/spec/models/abilities/common_spec.rb b/spec/models/abilities/common_spec.rb index dfaac3598..7f936cfcf 100644 --- a/spec/models/abilities/common_spec.rb +++ b/spec/models/abilities/common_spec.rb @@ -59,6 +59,11 @@ describe "Abilities::Common" do let(:own_budget_investment_document) { build(:document, documentable: own_investment_in_accepting_budget) } let(:budget_investment_document) { build(:document, documentable: investment_in_accepting_budget) } + let(:own_proposal_image) { build(:image, imageable: own_proposal) } + let(:proposal_image) { build(:image, imageable: proposal) } + let(:own_budget_investment_image) { build(:image, imageable: own_investment_in_accepting_budget) } + let(:budget_investment_image) { build(:image, imageable: investment_in_accepting_budget) } + it { should be_able_to(:index, Debate) } it { should be_able_to(:show, debate) } it { should be_able_to(:vote, debate) } @@ -87,25 +92,18 @@ describe "Abilities::Common" do it { should_not be_able_to(:create, DirectMessage) } it { should_not be_able_to(:show, DirectMessage) } - it { should be_able_to(:new_nested, Document) } - it { should be_able_to(:destroy_upload, Document) } - - it { should be_able_to(:new, own_proposal_document) } - it { should be_able_to(:create, own_proposal_document) } it { should be_able_to(:destroy, own_proposal_document) } - - it { should_not be_able_to(:new, proposal_document) } - it { should_not be_able_to(:create, proposal_document) } it { should_not be_able_to(:destroy, proposal_document) } - it { should be_able_to(:new, own_budget_investment_document) } - it { should be_able_to(:create, own_budget_investment_document) } it { should be_able_to(:destroy, own_budget_investment_document) } - - it { should_not be_able_to(:new, budget_investment_document) } - it { should_not be_able_to(:create, budget_investment_document) } it { should_not be_able_to(:destroy, budget_investment_document) } + it { should be_able_to(:destroy, own_proposal_image) } + it { should_not be_able_to(:destroy, proposal_image) } + + it { should be_able_to(:destroy, own_budget_investment_image) } + it { should_not be_able_to(:destroy, budget_investment_image) } + describe 'flagging content' do it { should be_able_to(:flag, debate) } it { should be_able_to(:unflag, debate) } diff --git a/spec/models/abilities/everyone_spec.rb b/spec/models/abilities/everyone_spec.rb index fcfff4e42..21568c999 100644 --- a/spec/models/abilities/everyone_spec.rb +++ b/spec/models/abilities/everyone_spec.rb @@ -8,6 +8,9 @@ describe "Abilities::Everyone" do let(:debate) { create(:debate) } let(:proposal) { create(:proposal) } + let(:reviewing_ballot_budget) { create(:budget, phase: 'reviewing_ballots') } + let(:finished_budget) { create(:budget, phase: 'finished') } + it { should be_able_to(:index, Debate) } it { should be_able_to(:show, debate) } it { should_not be_able_to(:edit, Debate) } @@ -28,4 +31,7 @@ describe "Abilities::Everyone" do it { should_not be_able_to(:create, SpendingProposal) } it { should be_able_to(:index, Budget) } -end \ No newline at end of file + + it { should be_able_to(:read_results, finished_budget) } + it { should_not be_able_to(:read_results, reviewing_ballot_budget) } +end diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index c363f3bdc..f11c4916b 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -29,6 +29,8 @@ describe Budget::Investment do end end + it_behaves_like "acts as imageable", "budget_investment_image" + it "sanitizes description" do investment.description = "" investment.valid? @@ -103,7 +105,7 @@ describe Budget::Investment do let(:investment) { create(:budget_investment) } it "returns the proposal id" do - expect(investment.code).to include((investment.id).to_s) + expect(investment.code).to include(investment.id.to_s) end it "returns the administrator id when assigned" do @@ -393,7 +395,7 @@ describe Budget::Investment do investment2 = create(:budget_investment, :feasible, budget: budget) investment3 = create(:budget_investment, :unfeasible, budget: budget) - results = Budget::Investment::apply_filters_and_search(budget, {}, :feasible) + results = Budget::Investment.apply_filters_and_search(budget, {}, :feasible) expect(results).to include investment1 expect(results).to include investment2 @@ -405,7 +407,7 @@ describe Budget::Investment do investment2 = create(:budget_investment, :unfeasible, budget: budget) investment3 = create(:budget_investment, :feasible, budget: budget) - results = Budget::Investment::apply_filters_and_search(budget, {}, :unfeasible) + results = Budget::Investment.apply_filters_and_search(budget, {}, :unfeasible) expect(results).to include investment1 expect(results).to include investment2 @@ -419,7 +421,7 @@ describe Budget::Investment do investment2 = create(:budget_investment, :feasible, :selected, budget: budget) investment3 = create(:budget_investment, :feasible, :unselected, budget: budget) - results = Budget::Investment::apply_filters_and_search(budget, {}, :selected) + results = Budget::Investment.apply_filters_and_search(budget, {}, :selected) expect(results).to include investment1 expect(results).to include investment2 @@ -433,7 +435,7 @@ describe Budget::Investment do investment2 = create(:budget_investment, :feasible, :unselected, budget: budget) investment3 = create(:budget_investment, :feasible, :selected, budget: budget) - results = Budget::Investment::apply_filters_and_search(budget, {}, :unselected) + results = Budget::Investment.apply_filters_and_search(budget, {}, :unselected) expect(results).to include investment1 expect(results).to include investment2 @@ -450,7 +452,7 @@ describe Budget::Investment do investment2 = create(:budget_investment, heading: heading1, budget: budget) investment3 = create(:budget_investment, heading: heading2, budget: budget) - results = Budget::Investment::apply_filters_and_search(budget, heading_id: heading1.id) + results = Budget::Investment.apply_filters_and_search(budget, heading_id: heading1.id) expect(results).to include investment1 expect(results).to include investment2 @@ -462,7 +464,7 @@ describe Budget::Investment do investment2 = create(:budget_investment, title: "improved health", budget: budget) investment3 = create(:budget_investment, title: "finance", budget: budget) - results = Budget::Investment::apply_filters_and_search(budget, search: "health") + results = Budget::Investment.apply_filters_and_search(budget, search: "health") expect(results).to include investment1 expect(results).to include investment2 diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 8d24f9945..64dbf729f 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -687,12 +687,12 @@ describe Debate do describe "#last_week" do it "should return debates created this week" do debate = create(:debate) - expect(Debate.last_week.all).to include (debate) + expect(Debate.last_week.all).to include debate end it "should not show debates created more than a week ago" do debate = create(:debate, created_at: 8.days.ago) - expect(Debate.last_week.all).to_not include (debate) + expect(Debate.last_week.all).to_not include debate end end @@ -714,4 +714,53 @@ describe Debate do end end + describe "#recommendations" do + + let(:user) { create(:user) } + + it "Should not return any debates when user has not interests" do + create(:debate) + + expect(Debate.recommendations(user).size).to eq 0 + end + + it "Should return debates ordered by cached_votes_total" do + debate1 = create(:debate, cached_votes_total: 1, tag_list: "Sport" ) + debate2 = create(:debate, cached_votes_total: 5, tag_list: "Sport" ) + debate3 = create(:debate, cached_votes_total: 10, tag_list: "Sport" ) + proposal = create(:proposal, tag_list: "Sport" ) + create(:follow, followable: proposal, user: user) + + result = Debate.recommendations(user).sort_by_recommendations + + expect(result.first).to eq debate3 + expect(result.second).to eq debate2 + expect(result.third).to eq debate1 + end + + it "Should return debates related with user interests" do + debate1 = create(:debate, tag_list: "Sport") + debate2 = create(:debate, tag_list: "Politics") + proposal1 = create(:proposal, tag_list: "Sport") + create(:follow, followable: proposal1, user: user) + + result = Debate.recommendations(user) + + expect(result.size).to eq 1 + expect(result).to eq [debate1] + end + + it "Should not return debates when user is the author" do + debate1 = create(:debate, author: user, tag_list: "Sport") + debate2 = create(:debate, tag_list: "Sport") + proposal = create(:proposal, tag_list: "Sport" ) + create(:follow, followable: proposal, user: user) + + result = Debate.recommendations(user) + + expect(result.size).to eq 1 + expect(result).to eq [debate2] + end + + end end diff --git a/spec/models/direct_upload_spec.rb b/spec/models/direct_upload_spec.rb new file mode 100644 index 000000000..5abe06765 --- /dev/null +++ b/spec/models/direct_upload_spec.rb @@ -0,0 +1,65 @@ +require 'rails_helper' + +describe DirectUpload do + + context "configurations" do + + it "should be valid for different kind of combinations when attachment is valid" do + expect(build(:direct_upload, :proposal, :documents)).to be_valid + expect(build(:direct_upload, :proposal, :image)).to be_valid + expect(build(:direct_upload, :budget_investment, :documents)).to be_valid + expect(build(:direct_upload, :budget_investment, :image)).to be_valid + end + + it "should not be valid for different kind of combinations with invalid atttachment content types" do + expect(build(:direct_upload, :proposal, :documents, attachment: File.new("spec/fixtures/files/clippy.png"))).not_to be_valid + expect(build(:direct_upload, :proposal, :image, attachment: File.new("spec/fixtures/files/empty.pdf"))).not_to be_valid + expect(build(:direct_upload, :budget_investment, :documents, attachment: File.new("spec/fixtures/files/clippy.png"))).not_to be_valid + expect(build(:direct_upload, :budget_investment, :image, attachment: File.new("spec/fixtures/files/empty.pdf"))).not_to be_valid + end + + it "should not be valid without resource_type" do + expect(build(:direct_upload, :proposal, :documents, resource_type: nil)).not_to be_valid + end + + it "should not be valid without resource_relation" do + expect(build(:direct_upload, :proposal, :documents, resource_relation: nil)).not_to be_valid + end + + it "should not be valid without attachment" do + expect(build(:direct_upload, :proposal, :documents, attachment: nil)).not_to be_valid + end + + it "should not be valid without user" do + expect(build(:direct_upload, :proposal, :documents, user: nil)).not_to be_valid + end + end + + context "save_attachment" do + + it "should save uploaded file" do + proposal_document_direct_upload = build(:direct_upload, :proposal, :documents) + + proposal_document_direct_upload.save_attachment + + expect(File.exists?(proposal_document_direct_upload.relation.attachment.path)).to eq(true) + expect(proposal_document_direct_upload.relation.attachment.path).to include('cached_attachments') + end + + end + + context "destroy_attachment" do + + it "should remove uploaded file" do + proposal_document_direct_upload = build(:direct_upload, :proposal, :documents) + + proposal_document_direct_upload.save_attachment + uploaded_path = proposal_document_direct_upload.relation.attachment.path + proposal_document_direct_upload.destroy_attachment + + expect(File.exists?(uploaded_path)).to eq(false) + end + + end + +end \ No newline at end of file diff --git a/spec/models/image_spec.rb b/spec/models/image_spec.rb new file mode 100644 index 000000000..cf19257cd --- /dev/null +++ b/spec/models/image_spec.rb @@ -0,0 +1,8 @@ +require 'rails_helper' + +describe Image do + + it_behaves_like "image validations", "budget_investment_image" + it_behaves_like "image validations", "proposal_image" + +end diff --git a/spec/models/map_location_spec.rb b/spec/models/map_location_spec.rb new file mode 100644 index 000000000..bd093a71e --- /dev/null +++ b/spec/models/map_location_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +describe MapLocation do + + let(:map_location) { build(:map_location, :proposal_map_location ) } + + it "should be valid" do + expect(map_location).to be_valid + end + + context "#available?" do + + it "should return true when latitude, longitude and zoom defined" do + expect(map_location.available?).to be(true) + end + + it "should return false when longitude is nil" do + map_location.longitude = nil + + expect(map_location.available?).to be(false) + end + + it "should return false when latitude is nil" do + map_location.latitude = nil + + expect(map_location.available?).to be(false) + end + + it "should return false when zoom is nil" do + map_location.zoom = nil + + expect(map_location.available?).to be(false) + end + end + +end diff --git a/spec/models/poll/answer_spec.rb b/spec/models/poll/answer_spec.rb index 10ccafbb6..8731445cc 100644 --- a/spec/models/poll/answer_spec.rb +++ b/spec/models/poll/answer_spec.rb @@ -3,27 +3,72 @@ require 'rails_helper' describe Poll::Answer do describe "validations" do - it "validates that the answers are included in the Poll::Question's list" do - q = create(:poll_question, valid_answers: 'One, Two, Three') - expect(build(:poll_answer, question: q, answer: 'One')).to be_valid - expect(build(:poll_answer, question: q, answer: 'Two')).to be_valid - expect(build(:poll_answer, question: q, answer: 'Three')).to be_valid - expect(build(:poll_answer, question: q, answer: 'Four')).to_not be_valid + let(:answer) { build(:poll_answer) } + + it "should be valid" do + expect(answer).to be_valid + end + + it "should not be valid wihout a question" do + answer.question = nil + expect(answer).to_not be_valid + end + + it "should not be valid without an author" do + answer.author = nil + expect(answer).to_not be_valid + end + + it "should not be valid without an answer" do + answer.answer = nil + expect(answer).to_not be_valid + end + + it "should be valid for answers included in the Poll::Question's list" do + skip "review when removing valid_answers" + question = create(:poll_question, valid_answers: 'One, Two, Three') + expect(build(:poll_answer, question: question, answer: 'One')).to be_valid + expect(build(:poll_answer, question: question, answer: 'Two')).to be_valid + expect(build(:poll_answer, question: question, answer: 'Three')).to be_valid + + expect(build(:poll_answer, question: question, answer: 'Four')).to_not be_valid end end describe "#record_voter_participation" do + + let(:author) { create(:user, :level_two) } + let(:poll) { create(:poll) } + let(:question) { create(:poll_question, poll: poll, valid_answers: "Yes, No") } + it "creates a poll_voter with user and poll data" do - answer = create(:poll_answer) + answer = create(:poll_answer, question: question, author: author, answer: "Yes") expect(answer.poll.voters).to be_blank - answer.record_voter_participation - expect(answer.poll.reload.voters.size).to eq(1) - voter = answer.poll.voters.first + answer.record_voter_participation('token') + expect(poll.reload.voters.size).to eq(1) + voter = poll.voters.first expect(voter.document_number).to eq(answer.author.document_number) expect(voter.poll_id).to eq(answer.poll.id) + expect(voter.officer_id).to eq(nil) + end + + it "updates a poll_voter with user and poll data" do + answer = create(:poll_answer, question: question, author: author, answer: "Yes") + answer.record_voter_participation('token') + + expect(poll.reload.voters.size).to eq(1) + + answer = create(:poll_answer, question: question, author: author, answer: "No") + answer.record_voter_participation('token') + + expect(poll.reload.voters.size).to eq(1) + + voter = poll.voters.first + expect(voter.document_number).to eq(answer.author.document_number) + expect(voter.poll_id).to eq(answer.poll.id) end end diff --git a/spec/models/poll/poll_spec.rb b/spec/models/poll/poll_spec.rb index ac0cc44ea..5083d7439 100644 --- a/spec/models/poll/poll_spec.rb +++ b/spec/models/poll/poll_spec.rb @@ -138,4 +138,33 @@ describe :poll do end end end + + describe "#voted_in_booth?" do + + it "returns true if the user has already voted in booth" do + user = create(:user, :level_two) + poll = create(:poll) + + create(:poll_voter, poll: poll, user: user, origin: "booth") + + expect(poll.voted_in_booth?(user)).to be + end + + it "returns false if the user has not already voted in a booth" do + user = create(:user, :level_two) + poll = create(:poll) + + expect(poll.voted_in_booth?(user)).to_not be + end + + it "returns false if the user has voted in web" do + user = create(:user, :level_two) + poll = create(:poll) + + create(:poll_voter, poll: poll, user: user, origin: "web") + + expect(poll.voted_in_booth?(user)).to_not be + end + + end end diff --git a/spec/models/poll/recount_spec.rb b/spec/models/poll/recount_spec.rb new file mode 100644 index 000000000..2a5ed16a7 --- /dev/null +++ b/spec/models/poll/recount_spec.rb @@ -0,0 +1,104 @@ +require 'rails_helper' + +describe Poll::Recount do + + describe "logging changes" do + let(:author) { create(:user) } + let(:officer_assignment) { create(:poll_officer_assignment) } + let(:poll_recount) { create(:poll_recount, author: author, officer_assignment: officer_assignment) } + + it "should update white_amount_log if white_amount changes" do + poll_recount.white_amount = 33 + + expect(poll_recount.white_amount_log).to eq("") + + poll_recount.white_amount = 33 + poll_recount.save + poll_recount.white_amount = 32 + poll_recount.save + poll_recount.white_amount = 34 + poll_recount.save + + expect(poll_recount.white_amount_log).to eq(":0:33:32") + end + + it "should update null_amount_log if null_amount changes" do + poll_recount.null_amount = 33 + + expect(poll_recount.null_amount_log).to eq("") + + poll_recount.null_amount = 33 + poll_recount.save + poll_recount.null_amount = 32 + poll_recount.save + poll_recount.null_amount = 34 + poll_recount.save + + expect(poll_recount.null_amount_log).to eq(":0:33:32") + end + + it "should update total_amount_log if total_amount changes" do + poll_recount.total_amount = 33 + + expect(poll_recount.total_amount_log).to eq("") + + poll_recount.total_amount = 33 + poll_recount.save + poll_recount.total_amount = 32 + poll_recount.save + poll_recount.total_amount = 34 + poll_recount.save + + expect(poll_recount.total_amount_log).to eq(":0:33:32") + end + + it "should update officer_assignment_id_log if amount changes" do + poll_recount.white_amount = 33 + + expect(poll_recount.white_amount_log).to eq("") + expect(poll_recount.officer_assignment_id_log).to eq("") + + poll_recount.white_amount = 33 + poll_recount.officer_assignment = create(:poll_officer_assignment, id: 101) + poll_recount.save + + poll_recount.white_amount = 32 + poll_recount.officer_assignment = create(:poll_officer_assignment, id: 102) + poll_recount.save + + poll_recount.white_amount = 34 + poll_recount.officer_assignment = create(:poll_officer_assignment, id: 103) + poll_recount.save + + expect(poll_recount.white_amount_log).to eq(":0:33:32") + expect(poll_recount.officer_assignment_id_log).to eq(":#{officer_assignment.id}:101:102") + end + + it "should update author_id if amount changes" do + poll_recount.white_amount = 33 + + expect(poll_recount.white_amount_log).to eq("") + expect(poll_recount.author_id_log).to eq("") + + first_author = create(:poll_officer).user + second_author = create(:poll_officer).user + third_author = create(:poll_officer).user + + poll_recount.white_amount = 33 + poll_recount.author_id = first_author.id + poll_recount.save! + + poll_recount.white_amount = 32 + poll_recount.author_id = second_author.id + poll_recount.save! + + poll_recount.white_amount = 34 + poll_recount.author_id = third_author.id + poll_recount.save! + + expect(poll_recount.white_amount_log).to eq(":0:33:32") + expect(poll_recount.author_id_log).to eq(":#{author.id}:#{first_author.id}:#{second_author.id}") + end + end + +end diff --git a/spec/models/poll/shift_spec.rb b/spec/models/poll/shift_spec.rb index b7918b95c..cba4285ae 100644 --- a/spec/models/poll/shift_spec.rb +++ b/spec/models/poll/shift_spec.rb @@ -1,9 +1,14 @@ require 'rails_helper' describe :shift do - let(:shift) { build(:poll_shift) } + let(:poll) { create(:poll) } + let(:booth) { create(:poll_booth) } + let(:user) { create(:user, username: "Ana", email: "ana@example.com") } + let(:officer) { create(:poll_officer, user: user) } + let(:recount_shift) { build(:poll_shift, booth: booth, officer: officer, date: Date.current, task: :recount_scrutiny) } describe "validations" do + let(:shift) { build(:poll_shift) } it "should be valid" do expect(shift).to be_valid @@ -24,45 +29,80 @@ describe :shift do expect(shift).to_not be_valid end + it "should not be valid without a task" do + shift.task = nil + expect(shift).to_not be_valid + end + + it "should not be valid with same booth, officer, date and task" do + recount_shift.save + + expect(build(:poll_shift, booth: booth, officer: officer, date: Date.current, task: :recount_scrutiny)).to_not be_valid + end + + it "should be valid with same booth, officer and date but different task" do + recount_shift.save + + expect(build(:poll_shift, booth: booth, officer: officer, date: Date.current, task: :vote_collection)).to be_valid + end + + it "should be valid with same booth, officer and task but different date" do + recount_shift.save + + expect(build(:poll_shift, booth: booth, officer: officer, date: Date.tomorrow, task: :recount_scrutiny)).to be_valid + end + end describe "officer_assignments" do - it "should create corresponding officer_assignments" do - poll1 = create(:poll) + it "should create and destroy corresponding officer_assignments" do poll2 = create(:poll) poll3 = create(:poll) - booth = create(:poll_booth) - officer = create(:poll_officer) - - booth_assignment1 = create(:poll_booth_assignment, poll: poll1, booth: booth) + booth_assignment1 = create(:poll_booth_assignment, poll: poll, booth: booth) booth_assignment2 = create(:poll_booth_assignment, poll: poll2, booth: booth) - shift = create(:poll_shift, booth: booth, officer: officer, date: Date.current) + expect { create(:poll_shift, booth: booth, officer: officer, date: Date.current) }.to change {Poll::OfficerAssignment.all.count}.by(2) officer_assignments = Poll::OfficerAssignment.all - expect(officer_assignments.count).to eq(2) - oa1 = officer_assignments.first oa2 = officer_assignments.second expect(oa1.officer).to eq(officer) expect(oa1.date).to eq(Date.current) expect(oa1.booth_assignment).to eq(booth_assignment1) + expect(oa1.final).to be_falsey expect(oa2.officer).to eq(officer) expect(oa2.date).to eq(Date.current) expect(oa2.booth_assignment).to eq(booth_assignment2) + expect(oa2.final).to be_falsey + + create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment1, date: Date.tomorrow) + + expect { Poll::Shift.last.destroy }.to change {Poll::OfficerAssignment.all.count}.by(-2) + end + + it "should create final officer_assignments" do + booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth) + recount_shift.save + + officer_assignments = Poll::OfficerAssignment.all + expect(officer_assignments.count).to eq(1) + + officer_assignment = officer_assignments.first + + expect(officer_assignment.officer).to eq(officer) + expect(officer_assignment.date).to eq(Date.current) + expect(officer_assignment.booth_assignment).to eq(booth_assignment) + expect(officer_assignment.final).to be_truthy end end describe "#persist_data" do - - let(:user) { create(:user, username: "Ana", email: "ana@example.com") } - let(:officer) { create(:poll_officer, user: user) } - let(:shift) { create(:poll_shift, officer: officer) } + let(:shift) { create(:poll_shift, officer: officer, booth: booth) } it "should maintain officer data after destroying associated user" do shift.officer.user.destroy diff --git a/spec/models/poll/voter_spec.rb b/spec/models/poll/voter_spec.rb index c1c248550..ae0f84a49 100644 --- a/spec/models/poll/voter_spec.rb +++ b/spec/models/poll/voter_spec.rb @@ -76,13 +76,71 @@ describe :voter do it "should not be valid if the user has voted via web" do answer = create(:poll_answer) - answer.record_voter_participation + answer.record_voter_participation('token') voter = build(:poll_voter, poll: answer.question.poll, user: answer.author) expect(voter).to_not be_valid expect(voter.errors.messages[:document_number]).to eq(["User has already voted"]) end + context "origin" do + + it "should not be valid without an origin" do + voter.origin = nil + expect(voter).to_not be_valid + end + + it "should not be valid without a valid origin" do + voter.origin = "invalid_origin" + expect(voter).to_not be_valid + end + + it "should be valid with a booth origin" do + voter.origin = "booth" + expect(voter).to be_valid + end + + it "should be valid with a web origin" do + voter.origin = "web" + expect(voter).to be_valid + end + + end + + end + + describe "scopes" do + + describe "#web" do + it "returns voters with a web origin" do + voter1 = create(:poll_voter, origin: "web") + voter2 = create(:poll_voter, origin: "web") + voter3 = create(:poll_voter, origin: "booth") + + web_voters = Poll::Voter.web + + expect(web_voters.count).to eq(2) + expect(web_voters).to include(voter1) + expect(web_voters).to include(voter2) + expect(web_voters).to_not include(voter3) + end + end + + describe "#booth" do + it "returns voters with a booth origin" do + voter1 = create(:poll_voter, origin: "booth") + voter2 = create(:poll_voter, origin: "booth") + voter3 = create(:poll_voter, origin: "web") + + booth_voters = Poll::Voter.booth + + expect(booth_voters.count).to eq(2) + expect(booth_voters).to include(voter1) + expect(booth_voters).to include(voter2) + expect(booth_voters).to_not include(voter3) + end + end + end describe "save" do @@ -104,11 +162,12 @@ describe :voter do it "sets user info" do user = create(:user, document_number: "1234A", document_type: "1") - voter = build(:poll_voter, user: user) + voter = build(:poll_voter, user: user, token: "1234abcd") voter.save expect(voter.document_number).to eq("1234A") expect(voter.document_type).to eq("1") + expect(voter.token).to eq("1234abcd") end end -end \ No newline at end of file +end diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 83c19edde..588bd4057 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -891,4 +891,63 @@ describe Proposal do end end + + describe "#recommendations" do + + let(:user) { create(:user) } + + it "Should not return any proposals when user has not interests" do + create(:proposal) + + expect(Proposal.recommendations(user).size).to eq 0 + end + + it "Should return proposals ordered by cached_votes_up" do + proposal1 = create(:proposal, cached_votes_up: 1, tag_list: "Sport" ) + proposal2 = create(:proposal, cached_votes_up: 5, tag_list: "Sport" ) + proposal3 = create(:proposal, cached_votes_up: 10, tag_list: "Sport" ) + proposal4 = create(:proposal, tag_list: "Sport" ) + create(:follow, followable: proposal4, user: user) + + result = Proposal.recommendations(user).sort_by_recommendations + + expect(result.first).to eq proposal3 + expect(result.second).to eq proposal2 + expect(result.third).to eq proposal1 + end + + it "Should return proposals related with user interests" do + proposal1 = create(:proposal, tag_list: "Sport") + proposal2 = create(:proposal, tag_list: "Sport") + proposal3 = create(:proposal, tag_list: "Politics") + create(:follow, followable: proposal1, user: user) + + result = Proposal.recommendations(user) + + expect(result.size).to eq 1 + expect(result).to eq [proposal2] + end + + it "Should not return proposals when user is follower" do + proposal1 = create(:proposal, tag_list: "Sport") + create(:follow, followable: proposal1, user: user) + + result = Proposal.recommendations(user) + + expect(result.size).to eq 0 + end + + it "Should not return proposals when user is the author" do + proposal1 = create(:proposal, author: user, tag_list: "Sport") + proposal2 = create(:proposal, tag_list: "Sport") + proposal3 = create(:proposal, tag_list: "Sport") + create(:follow, followable: proposal3, user: user) + + result = Proposal.recommendations(user) + + expect(result.size).to eq 1 + expect(result).to eq [proposal2] + end + + end end diff --git a/spec/models/residence_spec.rb b/spec/models/residence_spec.rb index 9ba93b2c7..2dd6760a0 100644 --- a/spec/models/residence_spec.rb +++ b/spec/models/residence_spec.rb @@ -27,7 +27,7 @@ describe Verification::Residence do it "should validate user has allowed age" do residence = Verification::Residence.new("date_of_birth(3i)" => "1", "date_of_birth(2i)" => "1", - "date_of_birth(1i)" => (5.years.ago.year).to_s) + "date_of_birth(1i)" => 5.years.ago.year.to_s) expect(residence).to_not be_valid expect(residence.errors[:date_of_birth]).to include("You don't have the required age to participate") end diff --git a/spec/shared/features/documentable.rb b/spec/shared/features/documentable.rb index 9c31da7b0..2bd9d8f86 100644 --- a/spec/shared/features/documentable.rb +++ b/spec/shared/features/documentable.rb @@ -1,13 +1,10 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path, documentable_path_arguments| include ActionView::Helpers - include DocumentsHelper - include DocumentablesHelper let!(:administrator) { create(:user) } let!(:user) { create(:user) } let!(:arguments) { {} } let!(:documentable) { create(documentable_factory_name, author: user) } - let!(:documentable_dom_name) { documentable_factory_name.parameterize } before do create(:administrator, user: administrator) @@ -17,374 +14,81 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path, end end - context "Show" do + context "Show documents tab" do - scenario "Should not display upload document button when there is no logged user" do + let!(:document) { create(:document, documentable: documentable, user: documentable.author)} + + scenario "Should not display maximum number of documents alert when reached for users without document creation permission" do + create_list(:document, 2, documentable: documentable) visit send(documentable_path, arguments) - within "##{dom_id(documentable)}" do - expect(page).not_to have_link("Upload document") - end - end - - scenario "Should not display upload document button when maximum number of documents reached " do - create_list(:document, 3, documentable: documentable) - visit send(documentable_path, arguments) - - within "##{dom_id(documentable)}" do - expect(page).not_to have_link("Upload document") - end - end - - scenario "Should display upload document button when user is logged in and is documentable owner" do - login_as(user) - - visit send(documentable_path, arguments) - - within "##{dom_id(documentable)}" do - expect(page).to have_link("Upload document") - end - end - - scenario "Should display upload document button when admin is logged in" do - login_as(administrator) - - visit send(documentable_path, arguments) - - within "##{dom_id(documentable)}" do - expect(page).to have_link("Upload document") - end - end - - scenario "Should navigate to new document page when click un upload button" do - login_as(user) - - visit send(documentable_path, arguments) - click_link "Upload document" - - expect(page).to have_selector("h1", text: "Upload document") - end - - describe "Documents tab" do - - let!(:document) { create(:document, documentable: documentable, user: documentable.author)} - - scenario "Should not display maximum number of documents alert when reached for users without document creation permission" do - create_list(:document, 2, documentable: documentable) - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).not_to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another." - end - end - - scenario "Should display maximum number of documents alert when reached and when current user has document creation permission" do - login_as documentable.author - create_list(:document, 2, documentable: documentable) - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another." - end - end - - scenario "Download action should be able to anyone" do - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).to have_link("Dowload file") - end - end - - scenario "Download file link should have blank target attribute" do - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).to have_selector("a[target=_blank]", text: "Dowload file") - end - end - - scenario "Download file links should have rel attribute setted to no follow" do - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).to have_selector("a[rel=nofollow]", text: "Dowload file") - end - end - - describe "Destroy action" do - - scenario "Should not be able when no user logged in" do - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).not_to have_link("Destroy") - end - end - - scenario "Should be able when documentable author is logged in" do - login_as documentable.author - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).to have_link("Destroy") - end - end - - scenario "Should be able when any administrator logged in" do - login_as administrator - visit send(documentable_path, arguments) - - within "#tab-documents" do - expect(page).to have_link("Destroy") - end - end - - end - - end - - end - - context "New" do - - scenario "Should not be able for unathenticated users" do - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - expect(page).to have_content("You must sign in or register to continue.") - end - - scenario "Should not be able for other users" do - login_as create(:user) - - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - expect(page).to have_content("You do not have permission to carry out the action 'new' on document. ") - end - - scenario "Should be able to documentable author" do - login_as documentable.author - - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - expect(page).to have_selector("h1", text: "Upload document") - end - - scenario "Should display file name after file selection", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - - expect(page).to have_content "empty.pdf" - end - - scenario "Should not display file name after file selection", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/logo_header.png", make_visible: true - sleep 1 - - expect(page).not_to have_content "logo_header.jpg" - end - - scenario "Should update loading bar style after valid file upload", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - - expect(page).to have_selector ".loading-bar.complete" - end - - scenario "Should update loading bar style after unvalid file upload", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/logo_header.png", make_visible: true - sleep 1 - - expect(page).to have_selector ".loading-bar.errors" - end - - scenario "Should update document title with attachment original file name after file selection if no title defined by user", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - - expect(find("input[name='document[title]']").value).to eq("empty.pdf") - end - - scenario "Should not update document title with attachment original file name after file selection when title already defined by user", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - fill_in :document_title, with: "My custom title" - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - - expect(find("input[name='document[title]']").value).to eq("My custom title") - end - - scenario "Should update document cached_attachment field after valid file upload", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - - expect(find("input[name='document[cached_attachment]']", visible: false).value).to include("empty.pdf") - end - - scenario "Should not show 'Choose document' button after valid upload", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - - expect(page).not_to have_content "Choose document" - end - - scenario "Should show 'Remove document' button after valid upload", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - - expect(page).to have_link("Remove document") - end - - scenario "Should show 'Choose document' button after remove valid upload", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true - sleep 1 - click_link "Remove document" - sleep 1 - - expect(page).to have_content "Choose document" - end - - scenario "Should not update document cached_attachment field after unvalid file upload", :js do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - attach_file :document_attachment, "spec/fixtures/files/logo_header.png", make_visible: true - sleep 1 - - expect(find("input[name='document[cached_attachment]']", visible: false).value).to eq "" - end - - scenario "Should show documentable custom recomentations" do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id, - from: send(documentable_path, arguments)) - - expect(page).to have_content "You can upload up to a maximum of #{max_file_size(documentable)} documents." - expect(page).to have_content "You can upload #{humanized_accepted_content_types(documentable)} files." - expect(page).to have_content "You can upload files up to #{max_file_size(documentable)} MB." - end - - end - - context "Create" do - - scenario "Should show validation errors" do - login_as documentable.author - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id) - - click_on "Upload document" - - expect(page).to have_content "2 errors prevented this Document from being saved: " - expect(page).to have_selector "small.error", text: "can't be blank", count: 2 - end - - scenario "Should show error notice after unsuccessfull document upload" do - login_as documentable.author - - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id, - from: send(documentable_path, arguments)) - attach_file :document_attachment, "spec/fixtures/files/empty.pdf" - sleep 1 - click_on "Upload document" - - expect(page).to have_content "Cannot create document. Check form errors and try again." - end - - scenario "Should show success notice after successfull document upload" do - login_as documentable.author - - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id, - from: send(documentable_path, arguments)) - fill_in :document_title, with: "Document title" - attach_file :document_attachment, "spec/fixtures/files/empty.pdf" - sleep 1 - click_on "Upload document" - - expect(page).to have_content "Document was created successfully." - end - - scenario "Should redirect to documentable path after successfull document upload" do - login_as documentable.author - - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id, - from: send(documentable_path, arguments)) - fill_in :document_title, with: "Document title" - attach_file :document_attachment, "spec/fixtures/files/empty.pdf" - sleep 1 - click_on "Upload document" - - within "##{dom_id(documentable)}" do - expect(page).to have_selector "h1", text: documentable.title - end - end - - scenario "Should show new document on documentable documents tab after successfull document upload" do - login_as documentable.author - - visit new_document_path(documentable_type: documentable.class.name, - documentable_id: documentable.id, - from: send(documentable_path, arguments)) - fill_in :document_title, with: "Document title" - attach_file :document_attachment, "spec/fixtures/files/empty.pdf" - sleep 1 - click_on "Upload document" - - expect(page).to have_link "Documents (1)" within "#tab-documents" do - within "#document_#{Document.last.id}" do - expect(page).to have_content "Document title" - expect(page).to have_link "Dowload file" - expect(page).to have_link "Destroy" + expect(page).not_to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another." + end + end + + scenario "Should display maximum number of documents alert when reached and when current user has document creation permission" do + login_as documentable.author + create_list(:document, 2, documentable: documentable) + visit send(documentable_path, arguments) + + within "#tab-documents" do + expect(page).to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another." + end + end + + scenario "Download action should be able to anyone" do + visit send(documentable_path, arguments) + + within "#tab-documents" do + expect(page).to have_link("Dowload file") + end + end + + scenario "Download file link should have blank target attribute" do + visit send(documentable_path, arguments) + + within "#tab-documents" do + expect(page).to have_selector("a[target=_blank]", text: "Dowload file") + end + end + + scenario "Download file links should have rel attribute setted to no follow" do + visit send(documentable_path, arguments) + + within "#tab-documents" do + expect(page).to have_selector("a[rel=nofollow]", text: "Dowload file") + end + end + + describe "Destroy action" do + + scenario "Should not be able when no user logged in" do + visit send(documentable_path, arguments) + + within "#tab-documents" do + expect(page).not_to have_link("Destroy") end end + + scenario "Should be able when documentable author is logged in" do + login_as documentable.author + visit send(documentable_path, arguments) + + within "#tab-documents" do + expect(page).to have_link("Destroy") + end + end + + scenario "Should be able when any administrator logged in" do + login_as administrator + visit send(documentable_path, arguments) + + within "#tab-documents" do + expect(page).to have_link("Destroy") + end + end + end end @@ -437,3 +141,12 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path, end end + +def attach_document(path, success = true) + attach_file :document_attachment, path, make_visible: true + if success + expect(page).to have_css ".loading-bar.complete" + else + expect(page).to have_css ".loading-bar.errors" + end +end \ No newline at end of file diff --git a/spec/shared/features/imageable.rb b/spec/shared/features/imageable.rb new file mode 100644 index 000000000..418d971c2 --- /dev/null +++ b/spec/shared/features/imageable.rb @@ -0,0 +1,96 @@ +shared_examples "imageable" do |imageable_factory_name, imageable_path, imageable_path_arguments| + include ActionView::Helpers + include ImagesHelper + include ImageablesHelper + + let!(:administrator) { create(:user) } + let!(:user) { create(:user) } + let!(:imageable_arguments) { {} } + let!(:imageables_arguments) { {} } + let!(:imageable) { create(imageable_factory_name, author: user) } + let!(:imageable_dom_name) { imageable_factory_name.parameterize } + + before do + create(:administrator, user: administrator) + + imageable_path_arguments.each do |argument_name, path_to_value| + imageable_arguments.merge!("#{argument_name}": imageable.send(path_to_value)) + end + end + + context "Show" do + + scenario "Show descriptive image when exists", :js do + image = create(:image, imageable: imageable) + + visit send(imageable_path, imageable_arguments) + + expect(page).to have_css("img[alt='#{image.title}'][title='#{image.title}']") + end + + scenario "Show image title when image exists" do + image = create(:image, imageable: imageable) + + visit send(imageable_path, imageable_arguments) + + expect(page).to have_content image.title + end + + end + + context "Destroy" do + + let!(:image) { create(:image, imageable: imageable, user: imageable.author) } + + scenario "Should show success notice after successfull deletion by an admin" do + login_as administrator + + visit send(imageable_path, imageable_arguments) + click_on "Remove image" + + expect(page).to have_content "Image was deleted successfully." + end + + scenario "Should show success notice after successfull deletion" do + login_as imageable.author + + visit send(imageable_path, imageable_arguments) + click_on "Remove image" + + expect(page).to have_content "Image was deleted successfully." + end + + scenario "Should not show image after successful deletion" do + login_as imageable.author + + visit send(imageable_path, imageable_arguments) + click_on "Remove image" + + expect(page).not_to have_selector "figure img" + end + + scenario "Should redirect to imageable path after successful deletion" do + login_as imageable.author + + visit send(imageable_path, imageable_arguments) + click_on "Remove image" + + within "##{dom_id(imageable)}" do + expect(page).to have_selector "h1", text: imageable.title + end + end + + end + +end + +def attach_image(path, success = true) + image = find(".image") + image_input = image.find("input[type=file]", visible: false) + attach_file image_input[:id], path, make_visible: true + if success + expect(page).to have_css ".loading-bar.complete" + else + expect(page).to have_css ".loading-bar.errors" + end +end diff --git a/spec/shared/features/mappable.rb b/spec/shared/features/mappable.rb new file mode 100644 index 000000000..ccbcd5625 --- /dev/null +++ b/spec/shared/features/mappable.rb @@ -0,0 +1,220 @@ +shared_examples "mappable" do |mappable_factory_name, mappable_association_name, mappable_new_path, mappable_edit_path, mappable_show_path, mappable_path_arguments| + + include ActionView::Helpers + + let!(:user) { create(:user, :level_two) } + + before do + Setting['feature.map'] = true + end + + describe "At #{mappable_new_path}" do + + let!(:arguments) { {} } + let!(:mappable) { create("#{mappable_factory_name}".to_sym) } + let!(:map_location) { create(:map_location, "#{mappable_factory_name}_map_location".to_sym, "#{mappable_association_name}": mappable) } + + before { set_arguments(arguments, mappable, mappable_path_arguments) } + + scenario "Should not show marker by default on create #{mappable_factory_name}", :js do + login_as user + visit send(mappable_new_path, arguments) + + send("fill_in_#{mappable_factory_name}_form") + + within ".map_location" do + expect(page).not_to have_css(".map-icon") + end + end + + scenario "Should show marker on create #{mappable_factory_name} when click on map", :js do + login_as user + visit send(mappable_new_path, arguments) + + send("fill_in_#{mappable_factory_name}_form") + find("#new_map_location").click + + within ".map_location" do + expect(page).to have_css(".map-icon") + end + end + + scenario "Should create #{mappable_factory_name} with map", :js do + login_as user + visit send(mappable_new_path, arguments) + + send("fill_in_#{mappable_factory_name}_form") + find("#new_map_location").click + send("submit_#{mappable_factory_name}_form") + + expect(page).to have_css(".map_location") + end + + scenario "Can not display map on #{mappable_factory_name} when not fill marker on map", :js do + login_as user + visit send(mappable_new_path, arguments) + + send("fill_in_#{mappable_factory_name}_form") + expect(page).to have_css ".map_location" + send("submit_#{mappable_factory_name}_form") + + expect(page).not_to have_css(".map_location") + end + + scenario "Can not display map on #{mappable_factory_name} when feature.map is disabled", :js do + Setting['feature.map'] = false + login_as user + visit send(mappable_new_path, arguments) + + send("fill_in_#{mappable_factory_name}_form") + expect(page).not_to have_css ".map_location" + send("submit_#{mappable_factory_name}_form") + + expect(page).not_to have_css(".map_location") + end + + end + + describe "At #{mappable_edit_path}" do + + let!(:mappable) { create("#{mappable_factory_name}".to_sym) } + let!(:map_location) { create(:map_location, "#{mappable_factory_name}_map_location".to_sym, "#{mappable_association_name}": mappable) } + + before { skip } unless mappable_edit_path.present? + + scenario "Should edit map on #{mappable_factory_name} and contain default values", :js do + login_as mappable.author + + visit send(mappable_edit_path, id: mappable.id) + + expect(page).to have_content "Navigate the map to the location and place the marker." + validate_latitude_longitude(mappable_factory_name) + end + + scenario "Should edit default values from map on #{mappable_factory_name} edit page", :js do + login_as mappable.author + + visit send(mappable_edit_path, id: mappable.id) + find(".map_location").click + click_on("Save changes") + mappable.reload + + expect(page).to have_css(".map_location") + expect(page).not_to have_selector(".map_location[data-marker-latitude='#{map_location.latitude}']") + expect(page).to have_selector(".map_location[data-marker-latitude='#{mappable.map_location.latitude}']") + end + + scenario "Should edit mappable on #{mappable_factory_name} without change map", :js do + login_as mappable.author + + visit send(mappable_edit_path, id: mappable.id) + fill_in "#{mappable_factory_name}_title", with: "New title" + click_on("Save changes") + mappable.reload + + expect(page).to have_css(".map_location") + expect(page).to have_selector(".map_location[data-marker-latitude='#{map_location.latitude}']") + expect(page).to have_selector(".map_location[data-marker-latitude='#{mappable.map_location.latitude}']") + end + + scenario "Can not display map on #{mappable_factory_name} edit when remove map marker", :js do + login_as mappable.author + + visit send(mappable_edit_path, id: mappable.id) + click_link "Remove map marker" + click_on "Save changes" + + expect(page).not_to have_css(".map_location") + end + + scenario "Can not display map on #{mappable_factory_name} edit when feature.map is disabled", :js do + Setting['feature.map'] = false + login_as mappable.author + + visit send(mappable_edit_path, id: mappable.id) + fill_in "#{mappable_factory_name}_title", with: "New title" + click_on("Save changes") + + expect(page).not_to have_css(".map_location") + end + + end + + describe "At #{mappable_show_path}" do + + let!(:arguments) { {} } + let!(:mappable) { create("#{mappable_factory_name}".to_sym) } + let!(:map_location) { create(:map_location, "#{mappable_factory_name}_map_location".to_sym, "#{mappable_association_name}": mappable) } + + before { set_arguments(arguments, mappable, mappable_path_arguments) } + + scenario "Should display map on #{mappable_factory_name} show page", :js do + arguments.merge!("id": mappable.id) + + visit send(mappable_show_path, arguments) + + expect(page).to have_css(".map_location") + end + + scenario "Should not display map on #{mappable_factory_name} show when marker is not defined", :js do + mappable_without_map = create("#{mappable_factory_name}".to_sym) + set_arguments(arguments, mappable_without_map, mappable_path_arguments) + arguments.merge!("id": mappable_without_map.id) + + visit send(mappable_show_path, arguments) + + expect(page).not_to have_css(".map_location") + end + + scenario "Should not display map on #{mappable_factory_name} show page when feature.map is disable", :js do + Setting['feature.map'] = false + arguments.merge!("id": mappable.id) + + visit send(mappable_show_path, arguments) + + expect(page).not_to have_css(".map_location") + end + + end + +end + +def fill_in_proposal_form + fill_in 'proposal_title', with: 'Help refugees' + fill_in 'proposal_question', with: '¿Would you like to give assistance to war refugees?' + fill_in 'proposal_summary', with: 'In summary, what we want is...' +end + +def submit_proposal_form + check :proposal_terms_of_service + click_button 'Create proposal' + + click_link 'Not now, go to my proposal' +end + +def validate_latitude_longitude(mappable_factory_name) + expect(find("##{mappable_factory_name}_map_location_attributes_latitude", visible: false).value).to eq "51.48" + expect(find("##{mappable_factory_name}_map_location_attributes_longitude", visible: false).value).to eq "0.0" + expect(mappable.map_location.latitude).to eq 51.48 + expect(mappable.map_location.longitude).to eq 0.0 +end + +def fill_in_budget_investment_form + page.select mappable.heading.name_scoped_by_group, from: :budget_investment_heading_id + fill_in :budget_investment_title, with: "Budget investment title" + fill_in_ckeditor "budget_investment_description", with: "Budget investment description" + check :budget_investment_terms_of_service +end + +def submit_budget_investment_form + check :budget_investment_terms_of_service + click_button 'Create Investment' +end + +def set_arguments(arguments, mappable, mappable_path_arguments) + if mappable_path_arguments + mappable_path_arguments.each do |argument_name, path_to_value| + arguments.merge!("#{argument_name}": mappable.send(path_to_value)) + end + end +end diff --git a/spec/shared/features/nested_documentable.rb b/spec/shared/features/nested_documentable.rb index 906b2d38f..24d6631a8 100644 --- a/spec/shared/features/nested_documentable.rb +++ b/spec/shared/features/nested_documentable.rb @@ -1,4 +1,4 @@ -shared_examples "nested documentable" do |documentable_factory_name, path, documentable_path_arguments, fill_resource_method_name, submit_button, documentable_success_notice| +shared_examples "nested documentable" do |login_as_name, documentable_factory_name, path, documentable_path_arguments, fill_resource_method_name, submit_button, documentable_success_notice| include ActionView::Helpers include DocumentsHelper include DocumentablesHelper @@ -7,257 +7,321 @@ shared_examples "nested documentable" do |documentable_factory_name, path, docum let!(:user) { create(:user, :level_two) } let!(:arguments) { {} } let!(:documentable) { create(documentable_factory_name, author: user) } + let!(:user_to_login) { send(login_as_name)} before do create(:administrator, user: administrator) documentable_path_arguments&.each do |argument_name, path_to_value| - arguments.merge!("#{argument_name}": documentable.send(path_to_value)) + arguments.merge!("#{argument_name}": documentable.send(path_to_value)) end end describe "at #{path}" do scenario "Should show new document link when max documents allowed limit is not reached" do - login_as user + login_as user_to_login visit send(path, arguments) - expect(page).to have_selector "#new_document_link", visible: true + expect(page).to have_css "#new_document_link", visible: true end scenario "Should not show new document link when documentable max documents allowed limit is reached", :js do - login_as user + login_as user_to_login visit send(path, arguments) - click_link "Add new document" - sleep 1 - click_link "Add new document" - sleep 1 - click_link "Add new document" + documentable.class.max_documents_allowed.times.each do + click_link "Add new document" + end - expect(page).to have_selector "#new_document_link", visible: false + expect(page).to have_css "#new_document_link", visible: false end scenario "Should not show max documents warning when no documents added", :js do - login_as user + login_as user_to_login visit send(path, arguments) - expect(page).to have_selector ".max-documents-notice", visible: false + expect(page).to have_css ".max-documents-notice", visible: false end scenario "Should show max documents warning when max documents allowed limit is reached", :js do - login_as user + login_as user_to_login visit send(path, arguments) - click_link "Add new document" - sleep 1 - click_link "Add new document" - sleep 1 - click_link "Add new document" + documentable.class.max_documents_allowed.times.each do + click_link "Add new document" + end - expect(page).to have_selector ".max-documents-notice", visible: true + expect(page).to have_css ".max-documents-notice", visible: true end scenario "Should hide max documents warning after any document removal", :js do - login_as user + login_as user_to_login visit send(path, arguments) - click_link "Add new document" - sleep 1 - click_link "Add new document" - sleep 1 - click_link "Add new document" - sleep 1 - within "#document_0" do - find("a", text: "Remove document").click + documentable.class.max_documents_allowed.times.each do + click_link "Add new document" end - sleep 1 - expect(page).to have_selector ".max-documents-notice", visible: false + all("a", text: "Remove document").last.click + + expect(page).to have_css ".max-documents-notice", visible: false end scenario "Should update nested document file name after choosing a file", :js do - login_as user + login_as user_to_login visit send(path, arguments) - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") + click_link "Add new document" + within "#nested-documents" do + document = find(".document input[type=file]", visible: false) + attach_file(document[:id], "spec/fixtures/files/empty.pdf", make_visible: true) + end - expect(page).to have_selector ".file-name", text: "empty.pdf" + expect(page).to have_css ".file-name", text: "empty.pdf" end scenario "Should update nested document file title with file name after choosing a file when no title defined", :js do - login_as user + login_as user_to_login visit send(path, arguments) - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - expect(find("##{documentable_factory_name}_documents_attributes_0_title").value).to eq "empty.pdf" + expect_document_has_title(0, "empty.pdf") end scenario "Should not update nested document file title with file name after choosing a file when title already defined", :js do - login_as user + login_as user_to_login visit send(path, arguments) click_link "Add new document" - sleep 1 - fill_in "#{documentable_factory_name}[documents_attributes][0][title]", with: "Title" - attach_file("#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf", make_visible: true) - sleep 1 + within "#nested-documents" do + input = find("input[name$='[title]']") + fill_in input[:id], with: "My Title" + document_input = find("input[type=file]", visible: false) + attach_file(document_input[:id], "spec/fixtures/files/empty.pdf", make_visible: true) + end - expect(find("##{documentable_factory_name}_documents_attributes_0_title").value).to eq "Title" + expect_document_has_title(0, "My Title") end scenario "Should update loading bar style after valid file upload", :js do - login_as user + login_as user_to_login visit send(path, arguments) - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - fill_in "#{documentable_factory_name}[documents_attributes][0][title]", with: "Title" + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - expect(page).to have_selector ".loading-bar.complete" + expect(page).to have_css ".loading-bar.complete" end scenario "Should update loading bar style after unvalid file upload", :js do - login_as user + login_as user_to_login visit send(path, arguments) - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/logo_header.png") + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/logo_header.png", false) - expect(page).to have_selector ".loading-bar.errors" + expect(page).to have_css ".loading-bar.errors" end scenario "Should update document cached_attachment field after valid file upload", :js do - login_as user + login_as user_to_login visit send(path, arguments) - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - expect(find("input[name='#{documentable_factory_name}[documents_attributes][0][cached_attachment]']", visible: false).value).to include("empty.pdf") + expect_document_has_cached_attachment(0, ".pdf") end scenario "Should not update document cached_attachment field after unvalid file upload", :js do - login_as user + login_as user_to_login visit send(path, arguments) - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/logo_header.png") + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/logo_header.png", false) - expect(find("input[name='#{documentable_factory_name}[documents_attributes][0][cached_attachment]']", visible: false).value).to eq "" + expect_document_has_cached_attachment(0, "") end - scenario "Should show document errors after unvalid file upload", :js do - login_as user + scenario "Should show document errors after documentable submit with empty document fields", :js do + login_as user_to_login visit send(path, arguments) click_link "Add new document" - sleep 1 click_on submit_button - within "#document_0" do + within "#nested-documents .document" do expect(page).to have_content("can't be blank", count: 2) end end scenario "Should delete document after valid file upload and click on remove button", :js do - login_as user + login_as user_to_login visit send(path, arguments) - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - within "#document_0" do - click_link "Remove document" - end + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") + click_link "Remove document" - expect(page).not_to have_selector("#document_0") - end - - scenario "Should delete document after valid file upload and click on remove button", :js do - login_as user - visit send(path, arguments) - - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - within "#document_0" do - click_link "Remove document" - end - - expect(page).to have_content "Document was deleted successfully." + expect(page).not_to have_css("#nested-documents .document") end scenario "Should show successful notice when resource filled correctly without any nested documents", :js do - login_as user + login_as user_to_login visit send(path, arguments) - send(fill_resource_method_name) if fill_resource_method_name + send(fill_resource_method_name) if fill_resource_method_name click_on submit_button + expect(page).to have_content documentable_success_notice end scenario "Should show successful notice when resource filled correctly and after valid file uploads", :js do - login_as user + login_as user_to_login visit send(path, arguments) send(fill_resource_method_name) if fill_resource_method_name - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") click_on submit_button + expect(page).to have_content documentable_success_notice end scenario "Should show new document after successful creation with one uploaded file", :js do - login_as user + login_as user_to_login visit send(path, arguments) send(fill_resource_method_name) if fill_resource_method_name - attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") - + documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf") click_on submit_button - redirected_to_resource_show_or_navigate_to - expect(page).to have_content "Documents (1)" + documentable_redirected_to_resource_show_or_navigate_to + + expect(page).to have_content "Documents" + + find("#tab-documents-label").click + expect(page).to have_content "empty.pdf" + + #Review + #Doble check why the file is stored with a name different to empty.pdf + expect(page).to have_css("a[href$='.pdf']") end scenario "Should show resource with new document after successful creation with maximum allowed uploaded files", :js do - login_as user + skip "due to weird behaviour" + page.driver.resize_window 1200, 2500 + login_as user_to_login visit send(path, arguments) + send(fill_resource_method_name) if fill_resource_method_name - documentable.class.max_documents_allowed.times.each do |index| - attach_new_file(documentable_factory_name, index, "spec/fixtures/files/empty.pdf") + documentable.class.max_documents_allowed.times.each do + click_link "Add new document" end + documents = all(".document") + documents.each_with_index do |document, index| + document_input = document.find("input[type=file]", visible: false) + attach_file(document_input[:id], "spec/fixtures/files/empty.pdf", make_visible: true) + within all(".document")[index] do + expect(page).to have_css ".loading-bar.complete" + end + end click_on submit_button - redirected_to_resource_show_or_navigate_to + documentable_redirected_to_resource_show_or_navigate_to expect(page).to have_content "Documents (#{documentable.class.max_documents_allowed})" end + if path.include? "edit" + + scenario "Should show persisted documents and remove nested_field" do + login_as user_to_login + create(:document, documentable: documentable) + visit send(path, arguments) + + expect(page).to have_css ".document", count: 1 + end + + scenario "Should not show add document button when documentable has reached maximum of documents allowed", :js do + login_as user_to_login + create_list(:document, documentable.class.max_documents_allowed, documentable: documentable) + visit send(path, arguments) + + expect(page).to have_css "#new_document_link", visible: false + end + + scenario "Should show add document button after destroy one document", :js do + login_as user_to_login + create_list(:document, documentable.class.max_documents_allowed, documentable: documentable) + visit send(path, arguments) + last_document = all("#nested-documents .document").last + within last_document do + click_on "Remove document" + end + + expect(page).to have_css "#new_document_link", visible: true + end + + scenario "Should remove nested field after remove document", :js do + login_as user_to_login + create(:document, documentable: documentable) + visit send(path, arguments) + click_on "Remove document" + + expect(page).not_to have_css ".document" + end + + end + end end -def redirected_to_resource_show_or_navigate_to +def documentable_redirected_to_resource_show_or_navigate_to find("a", text: "Not now, go to my proposal") click_on "Not now, go to my proposal" rescue return end -def attach_new_file(documentable_factory_name, index, path) +def documentable_attach_new_file(_documentable_factory_name, index, path, success = true) click_link "Add new document" - sleep 1 - attach_file("#{documentable_factory_name}[documents_attributes][#{index}][attachment]", path, make_visible: true) - sleep 1 + document = all(".document")[index] + document_input = document.find("input[type=file]", visible: false) + attach_file(document_input[:id], path, make_visible: true) + within document do + if success + expect(page).to have_css ".loading-bar.complete" + else + expect(page).to have_css ".loading-bar.errors" + end + end end -def fill_new_valid_proposal +def expect_document_has_title(index, title) + document = all(".document")[index] + + within document do + expect(find("input[name$='[title]']").value).to eq title + end +end + +def expect_document_has_cached_attachment(index, extension) + document = all(".document")[index] + + within document do + expect(find("input[name$='[cached_attachment]']", visible: false).value).to end_with(extension) + end +end + +def documentable_fill_new_valid_proposal fill_in :proposal_title, with: "Proposal title #{rand(9999)}" fill_in :proposal_summary, with: "Proposal summary" fill_in :proposal_question, with: "Proposal question?" check :proposal_terms_of_service end -def fill_new_valid_budget_investment +def documentable_fill_new_valid_budget_investment page.select documentable.heading.name_scoped_by_group, from: :budget_investment_heading_id fill_in :budget_investment_title, with: "Budget investment title" fill_in_ckeditor "budget_investment_description", with: "Budget investment description" check :budget_investment_terms_of_service end - diff --git a/spec/shared/features/nested_imageable.rb b/spec/shared/features/nested_imageable.rb new file mode 100644 index 000000000..1eef9a269 --- /dev/null +++ b/spec/shared/features/nested_imageable.rb @@ -0,0 +1,279 @@ +shared_examples "nested imageable" do |imageable_factory_name, path, imageable_path_arguments, fill_resource_method_name, submit_button, imageable_success_notice, has_many_images=false| + include ActionView::Helpers + include ImagesHelper + include ImageablesHelper + + let!(:user) { create(:user, :level_two) } + let!(:administrator) { create(:administrator, user: user) } + let!(:arguments) { {} } + let!(:imageable) { create(imageable_factory_name) } + + before do + if imageable_path_arguments + imageable_path_arguments.each do |argument_name, path_to_value| + arguments.merge!("#{argument_name}": imageable.send(path_to_value)) + end + end + + if imageable.respond_to?(:author) + imageable.update(author: user) + end + end + + describe "at #{path}" do + + scenario "Should show new image link when imageable has not an associated image defined" do + login_as user + visit send(path, arguments) + + expect(page).to have_selector "#new_image_link", visible: true + end + + scenario "Should hide new image link after add one image" do + login_as user + visit send(path, arguments) + + click_on "Add image" + + expect(page).to have_selector "#new_image_link", visible: true + end + + scenario "Should update nested image file name after choosing any file", :js do + login_as user + visit send(path, arguments) + + click_link "Add image" + image_input = find(".image").find("input[type=file]", visible: false) + attach_file(image_input[:id], "spec/fixtures/files/clippy.jpg", make_visible: true) + + expect(page).to have_selector ".file-name", text: "clippy.jpg" + end + + scenario "Should update nested image file title with file name after choosing a file when no title defined", :js do + login_as user + visit send(path, arguments) + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/clippy.jpg") + + expect_image_has_title("clippy.jpg") + end + + scenario "Should not update nested image file title with file name after choosing a file when title already defined", :js do + login_as user + visit send(path, arguments) + + click_link "Add image" + input_title = find(".image input[name$='[title]']") + fill_in input_title[:id], with: "Title" + image_input = find(".image").find("input[type=file]", visible: false) + attach_file(image_input[:id], "spec/fixtures/files/clippy.jpg", make_visible: true) + + if has_many_images + expect(find("input[id$='_title']").value).to eq "Title" + else + expect(find("##{imageable_factory_name}_image_attributes_title").value).to eq "Title" + end + end + + scenario "Should update loading bar style after valid file upload", :js do + login_as user + visit send(path, arguments) + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/clippy.jpg") + + expect(page).to have_selector ".loading-bar.complete" + end + + scenario "Should update loading bar style after invalid file upload", :js do + login_as user + visit send(path, arguments) + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/logo_header.png", false) + + expect(page).to have_selector ".loading-bar.errors" + end + + scenario "Should update image cached_attachment field after valid file upload", :js do + login_as user + visit send(path, arguments) + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/clippy.jpg") + + expect_image_has_cached_attachment(".jpg") + end + + scenario "Should not update image cached_attachment field after unvalid file upload", :js do + login_as user + visit send(path, arguments) + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/logo_header.png", false) + + expect_image_has_cached_attachment("") + end + + scenario "Should show nested image errors after unvalid form submit", :js do + login_as user + visit send(path, arguments) + + click_link "Add image" + click_on submit_button + + if has_many_images + #Pending. Review soon and test + else + within "#nested-image .image" do + expect(page).to have_content("can't be blank", count: 2) + end + end + end + + scenario "Should remove nested image after valid file upload and click on remove button", :js do + login_as user + visit send(path, arguments) + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/clippy.jpg") + within "#nested-image .image" do + click_link "Remove image" + end + + expect(page).not_to have_selector("#nested-image .image") + end + + scenario "Should show successful notice when resource filled correctly without any nested images", :js do + login_as user + visit send(path, arguments) + + send(fill_resource_method_name) if fill_resource_method_name + click_on submit_button + + if has_many_images + skip "no need to test, there are no attributes for the parent resource" + else + expect(page).to have_content imageable_success_notice + end + end + + scenario "Should show successful notice when resource filled correctly and after valid file uploads", :js do + login_as user + visit send(path, arguments) + send(fill_resource_method_name) if fill_resource_method_name + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/clippy.jpg") + click_on submit_button + + expect(page).to have_content imageable_success_notice + end + + scenario "Should show new image after successful creation with one uploaded file", :js do + login_as user + visit send(path, arguments) + send(fill_resource_method_name) if fill_resource_method_name + + imageable_attach_new_file(imageable_factory_name, "spec/fixtures/files/clippy.jpg") + click_on submit_button + imageable_redirected_to_resource_show_or_navigate_to + + if has_many_images + #Pending. Review soon and test + else + expect(page).to have_selector "figure img" + expect(page).to have_selector "figure figcaption" + end + end + + if path.include? "edit" + + scenario "Should show persisted image" do + login_as user + create(:image, imageable: imageable) + visit send(path, arguments) + + expect(page).to have_css ".image", count: 1 + end + + scenario "Should not show add image button when image already exists", :js do + login_as user + create(:image, imageable: imageable) + visit send(path, arguments) + + expect(page).to have_css "a#new_image_link", visible: false + end + + scenario "Should remove nested field after remove image", :js do + login_as user + create(:image, imageable: imageable) + visit send(path, arguments) + click_on "Remove image" + + expect(page).not_to have_css ".image" + end + + scenario "Should show add image button after remove image", :js do + login_as user + create(:image, imageable: imageable) + visit send(path, arguments) + click_on "Remove image" + + expect(page).to have_css "a#new_image_link", visible: true + end + + end + + end + +end + +def imageable_redirected_to_resource_show_or_navigate_to + find("a", text: "Not now, go to my proposal") + click_on "Not now, go to my proposal" +rescue + return +end + +def imageable_attach_new_file(imageable_factory_name, path, success = true) + click_link "Add image" + within "#nested-image" do + image = find(".image") + image_input = image.find("input[type=file]", visible: false) + attach_file(image_input[:id], path, make_visible: true) + within image do + if success + expect(page).to have_css(".loading-bar.complete") + else + expect(page).to have_css(".loading-bar.errors") + end + end + end +end + +def imageable_fill_new_valid_proposal + fill_in :proposal_title, with: "Proposal title" + fill_in :proposal_summary, with: "Proposal summary" + fill_in :proposal_question, with: "Proposal question?" + check :proposal_terms_of_service +end + +def imageable_fill_new_valid_budget_investment + page.select imageable.heading.name_scoped_by_group, from: :budget_investment_heading_id + fill_in :budget_investment_title, with: "Budget investment title" + fill_in_ckeditor "budget_investment_description", with: "Budget investment description" + check :budget_investment_terms_of_service +end + +def expect_image_has_title(title) + image = find(".image") + + within image do + expect(find("input[name$='[title]']").value).to eq title + end +end + +def expect_image_has_cached_attachment(extension) + within "#nested-image" do + image = find(".image") + + within image do + expect(find("input[name$='[cached_attachment]']", visible: false).value).to end_with(extension) + end + end +end \ No newline at end of file diff --git a/spec/shared/models/acts_as_imageable.rb b/spec/shared/models/acts_as_imageable.rb new file mode 100644 index 000000000..e4f5f221d --- /dev/null +++ b/spec/shared/models/acts_as_imageable.rb @@ -0,0 +1,76 @@ +shared_examples "acts as imageable" do |imageable_factory| + + let!(:image) { build(:image, imageable_factory.to_sym) } + let!(:imageable) { image.imageable } + + it "should be valid" do + expect(image).to be_valid + end + + describe "file extension" do + + it "should not be valid with '.png' extension" do + image.attachment = File.new("spec/fixtures/files/clippy.png") + + expect(image).to_not be_valid + expect(image.errors[:attachment].size).to eq(1) + end + + it "should not be valid with '.gif' extension" do + image.attachment = File.new("spec/fixtures/files/clippy.gif") + + expect(image).to_not be_valid + expect(image.errors[:attachment].size).to eq(1) + end + + it "should be valid with '.jpg' extension" do + image.attachment = File.new("spec/fixtures/files/clippy.jpg") + + expect(image).to be_valid + end + + end + + describe "image dimmessions" do + + it "should be valid when image dimmessions are 475X475 at least" do + expect(image).to be_valid + end + + it "should not be valid when image dimmensions are smaller than 475X475" do + image.attachment = File.new("spec/fixtures/files/logo_header.jpg") + + expect(image).not_to be_valid + end + end + + describe "title" do + + it "should not be valid when correct image attached but no image title provided" do + image.title = '' + + expect(image).to_not be_valid + end + + it "should not be valid when image title is too short" do + image.title = 'a' * 3 + + expect(image).to_not be_valid + end + + it "should not be valid when image title is too long" do + image.title = 'a' * 81 + + expect(image).to_not be_valid + end + + end + + it "image destroy should remove image from file storage" do + image.save + image_url = image.attachment.url + + expect{ image.attachment.destroy }.to change{ image.attachment.url }.from(image_url).to("/attachments/original/missing.png") + end + +end \ No newline at end of file diff --git a/spec/shared/models/document_validations.rb b/spec/shared/models/document_validations.rb index 3226129a3..5d04c77ab 100644 --- a/spec/shared/models/document_validations.rb +++ b/spec/shared/models/document_validations.rb @@ -4,8 +4,8 @@ shared_examples "document validations" do |documentable_factory| let!(:document) { build(:document, documentable_factory.to_sym) } let!(:documentable) { document.documentable } - let!(:maxfilesize) { max_file_size(document.documentable) } - let!(:acceptedcontenttypes) { accepted_content_types(document.documentable) } + let!(:maxfilesize) { max_file_size(document.documentable.class) } + let!(:acceptedcontenttypes) { accepted_content_types(document.documentable.class) } it "should be valid" do expect(document).to be_valid diff --git a/spec/shared/models/image_validations.rb b/spec/shared/models/image_validations.rb new file mode 100644 index 000000000..f3ad0091e --- /dev/null +++ b/spec/shared/models/image_validations.rb @@ -0,0 +1,70 @@ +shared_examples "image validations" do |imageable_factory| + include ImagesHelper + include ImageablesHelper + + let!(:image) { build(:image, imageable_factory.to_sym) } + let!(:imageable) { image.imageable } + let!(:acceptedcontenttypes) { imageable_accepted_content_types } + + it "should be valid" do + expect(image).to be_valid + end + + it "should not be valid without a title" do + image.title = nil + + expect(image).to_not be_valid + end + + it "should not be valid without an attachment" do + image.attachment = nil + + expect(image).to_not be_valid + end + + it "should be valid for all accepted content types" do + acceptedcontenttypes.each do |content_type| + extension = content_type.split("/").last + image.attachment = File.new("spec/fixtures/files/clippy.#{extension}") + + expect(image).to be_valid + end + end + + it "should not be valid for png and gif image content types" do + ["gif", "png"].each do |content_type| + extension = content_type.split("/").last + image.attachment = File.new("spec/fixtures/files/clippy.#{extension}") + + expect(image).not_to be_valid + end + end + + it "should not be valid for attachments larger than imageable max_file_size definition" do + allow(image).to receive(:attachment_file_size).and_return(Image::MAX_IMAGE_SIZE + 1.byte) + + expect(image).to_not be_valid + expect(image.errors[:attachment]).to include "must be in between 0 Bytes and 1 MB" + end + + it "should not be valid without a user_id" do + image.user_id = nil + + expect(image).to_not be_valid + end + + it "should not be valid without a imageable_id" do + image.save + image.imageable_id = nil + + expect(image).to_not be_valid + end + + it "should not be valid without a imageable_type" do + image.save + image.imageable_type = nil + + expect(image).to_not be_valid + end + +end \ No newline at end of file diff --git a/spec/support/common_actions.rb b/spec/support/common_actions.rb index 8b8470293..256b070e4 100644 --- a/spec/support/common_actions.rb +++ b/spec/support/common_actions.rb @@ -24,6 +24,17 @@ module CommonActions click_button 'Enter' end + def login_through_form_as_officer(user) + visit root_path + click_link 'Sign in' + + fill_in 'user_login', with: user.email + fill_in 'user_password', with: user.password + + click_button 'Enter' + visit new_officing_residence_path + end + def login_as_authenticated_manager expected_response = {login: login, user_key: user_key, date: date}.with_indifferent_access login, user_key, date = "JJB042", "31415926", Time.current.strftime("%Y%m%d%H%M%S") @@ -287,4 +298,27 @@ module CommonActions end end + def vote_for_poll_via_web(poll, question) + visit poll_path(poll) + + within("#poll_question_#{question.id}_answers") do + click_link 'Yes' + expect(page).to_not have_link('Yes') + end + + expect(Poll::Voter.count).to eq(1) + end + + def vote_for_poll_via_booth + visit new_officing_residence_path + officing_verify_residence + + expect(page).to have_content poll.name + + first(:button, "Confirm vote").click + expect(page).to have_content "Vote introduced!" + + expect(Poll::Voter.count).to eq(1) + end + end diff --git a/spec/views/welcome/index.html.erb_spec.rb b/spec/views/welcome/index.html.erb_spec.rb new file mode 100644 index 000000000..d8738f42b --- /dev/null +++ b/spec/views/welcome/index.html.erb_spec.rb @@ -0,0 +1,43 @@ +require "rails_helper" + +RSpec.describe "welcome/index" do + + it 'Display images on orbit carrousel when we have defined image_default' do + debate = create(:debate) + + render template: "welcome/_recommended_carousel.html.erb", + locals: { key: "debates", + recommendeds: [debate], + image_field: nil, + image_version: nil, + image_default: "https://dummyimage.com/600x400/000/fff", + carousel_size: "medium-6 large-6 medium-centered large-centered", + btn_text_link: t("welcome.recommended.debates.btn_text_link"), + btn_path_link: debates_path(order: "recommendations")} + + within 'li[data-slide="0"] .card' do + expect(page).to have_selector("img") + end + + end + + it 'Not display images on orbit carrousel when we have not defined image_default' do + debate = create(:debate) + + render template: "welcome/_recommended_carousel.html.erb", + locals: { key: "debates", + recommendeds: [debate], + image_field: nil, + image_version: nil, + image_default: nil, + carousel_size: "medium-6 large-6 medium-centered large-centered", + btn_text_link: t("welcome.recommended.debates.btn_text_link"), + btn_path_link: debates_path(order: "recommendations")} + + within 'li[data-slide="0"] .card' do + expect(page).not_to have_selector("img") + end + + end + +end
- <%= t("shared.comments.title") %> - (<%= @commentable.comments_count %>) -
- - <%= render 'shared/wide_order_selector', i18n_namespace: "comments" %> - - <% if user_signed_in? %> - <%= render 'comments/form', {commentable: @commentable, parent_id: nil, toggeable: false} %> - <% else %> -- -