From cc8d628da11c71846ee312edaf6fa15832ea7096 Mon Sep 17 00:00:00 2001 From: Nate Date: Sat, 30 Jan 2016 22:09:07 -0500 Subject: [PATCH 1/2] complete game_night acceptance specs add JSON schema validation to controller spec, create IndexGameNight interactor, fix update_game_night to return a game_night --- app/controllers/game_nights_controller.rb | 15 ++ app/interactors/index_game_night.rb | 9 ++ app/interactors/update_game_night.rb | 2 +- app/serializers/game_night_serializer.rb | 2 +- spec/acceptance/game_nights_spec.rb | 142 ++++++++++++++++++ .../game_nights_controller_spec.rb | 79 ++++++++++ spec/interactors/index_game_night_spec.rb | 35 +++++ 7 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 app/interactors/index_game_night.rb create mode 100644 spec/acceptance/game_nights_spec.rb create mode 100644 spec/interactors/index_game_night_spec.rb diff --git a/app/controllers/game_nights_controller.rb b/app/controllers/game_nights_controller.rb index dd627ed..e0b7ae3 100644 --- a/app/controllers/game_nights_controller.rb +++ b/app/controllers/game_nights_controller.rb @@ -1,4 +1,5 @@ class GameNightsController < AuthenticationController + # POST /game_nights def create result = CreateGameNight.call(user: current_user, game_night_params: game_night_params) @@ -10,6 +11,7 @@ def create end end + # PATCH /game_nights def update result = UpdateGameNight.call(id: params[:id], game_night_params: game_night_params) @@ -21,6 +23,7 @@ def update end end + # GET /game_nights/:id def show result = ShowGameNight.call(id: params[:id]) @@ -31,6 +34,18 @@ def show end end + # GET /game_nights + def index + result = IndexGameNight.call + + if result.success? + render json: result.game_nights, status: :ok + else + render json: result.errors, status: :internal_server_error + end + end + + # DELETE /game_nights/:id def destroy result = DeleteGameNight.call(id: params[:id]) diff --git a/app/interactors/index_game_night.rb b/app/interactors/index_game_night.rb new file mode 100644 index 0000000..148b489 --- /dev/null +++ b/app/interactors/index_game_night.rb @@ -0,0 +1,9 @@ +class IndexGameNight < StandardInteraction + def execute + context.game_nights = GameNight.all + end + + def validate_output + context.fail!(errors: "internal server error") unless context.game_nights + end +end diff --git a/app/interactors/update_game_night.rb b/app/interactors/update_game_night.rb index 7b73631..b046909 100644 --- a/app/interactors/update_game_night.rb +++ b/app/interactors/update_game_night.rb @@ -10,7 +10,7 @@ def execute private def update_game_night - GameNight.update(context.id, context.game_night_params) + context.game_night = GameNight.update(context.id, context.game_night_params) end def valid_input? diff --git a/app/serializers/game_night_serializer.rb b/app/serializers/game_night_serializer.rb index e1ac942..b16116c 100644 --- a/app/serializers/game_night_serializer.rb +++ b/app/serializers/game_night_serializer.rb @@ -1,3 +1,3 @@ class GameNightSerializer < ActiveModel::Serializer - attributes :id, :time, :location_name, :location_address + attributes :id, :name, :time, :location_name, :location_address end diff --git a/spec/acceptance/game_nights_spec.rb b/spec/acceptance/game_nights_spec.rb new file mode 100644 index 0000000..a87edeb --- /dev/null +++ b/spec/acceptance/game_nights_spec.rb @@ -0,0 +1,142 @@ +require "rspec_api_documentation/dsl" + +RSpec.resource "GameNights" do + let(:authenticated_user) do + create(:confirmed_user) + end + + let(:auth_token) do + Knock::AuthToken.new(payload: { sub: authenticated_user.id }).token + end + + def schema_path + "./config/schema/schemata/game_night.json" + end + + shared_context "game_night parameters" do + parameter "name", <<-DESC, scope: :game_night + The name of the game_night. + DESC + parameter "time", <<-DESC, scope: :game_night, required: true + The time of the game_night. + DESC + parameter "location_name", <<-DESC, scope: :game_night, required: true + The location of the game_night. + DESC + parameter "location_address", <<-DESC, scope: :game_night + The address of the game_night. + DESC + end + + post "/game_nights" do + let(:schema_path) { "#{Rails.root}/config/schema/api.json" } + let(:last_response) { response } + let(:last_request) { request } + + include_context "game_night parameters" + + let(:name) { "Waaggh" } + let(:time) { "2015-09-12 22:49:27 +0530" } + let(:location_name) { "Library" } + let(:location_address) { "999 main st. Silver Spring, MD 20910" } + + header "Authorization", :auth_token + + example_request "POST /game_nights" do + expect(status).to eq 201 + + json_response = JSON.parse(response_body) + + expect(json_response["data"]["attributes"]["name"]). + to eq public_send(:name) + + expect(authenticated_user.game_nights.first.name). + to eq public_send(:name) + + game_night = GameNight.first + + expect(game_night.users.first).to eq authenticated_user + end + end + + patch "/game_nights/:id" do + include_context "game_night parameters" + + let!(:game_night) { create(:game_night) } + let(:id) { game_night.id } + + parameter "id", <<-DESC, required: true + The id of the game_night. + DESC + + let(:name) { "New Name" } + let(:time) { "2015-09-12 22:49:27 +0530" } + let(:location_name) { "Library" } + let(:location_address) { "999 main st. Silver Spring, MD 20910" } + + header "Authorization", :auth_token + + example_request "PATCH /game_nights/:id" do + expect(status).to eq 200 + + game_night = JSON.parse(response_body) + + expect(game_night["data"]["attributes"]["name"]). + to eq public_send(:name) + end + end + + get "/game_nights/:id" do + let!(:game_night) { create(:game_night) } + let(:id) { game_night.id } + let(:name) { game_night.name } + + parameter "id", <<-DESC, required: true + The id of the game_night. + DESC + + header "Authorization", :auth_token + + example_request "GET /game_nights/:id" do + expect(status).to eq 200 + + game_night = JSON.parse(response_body) + + expect(game_night["data"]["attributes"]["name"]). + to eq public_send(:name) + end + end + + get "/game_nights/" do + let!(:game_night1) { create(:game_night) } + let!(:game_night2) { create(:game_night) } + let!(:game_night3) { create(:game_night) } + + header "Authorization", :auth_token + + example_request "GET /game_nights/" do + expect(status).to eq 200 + + list = JSON.parse(response_body) + + expect(list["data"][0].value?(game_night1.id.to_s)).to be_truthy + expect(list["data"][1].value?(game_night2.id.to_s)).to be_truthy + expect(list["data"][2].value?(game_night3.id.to_s)).to be_truthy + end + end + + delete "/game_nights/:id" do + let!(:game_night) { create(:game_night) } + let(:id) { game_night.id } + + header "Authorization", :auth_token + + parameter "id", <<-DESC, required: true + The id of the game_night. + DESC + + example_request "DELETE /game_nights/:id" do + expect(status).to eq 204 + end + end +end diff --git a/spec/controllers/game_nights_controller_spec.rb b/spec/controllers/game_nights_controller_spec.rb index f3b0296..d653935 100644 --- a/spec/controllers/game_nights_controller_spec.rb +++ b/spec/controllers/game_nights_controller_spec.rb @@ -1,6 +1,11 @@ +include Committee::Test::Methods + RSpec.describe GameNightsController do let(:user) { create(:confirmed_user) } let(:game_night) { create(:game_night) } + let(:schema_path) { "#{Rails.root}/config/schema/api.json" } + let(:last_response) { response } + let(:last_request) { request } before do authenticate @@ -48,6 +53,11 @@ post :create, params expect(serialize(game_night)).to eq(response.body) end + + it "conforms to JSON schema" do + post :create, params + assert_schema_conform + end end context "when CreateGameNight is a failure" do @@ -111,6 +121,11 @@ patch :update, params expect(serialize(game_night)).to eq(response.body) end + + it "conforms to JSON schema" do + patch :update, params + assert_schema_conform + end end context "when UpdateGameNight is a failure" do @@ -161,6 +176,11 @@ get :show, params expect(serialize(game_night)).to eq(response.body) end + + it "conforms to JSON schema" do + get :show, params + assert_schema_conform + end end context "when ShowGameNight is a failure" do @@ -227,4 +247,63 @@ end end end + + describe "GET #index" do + let(:game_night1) { create(:game_night) } + let(:game_night2) { create(:game_night) } + let(:game_night3) { create(:game_night) } + + let(:index_profile_context) do + Interactor::Context.new(errors: :val, + game_nights: [game_night1, game_night2, game_night3]) + end + + before(:example) do + allow(IndexGameNight).to receive(:call).and_return(index_profile_context) + end + + before do + authenticate + end + + context "when succesful" do + it "calls the IndexProfile interactor" do + expect(IndexGameNight).to receive(:call) + get :index + end + + it "returns HTTP status 200" do + get :index + expect(response).to have_http_status(200) + end + + it "render the profiles as JSON" do + get :index + expect(json["data"][0].value?(game_night1.id.to_s)).to be_truthy + expect(json["data"][1].value?(game_night2.id.to_s)).to be_truthy + expect(json["data"][2].value?(game_night3.id.to_s)).to be_truthy + end + + it "conforms to JSON schema" do + get :index + assert_schema_conform + end + end + + context "when IndexProfile fails" do + let(:index_profile_context) do + double(:context, errors: "internal server error", success?: false) + end + + it "returns HTTP status 500" do + get :index + expect(response).to have_http_status(500) + end + + it "renders an error" do + get :index + expect(response.body).to eq("internal server error") + end + end + end end diff --git a/spec/interactors/index_game_night_spec.rb b/spec/interactors/index_game_night_spec.rb new file mode 100644 index 0000000..56cd08e --- /dev/null +++ b/spec/interactors/index_game_night_spec.rb @@ -0,0 +1,35 @@ +RSpec.describe IndexGameNight do + describe ".call" do + subject do + described_class.call + end + + let!(:game_night1) { create(:game_night) } + let!(:game_night2) { create(:game_night) } + let!(:game_night3) { create(:game_night) } + + context "when successful" do + it "returns a successful context" do + is_expected.to be_a_success + end + + it "sets game_nights to an array of game_nights" do + expect(subject.game_nights).to eq([game_night1, game_night2, game_night3]) + end + end + + context "when unsuccessful" do + before do + allow(GameNight).to receive(:all).and_return(nil) + end + + it "fails" do + is_expected.to be_a_failure + end + + it "returns an error" do + expect(subject.errors).to eq("internal server error") + end + end + end +end From b161d2fa4dc881fe4fa5d93af60a9311a7b96677 Mon Sep 17 00:00:00 2001 From: Nate Date: Sat, 30 Jan 2016 22:14:40 -0500 Subject: [PATCH 2/2] clean up per robucop --- spec/controllers/game_nights_controller_spec.rb | 9 +++++---- spec/interactors/index_game_night_spec.rb | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/spec/controllers/game_nights_controller_spec.rb b/spec/controllers/game_nights_controller_spec.rb index d653935..dca3c89 100644 --- a/spec/controllers/game_nights_controller_spec.rb +++ b/spec/controllers/game_nights_controller_spec.rb @@ -54,7 +54,7 @@ expect(serialize(game_night)).to eq(response.body) end - it "conforms to JSON schema" do + it "conforms to JSON schema" do post :create, params assert_schema_conform end @@ -249,13 +249,14 @@ end describe "GET #index" do - let(:game_night1) { create(:game_night) } + let(:game_night1) { create(:game_night) } let(:game_night2) { create(:game_night) } let(:game_night3) { create(:game_night) } + let(:list) { [game_night1, game_night2, game_night3] } + let(:index_profile_context) do - Interactor::Context.new(errors: :val, - game_nights: [game_night1, game_night2, game_night3]) + Interactor::Context.new(errors: :val, game_nights: list) end before(:example) do diff --git a/spec/interactors/index_game_night_spec.rb b/spec/interactors/index_game_night_spec.rb index 56cd08e..59dea6b 100644 --- a/spec/interactors/index_game_night_spec.rb +++ b/spec/interactors/index_game_night_spec.rb @@ -14,7 +14,8 @@ end it "sets game_nights to an array of game_nights" do - expect(subject.game_nights).to eq([game_night1, game_night2, game_night3]) + expect(subject.game_nights). + to eq([game_night1, game_night2, game_night3]) end end