diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index ee8341f..babf532 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -14,6 +14,7 @@ abort('The Rails environment is running in production mode!') if Rails.env.production? require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! +require_relative 'support/api_helpers' require 'simplecov' require 'simplecov-cobertura' @@ -67,6 +68,7 @@ config.include GraphitiSpecHelpers::RSpec config.include GraphitiSpecHelpers::Sugar config.include Graphiti::Rails::TestHelpers + config.include ApiHelpers, type: :request # You can uncomment this line to turn off ActiveRecord support entirely. # config.use_active_record = false @@ -86,6 +88,17 @@ # https://relishapp.com/rspec/rspec-rails/docs config.infer_spec_type_from_file_location! + config.before(:each, type: :request) do + original_env_config = Rails.application.method(:env_config) + allow(Rails.application).to receive(:env_config) do + original_env_config.call.merge( + 'action_dispatch.show_exceptions' => :all, + 'action_dispatch.show_detailed_exceptions' => false, + 'consider_all_requests_local' => false + ) + end + end + # Filter lines from Rails gems in backtraces. config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: diff --git a/spec/requests/api/v3/public/card_cycles_spec.rb b/spec/requests/api/v3/public/card_cycles_spec.rb new file mode 100644 index 0000000..3ed59c6 --- /dev/null +++ b/spec/requests/api/v3/public/card_cycles_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Card Cycles' do + let!(:card_cycle) { CardCycle.find('borealis') } + + describe 'GET /api/v3/public/card_cycles' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/card_cycles', CardCycle.count) + has_stats_total_count(json, CardCycle.count) + end + end + + describe 'GET /api/v3/public/card_cycles/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/card_cycles/#{card_cycle.id}", + card_cycle.id, + name: card_cycle.name, + position: card_cycle.position + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/card_cycles/#{card_cycle.id}", + card_pools: '/api/v3/public/card_pools', + card_sets: '/api/v3/public/card_sets', + cards: '/api/v3/public/cards', + printings: '/api/v3/public/printings' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/card_cycles/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/card_pools_spec.rb b/spec/requests/api/v3/public/card_pools_spec.rb new file mode 100644 index 0000000..011e37e --- /dev/null +++ b/spec/requests/api/v3/public/card_pools_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Card Pools' do + let!(:card_pool) { CardPool.find('standard_02') } + + describe 'GET /api/v3/public/card_pools' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/card_pools', CardPool.count) + has_stats_total_count(json, CardPool.count) + end + end + + describe 'GET /api/v3/public/card_pools/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/card_pools/#{card_pool.id}", + card_pool.id, + name: card_pool.name, + format_id: card_pool.format_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/card_pools/#{card_pool.id}", + card_cycles: '/api/v3/public/card_cycles', + card_sets: '/api/v3/public/card_sets', + cards: '/api/v3/public/cards', + format: '/api/v3/public/formats', + printings: '/api/v3/public/printings', + snapshots: '/api/v3/public/snapshots' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/card_pools/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/card_set_types_spec.rb b/spec/requests/api/v3/public/card_set_types_spec.rb new file mode 100644 index 0000000..5de7dea --- /dev/null +++ b/spec/requests/api/v3/public/card_set_types_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Card Set Types' do + let!(:card_set_type) { CardSetType.find('booster_pack') } + + describe 'GET /api/v3/public/card_set_types' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/card_set_types', CardSetType.count) + has_stats_total_count(json, CardSetType.count) + end + end + + describe 'GET /api/v3/public/card_set_types/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/card_set_types/#{card_set_type.id}", + card_set_type.id, + name: card_set_type.name, + description: card_set_type.description + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/card_set_types/#{card_set_type.id}", + card_sets: '/api/v3/public/card_sets' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/card_set_types/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/card_sets_spec.rb b/spec/requests/api/v3/public/card_sets_spec.rb new file mode 100644 index 0000000..56b2549 --- /dev/null +++ b/spec/requests/api/v3/public/card_sets_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Card Sets' do + let!(:card_set) { CardSet.find('midnight_sun') } + + describe 'GET /api/v3/public/card_sets' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/card_sets', CardSet.count) + has_stats_total_count(json, CardSet.count) + end + end + + describe 'GET /api/v3/public/card_sets/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/card_sets/#{card_set.id}", + card_set.id, + name: card_set.name, + card_cycle_id: card_set.card_cycle_id, + card_set_type_id: card_set.card_set_type_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/card_sets/#{card_set.id}", + card_cycle: '/api/v3/public/card_cycles', + card_pools: '/api/v3/public/card_pools', + card_set_type: '/api/v3/public/card_set_types', + cards: '/api/v3/public/cards', + printings: '/api/v3/public/printings' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/card_sets/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/card_subtypes_spec.rb b/spec/requests/api/v3/public/card_subtypes_spec.rb new file mode 100644 index 0000000..3eb81ab --- /dev/null +++ b/spec/requests/api/v3/public/card_subtypes_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Card Subtypes' do + let!(:card_subtype) { CardSubtype.find('advertisement') } + + describe 'GET /api/v3/public/card_subtypes' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/card_subtypes', CardSubtype.count) + has_stats_total_count(json, CardSubtype.count) + end + end + + describe 'GET /api/v3/public/card_subtypes/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/card_subtypes/#{card_subtype.id}", + card_subtype.id, + name: card_subtype.name + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/card_subtypes/#{card_subtype.id}", + cards: '/api/v3/public/cards', + printings: '/api/v3/public/printings' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/card_subtypes/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/card_types_spec.rb b/spec/requests/api/v3/public/card_types_spec.rb new file mode 100644 index 0000000..10cb6ad --- /dev/null +++ b/spec/requests/api/v3/public/card_types_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Card Types' do + let!(:card_type) { CardType.find('agenda') } + + describe 'GET /api/v3/public/card_types' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/card_types', CardType.count) + has_stats_total_count(json, CardType.count) + end + end + + describe 'GET /api/v3/public/card_types/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/card_types/#{card_type.id}", + card_type.id, + name: card_type.name + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/card_types/#{card_type.id}", + cards: '/api/v3/public/cards', + printings: '/api/v3/public/printings', + side: '/api/v3/public/sides' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/card_types/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/cards_spec.rb b/spec/requests/api/v3/public/cards_spec.rb new file mode 100644 index 0000000..253e976 --- /dev/null +++ b/spec/requests/api/v3/public/cards_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Cards' do + let!(:card) { Card.find('legwork') } + + describe 'GET /api/v3/public/cards' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/cards', Card.count) + has_stats_total_count(json, Card.count) + end + end + + describe 'GET /api/v3/public/cards/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/cards/#{card.id}", + card.id, + title: card.title, + side_id: card.side_id, + faction_id: card.faction_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/cards/#{card.id}", + card_cycles: '/api/v3/public/card_cycles', + card_pools: '/api/v3/public/card_pools', + card_sets: '/api/v3/public/card_sets', + card_subtypes: '/api/v3/public/card_subtypes', + card_type: '/api/v3/public/card_types', + decklists: '/api/v3/public/decklists', + faction: '/api/v3/public/factions', + printings: '/api/v3/public/printings', + reviews: '/api/v3/public/reviews', + rulings: '/api/v3/public/rulings', + side: '/api/v3/public/sides' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/cards/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/decklists_spec.rb b/spec/requests/api/v3/public/decklists_spec.rb new file mode 100644 index 0000000..34362d9 --- /dev/null +++ b/spec/requests/api/v3/public/decklists_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Decklists' do + let!(:decklist) { Decklist.find('11111111-1111-1111-1111-111111111111') } + + describe 'GET /api/v3/public/decklists' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/decklists', Decklist.count) + has_stats_total_count(json, Decklist.count) + end + end + + describe 'GET /api/v3/public/decklists/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/decklists/#{decklist.id}", + decklist.id, + name: decklist.name, + side_id: decklist.side_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/decklists/#{decklist.id}", + cards: '/api/v3/public/cards', + faction: '/api/v3/public/factions', + side: '/api/v3/public/sides' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/decklists/00000000-0000-0000-0000-000000000000') + end + end +end diff --git a/spec/requests/api/v3/public/factions_spec.rb b/spec/requests/api/v3/public/factions_spec.rb new file mode 100644 index 0000000..ee2a150 --- /dev/null +++ b/spec/requests/api/v3/public/factions_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Factions' do + let!(:faction) { Faction.find('haas_bioroid') } + + describe 'GET /api/v3/public/factions' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/factions', Faction.count) + has_stats_total_count(json, Faction.count) + end + end + + describe 'GET /api/v3/public/factions/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/factions/#{faction.id}", + faction.id, + name: faction.name, + side_id: faction.side_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/factions/#{faction.id}", + cards: '/api/v3/public/cards', + decklists: '/api/v3/public/decklists', + printings: '/api/v3/public/printings', + side: '/api/v3/public/sides' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/factions/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/formats_spec.rb b/spec/requests/api/v3/public/formats_spec.rb new file mode 100644 index 0000000..e3086a1 --- /dev/null +++ b/spec/requests/api/v3/public/formats_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Formats' do + let!(:format_record) { Format.find('standard') } + + describe 'GET /api/v3/public/formats' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/formats', Format.count) + has_stats_total_count(json, Format.count) + end + end + + describe 'GET /api/v3/public/formats/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/formats/#{format_record.id}", + format_record.id, + name: format_record.name + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/formats/#{format_record.id}", + card_pools: '/api/v3/public/card_pools', + restrictions: '/api/v3/public/restrictions', + snapshots: '/api/v3/public/snapshots' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/formats/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/illustrators_spec.rb b/spec/requests/api/v3/public/illustrators_spec.rb new file mode 100644 index 0000000..0d9f91e --- /dev/null +++ b/spec/requests/api/v3/public/illustrators_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Illustrators' do + let!(:illustrator) { Illustrator.find('tom_of_netrunner') } + + describe 'GET /api/v3/public/illustrators' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/illustrators', Illustrator.count) + has_stats_total_count(json, Illustrator.count) + end + end + + describe 'GET /api/v3/public/illustrators/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/illustrators/#{illustrator.id}", + illustrator.id, + name: illustrator.name + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/illustrators/#{illustrator.id}", + printings: '/api/v3/public/printings' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/illustrators/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/printings_spec.rb b/spec/requests/api/v3/public/printings_spec.rb new file mode 100644 index 0000000..0e24792 --- /dev/null +++ b/spec/requests/api/v3/public/printings_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Printings' do + let!(:printing) { Printing.find('21166') } + + describe 'GET /api/v3/public/printings' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/printings', Printing.count) + has_stats_total_count(json, Printing.count) + end + end + + describe 'GET /api/v3/public/printings/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/printings/#{printing.id}", + printing.id, + title: printing.title, + card_id: printing.card_id, + card_cycle_id: printing.card_cycle_id, + card_set_id: printing.card_set_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/printings/#{printing.id}", + card: '/api/v3/public/cards', + card_cycle: '/api/v3/public/card_cycles', + card_pools: '/api/v3/public/card_pools', + card_set: '/api/v3/public/card_sets', + card_subtypes: '/api/v3/public/card_subtypes', + card_type: '/api/v3/public/card_types', + faction: '/api/v3/public/factions', + illustrators: '/api/v3/public/illustrators', + side: '/api/v3/public/sides' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/printings/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/public_api_controller_spec.rb b/spec/requests/api/v3/public/public_api_controller_spec.rb new file mode 100644 index 0000000..355da2a --- /dev/null +++ b/spec/requests/api/v3/public/public_api_controller_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Exception Handling' do + describe 'GET /api/v3/public/card_cycles/:id' do + context 'when the record does not exist' do + it 'returns a valid JSON API error response' do + get '/api/v3/public/card_cycles/non-existent' + + expect(response).to have_http_status(:not_found) + expect(response.content_type).to match(%r{application/(json|vnd\.api\+json)}) + + json = JSON.parse(response.body) # rubocop:disable Rails/ResponseParsedBody + expect(json).to have_key('errors') + expect(json['errors']).to be_an(Array) + expect(json['errors'].first['status']).to eq('404') + expect(json['errors'].first['title']).to eq('Not Found') + end + end + end + + describe 'GET /api/v3/public/card_cycles' do + context 'when a standard error occurs' do + before do + allow(CardCycleResource).to receive(:all).and_raise(StandardError.new('Something went wrong')) + end + + it 'returns a 500 JSON API error response' do + get '/api/v3/public/card_cycles' + + expect(response).to have_http_status(:internal_server_error) + expect(response.content_type).to match(%r{application/(json|vnd\.api\+json)}) + + json = JSON.parse(response.body) # rubocop:disable Rails/ResponseParsedBody + expect(json).to have_key('errors') + expect(json['errors']).to be_an(Array) + expect(json['errors'].first['status']).to eq('500') + expect(json['errors'].first['title']).to eq('Internal Server Error') + expect(json['errors'].first['detail']).to eq( + "We've notified our engineers and hope to address this issue shortly." + ) + end + end + end +end diff --git a/spec/requests/api/v3/public/published_databases_spec.rb b/spec/requests/api/v3/public/published_databases_spec.rb new file mode 100644 index 0000000..895784c --- /dev/null +++ b/spec/requests/api/v3/public/published_databases_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Published Databases' do + fixtures :published_databases + + describe 'GET /api/v3/public/published_databases' do + it 'returns a successful 200 response with correct count' do + api_num_results('/api/v3/public/published_databases', 1) + end + end +end diff --git a/spec/requests/api/v3/public/restrictions_spec.rb b/spec/requests/api/v3/public/restrictions_spec.rb new file mode 100644 index 0000000..bc40ccb --- /dev/null +++ b/spec/requests/api/v3/public/restrictions_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Restrictions' do + let!(:restriction) { Restriction.find('standard_global_penalty') } + + describe 'GET /api/v3/public/restrictions' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/restrictions', Restriction.count) + has_stats_total_count(json, Restriction.count) + end + end + + describe 'GET /api/v3/public/restrictions/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/restrictions/#{restriction.id}", + restriction.id, + name: restriction.name, + format_id: restriction.format_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/restrictions/#{restriction.id}", + format: '/api/v3/public/formats' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/restrictions/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/reviews_spec.rb b/spec/requests/api/v3/public/reviews_spec.rb new file mode 100644 index 0000000..c1637e3 --- /dev/null +++ b/spec/requests/api/v3/public/reviews_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Reviews' do + let!(:review) { Review.find(1) } + + describe 'GET /api/v3/public/reviews' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/reviews', Review.count) + has_stats_total_count(json, Review.count) + end + end + + describe 'GET /api/v3/public/reviews/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/reviews/#{review.id}", + review.id, + card_id: review.card_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/reviews/#{review.id}", + card: '/api/v3/public/cards' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/reviews/999999') + end + end +end diff --git a/spec/requests/api/v3/public/rulings_spec.rb b/spec/requests/api/v3/public/rulings_spec.rb new file mode 100644 index 0000000..a460484 --- /dev/null +++ b/spec/requests/api/v3/public/rulings_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Rulings' do + let!(:ruling) { Ruling.find(1) } + + describe 'GET /api/v3/public/rulings' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/rulings', Ruling.count) + has_stats_total_count(json, Ruling.count) + end + end + + describe 'GET /api/v3/public/rulings/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/rulings/#{ruling.id}", + ruling.id, + card_id: ruling.card_id + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/rulings/#{ruling.id}", + card: '/api/v3/public/cards' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/rulings/999999') + end + end +end diff --git a/spec/requests/api/v3/public/sides_spec.rb b/spec/requests/api/v3/public/sides_spec.rb new file mode 100644 index 0000000..228236c --- /dev/null +++ b/spec/requests/api/v3/public/sides_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Sides' do + let!(:side) { Side.find('corp') } + + describe 'GET /api/v3/public/sides' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/sides', Side.count) + has_stats_total_count(json, Side.count) + end + end + + describe 'GET /api/v3/public/sides/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/sides/#{side.id}", + side.id, + name: side.name + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/sides/#{side.id}", + card_types: '/api/v3/public/card_types', + cards: '/api/v3/public/cards', + decklists: '/api/v3/public/decklists', + factions: '/api/v3/public/factions', + printings: '/api/v3/public/printings' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/sides/non-existent') + end + end +end diff --git a/spec/requests/api/v3/public/snapshots_spec.rb b/spec/requests/api/v3/public/snapshots_spec.rb new file mode 100644 index 0000000..90d3b50 --- /dev/null +++ b/spec/requests/api/v3/public/snapshots_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Public API Snapshots' do + let!(:snapshot) { Snapshot.find('standard_05') } + + describe 'GET /api/v3/public/snapshots' do + it 'returns a successful 200 response with correct count' do + json = api_num_results('/api/v3/public/snapshots', Snapshot.count) + has_stats_total_count(json, Snapshot.count) + end + end + + describe 'GET /api/v3/public/snapshots/:id' do + it 'matches existing record' do + matches_record( + "/api/v3/public/snapshots/#{snapshot.id}", + snapshot.id, + format_id: snapshot.format_id, + active: snapshot.active + ) + end + + it 'has expected relationships' do + has_relationships( + "/api/v3/public/snapshots/#{snapshot.id}", + card_pool: '/api/v3/public/card_pools', + format: '/api/v3/public/formats', + restriction: '/api/v3/public/restrictions' + ) + end + + it 'does not match missing record' do + missing_record('/api/v3/public/snapshots/non-existent') + end + end +end diff --git a/spec/support/api_helpers.rb b/spec/support/api_helpers.rb new file mode 100644 index 0000000..4098133 --- /dev/null +++ b/spec/support/api_helpers.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +module ApiHelpers + def matches_record(path, expected_id, attributes = {}) + get path + + expect(response).to have_http_status(:ok) + expect(response.content_type).to match(%r{application/(json|vnd\.api\+json)}) + + json = JSON.parse(response.body) + expect(json['data']['id']).to eq(expected_id.to_s) + + attributes.each do |key, value| + expect(json['data']['attributes'][key.to_s]).to eq(value) + end + json + end + + def missing_record(path) + get path + + expect(response).to have_http_status(:not_found) + expect(response.content_type).to match(%r{application/(json|vnd\.api\+json)}) + + json = JSON.parse(response.body) + expect(json).to have_key('errors') + expect(json['errors'].first['status']).to eq('404') + end + + # relationships_to_check is a hash of resource_type => expected URL fragment. + def has_relationships(path, relationships_to_check = {}) + get path + + expect(response).to have_http_status(:ok) + json = JSON.parse(response.body) + relationships = json['data']['relationships'] + + expect(relationships).to be_present + + # Check for expected relationships + relationships_to_check.each do |rel_name, expected_route_part| + expect(relationships).to have_key(rel_name.to_s) + expect(relationships[rel_name.to_s]).to have_key('links') + expect(relationships[rel_name.to_s]['links']).to have_key('related') + expect(relationships[rel_name.to_s]['links']['related']).to include(expected_route_part) + end + + # Check for any relationships not specified in relationships_to_check + relationships.each_key do |rel_name| + expect(relationships_to_check).to have_key(rel_name.to_sym), + "Unexpected relationship '#{rel_name}' found in response" + end + end + + def api_num_results(path, expected_count) + get path + + expect(response).to have_http_status(:ok) + expect(response.content_type).to match(%r{application/(json|vnd\.api\+json)}) + + json = JSON.parse(response.body) + expect(json['data'].size).to eq(expected_count) + json + end + + def has_stats_total_count(json, expected_count) + expect(json).to have_key('meta') + expect(json['meta']).to have_key('stats') + expect(json['meta']['stats']).to have_key('total') + expect(json['meta']['stats']['total']).to have_key('count') + expect(json['meta']['stats']['total']['count']).to eq(expected_count) + end +end