diff --git a/app/assets/stylesheets/main.css b/app/assets/stylesheets/main.css index 84ea2e1..4f679f5 100644 --- a/app/assets/stylesheets/main.css +++ b/app/assets/stylesheets/main.css @@ -112,6 +112,10 @@ li { margin-top: 1rem; } +.pr-9 { + padding-right: 9rem; +} + .text-center { text-align: center; } @@ -248,7 +252,8 @@ nav div.user { .buttons .collections, .buttons .equations, .buttons .groupings, -.buttons .participants { +.buttons .participants, +.buttons .reports { width: 100%; gap: 2.5vmin; } @@ -326,7 +331,8 @@ nav div.user { .collections, .equations, .groupings, -.participants { +.participants, +.reports { width: 90%; display: flex; flex-direction: column; @@ -363,7 +369,8 @@ nav div.user { #answers, #collections, -#groupings { +#groupings, +#reports { width: 100%; display: flex; flex-direction: column; @@ -427,7 +434,8 @@ nav div.user { .collections a, .equations a, .groupings a, -.participants a { +.participants a, +.reports a { text-align: center; font-size: 1.5rem; margin: 2vmin auto; @@ -525,6 +533,7 @@ a.forgot-password:hover { } .btn { + /* font-size: 1.2rem; */ cursor: pointer; width: 100%; text-align: center; diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb new file mode 100644 index 0000000..0343403 --- /dev/null +++ b/app/controllers/reports_controller.rb @@ -0,0 +1,38 @@ +class ReportsController < ApplicationController + before_action :set_report, only: %i[ show destroy ] + + # GET /reports or /reports.json + def index + @reports = current_admin.reports + end + + # GET /reports/1 or /reports/1.json + def show + if @report.nil? + @reports = current_admin.reports + flash.now[:alert] = I18n.t("reports.errors.not_found") + render :index + end + end + + # DELETE /reports/1 or /reports/1.json + def destroy + @report.destroy! + + respond_to do |format| + format.html { redirect_to reports_path, status: :see_other, notice: I18n.t("reports.destroyed") } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_report + @report = Report.find_by_id(params[:id]) + end + + # Only allow a list of trusted parameters through. + def report_params + params.require(:report).permit(:user_admin_id, :collection_id, :grouping_id) + end +end diff --git a/app/models/collection.rb b/app/models/collection.rb index be2029d..3a15c71 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -2,6 +2,7 @@ class Collection < ApplicationRecord belongs_to :user_admin, class_name: "User::Admin", dependent: :destroy has_many :collection_equations, dependent: :destroy has_many :equations, through: :collection_equations + has_many :reports validates :name, :equations_quantity, presence: true end diff --git a/app/models/report.rb b/app/models/report.rb new file mode 100644 index 0000000..cde4bcd --- /dev/null +++ b/app/models/report.rb @@ -0,0 +1,9 @@ +class Report < ApplicationRecord + belongs_to :user_admin, class_name: "User::Admin", foreign_key: "user_admin_id" + belongs_to :collection + belongs_to :grouping + + has_many :participants, class_name: "User::Participant", + foreign_key: :user_participant_id, through: :grouping + has_many :rounds +end diff --git a/app/models/round.rb b/app/models/round.rb index e6fac6a..0f7bd68 100644 --- a/app/models/round.rb +++ b/app/models/round.rb @@ -1,5 +1,33 @@ class Round < ApplicationRecord belongs_to :collection belongs_to :participant, class_name: "User::Participant", foreign_key: "user_participant_id" + belongs_to :report, optional: true + has_many :answers + + validates :user_participant_id, uniqueness: { scope: :collection_id } + validate :rounds_length + + private + + def rounds_length + report = Report.find_by(collection: collection) + grouping = report&.grouping + + if report && grouping + rounds = report&.rounds + participants = grouping&.participants + + if rounds && participants + return true if rounds.length <= participants.length + + errors.add( + :base, + :too_many_rounds, + grouping: grouping.name, + count: grouping.participants.length + ) + end + end + end end diff --git a/app/services/report/create_service.rb b/app/services/report/create_service.rb new file mode 100644 index 0000000..e0f31ad --- /dev/null +++ b/app/services/report/create_service.rb @@ -0,0 +1,23 @@ +class Report::CreateService + def initialize(user_admin, collection, grouping) + @user_admin = user_admin + @collection = collection + @grouping = grouping + end + + def self.call(user_admin:, collection:, grouping:) + new(user_admin, collection, grouping).call + end + + def call + create_report + end + + def create_report + @report = Report.find_or_create_by( + user_admin: @user_admin, + collection: @collection, + grouping: @grouping + ) + end +end diff --git a/app/services/round/finish_service.rb b/app/services/round/finish_service.rb index e69977f..1bef723 100644 --- a/app/services/round/finish_service.rb +++ b/app/services/round/finish_service.rb @@ -29,9 +29,17 @@ def collection_completed? def finalize_round @completed_at = Time.current + report = Report::CreateService.call( + user_admin: @user_admin, + collection: @collection, + grouping: @participant.grouping, + ) + @current_round.update!( completed_at: @completed_at, - round_time: calculate_round_time + round_time: calculate_round_time, + report: report + ) end diff --git a/app/views/reports/_report.html.erb b/app/views/reports/_report.html.erb new file mode 100644 index 0000000..03947bc --- /dev/null +++ b/app/views/reports/_report.html.erb @@ -0,0 +1,54 @@ +
+ + + + + + + + + + + <% report.rounds.each do |round| %> + + + + + + + + + + + + + + + + + + + + <% round.answers.each do |answer| %> + + + + + + + + + + + <% end %> + <% end %> + + +
+ <%= report.grouping.name %> +
<%= t("activerecord.models.collection") %><%= report.collection.name %>
<%= t("activerecord.models.user/participant") %><%= round.participant.full_name %>
+ <%= t("activerecord.models.equation").pluralize %> + <%= t("activerecord.attributes.equation.position_a") %><%= t("activerecord.attributes.equation.operator") %><%= t("activerecord.attributes.equation.position_b") %><%= t("activerecord.attributes.equation.position_c") %><%= t("activerecord.attributes.equation.unknown_position") %> + <%= t("activerecord.models.answer").pluralize %> + <%= t("activerecord.attributes.answer.answer_value") %><%= t("activerecord.attributes.answer.correct_answer") %><%= t("activerecord.attributes.answer.time") %>
<%= answer.equation.position_a %><%= answer.equation.operator %><%= answer.equation.position_b %><%= answer.equation.position_c %><%= answer.equation.unknown_position %><%= answer.answer_value %><%= answer.correct_answer ? "✔️" : "❌" %><%= answer.formatted_time %>
+
diff --git a/app/views/reports/_report.json.jbuilder b/app/views/reports/_report.json.jbuilder new file mode 100644 index 0000000..4e5c131 --- /dev/null +++ b/app/views/reports/_report.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! report, :id, :user_admin_id, :user_participant_id, :collection_id, :grouping_id, :created_at, :updated_at +json.url report_url(report, format: :json) diff --git a/app/views/reports/index.html.erb b/app/views/reports/index.html.erb new file mode 100644 index 0000000..6096e1c --- /dev/null +++ b/app/views/reports/index.html.erb @@ -0,0 +1,18 @@ +<% content_for :title, t("activerecord.models.report").pluralize %> +
+
+ <%= render "shared/header" %> +

<%= t("activerecord.models.report").pluralize %>

+
+
+ <% @reports.each do |report| %> +
+ <%= render report %> + <%= link_to t("reports.show"), report %> +
+ <% end %> +
+ <%= link_to t("home.back"), root_path, class: "btn mustard btn-text-black" %> +
+
+
diff --git a/app/views/reports/index.json.jbuilder b/app/views/reports/index.json.jbuilder new file mode 100644 index 0000000..31811f6 --- /dev/null +++ b/app/views/reports/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @reports, partial: "reports/report", as: :report diff --git a/app/views/reports/show.html.erb b/app/views/reports/show.html.erb new file mode 100644 index 0000000..0975380 --- /dev/null +++ b/app/views/reports/show.html.erb @@ -0,0 +1,12 @@ +
+
+ <%= render "shared/header" %> +
+ <%= render @report %> +
+ <%= link_to t("reports.back"), reports_path %> + <%= button_to t("reports.delete"), @report, class: "btn crimson", method: :delete, data: { turbo_method: :delete } %> +
+
+
+
diff --git a/app/views/reports/show.json.jbuilder b/app/views/reports/show.json.jbuilder new file mode 100644 index 0000000..b5a5508 --- /dev/null +++ b/app/views/reports/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "reports/report", report: @report diff --git a/app/views/shared/_header.html.erb b/app/views/shared/_header.html.erb index 784f74a..9643956 100644 --- a/app/views/shared/_header.html.erb +++ b/app/views/shared/_header.html.erb @@ -7,7 +7,7 @@ <%= link_to t("activerecord.models.grouping").pluralize, groupings_path, class: "nav-item" %> <%= link_to t("activerecord.models.collection").pluralize, collections_path, class: "nav-item" %> <%= link_to t("activerecord.models.equation").pluralize, equations_path, class: "nav-item" %> - <%#= link_to t("activerecord.models.answer").pluralize, answers_path, class: "nav-item" %> + <%= link_to t("activerecord.models.report").pluralize, reports_path, class: "nav-item" %> <% end %>
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 37e4a73..942c717 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -14,9 +14,9 @@ pt-BR: register: "Cadastrar nova resposta" show: "Ver resposta" show_all: "Ver todas as respostas" - created: "A resposta foi criada com sucesso." - updated: "A resposta foi atualizada com sucesso." - destroyed: "A resposta foi excluída com sucesso." + created: "A resposta foi criada com sucesso!" + updated: "A resposta foi atualizada com sucesso!" + destroyed: "A resposta foi excluída com sucesso!" collections: back: "Voltar para etapas" delete: "Excluir etapa" @@ -26,9 +26,9 @@ pt-BR: register: "Cadastrar nova etapa" show: "Ver etapa" show_all: "Ver todas as etapas" - created: "A etapa foi criada com sucesso." - updated: "A etapa foi atualizada com sucesso." - destroyed: "A etapa foi excluída com sucesso." + created: "A etapa foi criada com sucesso!" + updated: "A etapa foi atualizada com sucesso!" + destroyed: "A etapa foi excluída com sucesso!" errors: equations_limit: one: "não pode ter mais do que %{count} equação" @@ -44,9 +44,9 @@ pt-BR: register: "Cadastrar equação" show: "Ver equação" show_all: "Ver todas as equações" - created: "A equação foi criada com sucesso." - updated: "A equação foi atualizada com sucesso." - destroyed: "A equação foi excluída com sucesso." + created: "A equação foi criada com sucesso!" + updated: "A equação foi atualizada com sucesso!" + destroyed: "A equação foi excluída com sucesso!" groupings: back: "Voltar para grupos" delete: "Excluir grupo" @@ -56,9 +56,9 @@ pt-BR: select: "Selecionar grupo" show: "Ver grupo" show_all: "Ver todos os grupos" - created: "O grupo foi criado com sucesso." - updated: "O grupo foi atualizado com sucesso." - destroyed: "O grupo foi excluído com sucesso." + created: "O grupo foi criado com sucesso!" + updated: "O grupo foi atualizado com sucesso!" + destroyed: "O grupo foi excluído com sucesso!" participants: back: "Voltar para participantes" delete: "Excluir participante" @@ -70,9 +70,17 @@ pt-BR: register: "Cadastrar participante" show: "Ver participante" show_all: "Ver todos os participantes" - created: "O participante foi criado com sucesso." - updated: "O participante foi atualizado com sucesso." - destroyed: "O participante foi excluído com sucesso." + created: "O participante foi criado com sucesso!" + updated: "O participante foi atualizado com sucesso!" + destroyed: "O participante foi excluído com sucesso!" + reports: + back: "Voltar para relatórios" + delete: "Excluir relatório" + show: "Ver relatório" + show_all: "Ver todos os relatórios" + destroyed: "O relatório foi excluído com sucesso!" + errors: + not_found: "O relatório não foi encontrado!" rounds: new: "Nova sessão" congrats: "Parabéns!" @@ -112,6 +120,7 @@ pt-BR: collection: "Etapa" equation: "Equação" grouping: "Grupo" + report: "Relatório" round: "Sessão" user/admin: "Admin" user/participant: "Participante" @@ -256,6 +265,9 @@ pt-BR: wrong_length: one: não possui o tamanho esperado (%{count} caracter) other: não possui o tamanho esperado (%{count} caracteres) + too_many_rounds: + one: "%{model} não pode ter mais que %{count} sessão, pois o Grupo %{grouping} possui apenas %{count} participante" + other: "%{model} não pode ter mais que %{count} sessões, pois o Grupo %{grouping} possui apenas %{count} participantes" template: body: "Por favor, verifique o(s) seguinte(s) campo(s):" header: diff --git a/config/routes.rb b/config/routes.rb index b0fa0b4..c6ed3b3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,6 @@ # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html Rails.application.routes.draw do - scope "(:locale)", locale: /pt-BR|en/ do + scope "(:locale)", locale: /pt-BR|en/, defaults: { locale: "pt-BR" } do # Defines the root path route ("/") root "home#index" @@ -11,7 +11,7 @@ resources :equations resources :groupings resources :participants, module: :user - resources :reports + resources :reports, only: [ :index, :show, :destroy ] resources :equations, only: [] do resources :collections, only: [] do diff --git a/db/migrate/20241213171716_create_reports.rb b/db/migrate/20241213171716_create_reports.rb new file mode 100644 index 0000000..335caef --- /dev/null +++ b/db/migrate/20241213171716_create_reports.rb @@ -0,0 +1,11 @@ +class CreateReports < ActiveRecord::Migration[7.2] + def change + create_table :reports do |t| + t.references :user_admin, null: false, foreign_key: true + t.references :collection, null: false, foreign_key: true + t.references :group, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20241216155927_add_report_ref_to_rounds.rb b/db/migrate/20241216155927_add_report_ref_to_rounds.rb new file mode 100644 index 0000000..ab31190 --- /dev/null +++ b/db/migrate/20241216155927_add_report_ref_to_rounds.rb @@ -0,0 +1,5 @@ +class AddReportRefToRounds < ActiveRecord::Migration[7.2] + def change + add_reference :rounds, :report, null: false, foreign_key: true + end +end diff --git a/db/migrate/20241221023018_change_round_column_report_to_allow_null.rb b/db/migrate/20241221023018_change_round_column_report_to_allow_null.rb new file mode 100644 index 0000000..37e3193 --- /dev/null +++ b/db/migrate/20241221023018_change_round_column_report_to_allow_null.rb @@ -0,0 +1,5 @@ +class ChangeRoundColumnReportToAllowNull < ActiveRecord::Migration[7.2] + def change + change_column_null :rounds, :report_id, true + end +end diff --git a/db/schema.rb b/db/schema.rb index deabf6a..0f6ab62 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_12_18_195846) do +ActiveRecord::Schema[7.2].define(version: 2024_12_21_023018) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -87,7 +87,7 @@ t.integer "round_time" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.bigint "report_id", null: false + t.bigint "report_id" t.index ["collection_id"], name: "index_rounds_on_collection_id" t.index ["current_equation_id"], name: "index_rounds_on_current_equation_id" t.index ["report_id"], name: "index_rounds_on_report_id" diff --git a/spec/factories/reports.rb b/spec/factories/reports.rb new file mode 100644 index 0000000..a3f9166 --- /dev/null +++ b/spec/factories/reports.rb @@ -0,0 +1,7 @@ +FactoryBot.define do + factory :report do + user_admin + collection + grouping + end +end diff --git a/spec/factories/rounds.rb b/spec/factories/rounds.rb index c8059d2..786645c 100644 --- a/spec/factories/rounds.rb +++ b/spec/factories/rounds.rb @@ -4,6 +4,7 @@ association :participant, factory: :user_participant started_at { "2024-12-06 14:00:00" } completed_at { "2024-12-06 14:02:50" } + report trait :unfinished do started_at { Time.current } diff --git a/spec/factories/user/participants.rb b/spec/factories/user/participants.rb index 4a98c2d..f7248c7 100644 --- a/spec/factories/user/participants.rb +++ b/spec/factories/user/participants.rb @@ -3,7 +3,7 @@ first_name { FFaker::Name.first_name } last_name { FFaker::Name.last_name } birth_date { FFaker::Date.birthday(min_age: 5) } - grouping { build(:grouping) } + grouping user_admin diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb new file mode 100644 index 0000000..9093d6e --- /dev/null +++ b/spec/models/report_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe Report, type: :model do + describe 'database columns' do + it { should have_db_column(:user_admin_id).of_type(:integer) } + it { should have_db_column(:collection_id).of_type(:integer) } + it { should have_db_column(:grouping_id).of_type(:integer) } + end + + describe 'model associations' do + it { should belong_to(:user_admin).class_name('User::Admin') } + it { should belong_to(:collection) } + it { should belong_to(:grouping) } + it { should have_many(:rounds) } + it do + should have_many(:participants) + .class_name('User::Participant') + .through(:grouping) + end + end +end diff --git a/spec/models/round_spec.rb b/spec/models/round_spec.rb index bbf9cc2..8b1b6f8 100644 --- a/spec/models/round_spec.rb +++ b/spec/models/round_spec.rb @@ -14,6 +14,86 @@ describe 'model associations' do it { should belong_to(:collection) } it { should belong_to(:participant).class_name('User::Participant') } + it { should belong_to(:report).optional } it { should have_many(:answers) } end + + + describe 'model validations' do + let(:user_admin) { create(:user_admin) } + let(:collection) { create(:collection, user_admin: user_admin) } + let(:grouping) { create(:grouping, user_admin: user_admin) } + let(:participant) { + create( + :user_participant, + grouping: grouping, + user_admin: user_admin + ) + } + let(:report) { + create( + :report, + user_admin: user_admin, + collection: collection, + grouping: grouping + ) + } + + context "when report is nil" do + it "should be valid" do + round = create(:round, report: nil) + + expect(round).to be_valid + expect(round.errors).to be_empty + end + end + + context 'when rounds count is less or equal to the number of participants in a grouping' do + it 'should be valid with no errors' do + round = create( + :round, + collection: collection, + participant: participant, + report: report + ) + + expect(round).to be_valid + expect(round.errors).to be_empty + end + end + + context 'when rounds count is greater than the number of participants in a grouping' do + it 'should not be valid' do + grouping.reload + + report.rounds << [ + create( + :round, + collection: collection, + participant: participant, + report: report + ) + ] + + round = create( + :round, + collection: collection, + participant: create(:user_participant, user_admin: user_admin), + report: report + ) + + + expect(round).not_to be_valid + expect(round.errors).not_to be_empty + expect(round.errors.full_messages).to include( + I18n.t( + 'errors.messages.too_many_rounds', + model: round.model_name.human, + grouping: grouping.name, + count: grouping.participants.length + ) + ) + end + end + end end diff --git a/spec/requests/reports_spec.rb b/spec/requests/reports_spec.rb new file mode 100644 index 0000000..7ac3ce3 --- /dev/null +++ b/spec/requests/reports_spec.rb @@ -0,0 +1,78 @@ +require 'rails_helper' + +# This spec was generated by rspec-rails when you ran the scaffold generator. +# It demonstrates how one might use RSpec to test the controller code that +# was generated by Rails when you ran the scaffold generator. +# +# It assumes that the implementation code is generated by the rails scaffold +# generator. If you are using any extension libraries to generate different +# controller code, this generated spec may or may not pass. +# +# It only uses APIs available in rails and/or rspec-rails. There are a number +# of tools you can use to make these specs even more expressive, but we're +# sticking to rails and rspec-rails APIs to keep things simple and stable. + +RSpec.describe "/reports", type: :request do + # This should return the minimal set of attributes required to create a valid + # Report. As you add validations to Report, be sure to + # adjust the attributes here as well. + let(:user_admin) { create(:user_admin) } + let(:valid_attributes) { + { + user_admin: user_admin, + collection: create(:collection), + grouping: create(:grouping) + } + } + + let(:invalid_attributes) { + { + user_admin: nil, + collection: nil, + grouping: nil + } + } + + describe "GET /index" do + it "renders a successful response" do + sign_in user_admin + Report.create! valid_attributes + get reports_url + expect(response).to be_successful + end + end + + describe "GET /show" do + context "with valid parameters" do + it "renders a successful response" do + report = Report.create! valid_attributes + get report_url(report, locale: I18n.locale) + expect(response).to be_successful + end + end + + context "with invalid parameters" do + it "redirects to index page" do + sign_in user_admin + invalid_report_id = -1 + get report_url(invalid_report_id, locale: I18n.locale) + expect(response.body).to match(I18n.t("reports.errors.not_found")) + end + end + end + + describe "DELETE /destroy" do + it "destroys the requested report" do + report = Report.create! valid_attributes + expect { + delete report_url(report, locale: I18n.locale) + }.to change(Report, :count).by(-1) + end + + it "redirects to the reports list" do + report = Report.create! valid_attributes + delete report_url(report, locale: I18n.locale) + expect(response).to redirect_to(reports_url) + end + end +end diff --git a/spec/routing/reports_routing_spec.rb b/spec/routing/reports_routing_spec.rb new file mode 100644 index 0000000..760dbc6 --- /dev/null +++ b/spec/routing/reports_routing_spec.rb @@ -0,0 +1,17 @@ +require "rails_helper" + +RSpec.describe ReportsController, type: :routing do + describe "routing" do + it "routes to #index" do + expect(get: "/reports").to route_to("reports#index", locale: I18n.locale.to_s) + end + + it "routes to #show" do + expect(get: "/reports/1").to route_to("reports#show", id: "1", locale: I18n.locale.to_s) + end + + it "routes to #destroy" do + expect(delete: "/reports/1").to route_to("reports#destroy", id: "1", locale: I18n.locale.to_s) + end + end +end diff --git a/spec/services/report/create_service_spec.rb b/spec/services/report/create_service_spec.rb new file mode 100644 index 0000000..c1c8e9b --- /dev/null +++ b/spec/services/report/create_service_spec.rb @@ -0,0 +1,54 @@ +require "rails_helper" + +RSpec.describe Report::CreateService, type: :service do + describe ".call" do + let(:user_admin) { create(:user_admin) } + let(:collection) { create(:collection) } + let(:grouping) { create(:grouping) } + + it "calls the instance method #call" do + service_instance = instance_double(Report::CreateService) + allow(Report::CreateService).to receive(:new).and_return(service_instance) + allow(service_instance).to receive(:call) + + Report::CreateService.call(user_admin: user_admin, collection: collection, grouping: grouping) + + expect(Report::CreateService).to have_received(:new).with(user_admin, collection, grouping) + expect(service_instance).to have_received(:call) + end + end + + describe "#initialize" do + subject(:service) { described_class.new(user_admin, collection, grouping) } + let(:user_admin) { create(:user_admin) } + let(:collection) { create(:collection) } + let(:grouping) { create(:grouping) } + + it "initializes with user_admin, collection and grouping" do + expect(service.instance_variable_get(:@user_admin)).to eq(user_admin) + expect(service.instance_variable_get(:@collection)).to eq(collection) + expect(service.instance_variable_get(:@grouping)).to eq(grouping) + end + end + + describe "#call" do + subject(:service) { described_class.new(user_admin, collection, grouping) } + let(:user_admin) { create(:user_admin) } + let(:collection) { create(:collection) } + let(:grouping) { create(:grouping) } + + context "when report doesn't exist" do + it "creates a report" do + expect { service.call }.to change(Report, :count).by(1) + end + end + + context "when report already exists" do + let!(:report) { create(:report, user_admin: user_admin, collection: collection, grouping: grouping) } + + it "doesn't create a report" do + expect { service.call }.not_to change(Report, :count) + end + end + end +end diff --git a/spec/views/reports/_report.html.erb_spec.rb b/spec/views/reports/_report.html.erb_spec.rb new file mode 100644 index 0000000..b57eed4 --- /dev/null +++ b/spec/views/reports/_report.html.erb_spec.rb @@ -0,0 +1,40 @@ +require 'rails_helper' + +RSpec.describe "reports/_report", type: :view do + let(:current_admin) { create(:user_admin) } + it "renders a report table" do + report = create(:report) + assign(:report, report) + + render(locals: { report: report }) + + expect(rendered).to have_selector("table") + expect(rendered).to have_selector("th > strong", text: report.grouping.name) + expect(rendered).to have_selector("th", text: report.collection.name) + + report.rounds.each do |round| + expect(rendered).to have_selector("th", text: round.participant.full_name) + expect(rendered).to have_selector("th > strong", text: I18n.t("activerecord.models.equation").pluralize) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.equation.position_a")) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.equation.operator")) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.equation.position_b")) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.equation.position_c")) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.equation.unknown_position")) + expect(rendered).to have_selector("th > strong", text: I18n.t("activerecord.models.answer").pluralize) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.answer.answer_value")) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.answer.correct_answer")) + expect(rendered).to have_selector("th", text: I18n.t("activerecord.attributes.answer.time")) + + round.answers.each do |answer| + expect(rendered).to have_selector("td", text: answer.equation.position_a) + expect(rendered).to have_selector("td", text: answer.equation.operator) + expect(rendered).to have_selector("td", text: answer.equation.position_b) + expect(rendered).to have_selector("td", text: answer.equation.position_c) + expect(rendered).to have_selector("td", text: answer.equation.unknown_position) + expect(rendered).to have_selector("td", text: answer.answer_value) + expect(rendered).to have_selector("td", text: answer.correct_answer ? "✔️" : "❌") + expect(rendered).to have_selector("td", text: answer.formatted_time) + end + end + end +end diff --git a/spec/views/reports/index.html.erb_spec.rb b/spec/views/reports/index.html.erb_spec.rb new file mode 100644 index 0000000..cae0c5f --- /dev/null +++ b/spec/views/reports/index.html.erb_spec.rb @@ -0,0 +1,34 @@ +require 'rails_helper' + +RSpec.describe "reports/index", type: :view do + let(:current_admin) { create(:user_admin) } + + before(:each) do + assign(:reports, [ + Report.create!( + user_admin: current_admin, + collection: create(:collection), + grouping: create(:grouping) + ), + Report.create!( + user_admin: current_admin, + collection: create(:collection), + grouping: create(:grouping) + ) + ]) + end + + it "renders a list of reports" do + sign_in current_admin + stub_template("shared/_header.html.erb" => "This content") + + render + + expect(rendered).to have_selector("main", class: "background") + expect(rendered).to have_selector("section", class: "blur") + expect(rendered).to have_rendered("shared/_header") + expect(rendered).to have_selector("h2", text: I18n.t("activerecord.models.report").pluralize) + expect(rendered).to have_rendered("reports/_report") + expect(rendered).to have_link(I18n.t("reports.show"), href: report_path(Report.last)) + end +end diff --git a/spec/views/reports/show.html.erb_spec.rb b/spec/views/reports/show.html.erb_spec.rb new file mode 100644 index 0000000..fe4eb95 --- /dev/null +++ b/spec/views/reports/show.html.erb_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' + +RSpec.describe "reports/show", type: :view do + let(:current_admin) { create(:user_admin) } + + before(:each) do + assign(:report, Report.create!( + user_admin: current_admin, + collection: create(:collection), + grouping: create(:grouping) + )) + end + + it "renders partial reports/report" do + sign_in current_admin + stub_template("shared/_header.html.erb" => "This content") + + render + + expect(rendered).to have_selector("main", class: "background") + expect(rendered).to have_selector("section", class: "blur") + expect(rendered).to have_rendered("shared/_header") + expect(rendered).to have_rendered("reports/_report") + expect(rendered).to have_link(I18n.t("reports.back"), href: reports_path) + expect(rendered).to have_selector("button", text: I18n.t("reports.delete"), class: "btn crimson") + end +end