hensei-api/spec/requests/parties_controller_spec.rb
Justin Edmund 3cdd925162
Fix filters and add processors (#181)
* Update test csvs

* Fix count filters and refactor apply_filters

* Update party_querying_concern.rb

* +tests/-debug logs

* Make party association optional in Job

* Updates for weapon series

- Change to new series numbers
- Add static method for querying whether the weapon's element is changeable
- Add a new method to return a text slug for the weapon's series

* Add and update test data

- Updates canonical.rb for loading multiple types of data with multiple types of associations
- Adds test data for Guidebooks, Job Accessories, Job Skills, and Jobs
- Updates test data for Weapons and Summons

* Migrations

- Adds series of migrations for changing the weapon's series to the values used by Cygames
- Shuffled around some foreign keys

* Implement BaseProcessor

Processors are in charge of processing deck data straight from Granblue.

* Implement CharacterProcessor

Process character data from deck

* Implement WeaponProcessor

Process weapon data from deck

* Implement JobProcessor

Process job, job skill, and job accessory data from deck

* Implement SummonProcessor

Process summon data from deck

* Update SummonProcessor to work like the others

* ImportController should use processors

* Process element for changeable weapons
2025-02-17 23:51:50 -08:00

223 lines
8.3 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Parties API', type: :request do
let(:user) { create(:user) }
let(:access_token) do
Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public')
end
let(:headers) do
{ 'Authorization' => "Bearer #{access_token.token}", 'Content-Type' => 'application/json' }
end
describe 'POST /api/v1/parties' do
context 'with valid attributes' do
let(:valid_attributes) do
{
party: {
name: 'Test Party',
description: 'A party for testing',
raid_id: nil,
visibility: 1,
full_auto: false,
auto_guard: false,
charge_attack: true,
clear_time: 500,
button_count: 3,
turn_count: 4,
chain_count: 2
}
}
end
it 'creates a new party and returns status created' do
expect do
post '/api/v1/parties', params: valid_attributes.to_json, headers: headers
end.to change(Party, :count).by(1)
expect(response).to have_http_status(:created)
json = JSON.parse(response.body)
expect(json['party']['name']).to eq('Test Party')
end
end
end
describe 'GET /api/v1/parties/:id' do
let!(:party) { create(:party, user: user, name: 'Visible Party', visibility: 1) }
context 'when the party is public or owned' do
it 'returns the party details' do
get "/api/v1/parties/#{party.shortcode}", headers: headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['party']['name']).to eq('Visible Party')
end
end
context 'when the party is private and not owned' do
let!(:private_party) { create(:party, user: create(:user), visibility: 3, name: 'Private Party') }
it 'returns unauthorized' do
get "/api/v1/parties/#{private_party.shortcode}", headers: headers
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'PUT /api/v1/parties/:id' do
let!(:party) { create(:party, user: user, name: 'Old Name') }
let(:update_attributes) do
{ party: { name: 'New Name', description: 'Updated description' } }
end
it 'updates the party and returns the updated party' do
put "/api/v1/parties/#{party.id}", params: update_attributes.to_json, headers: headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['party']['name']).to eq('New Name')
expect(json['party']['description']).to eq('Updated description')
end
end
describe 'DELETE /api/v1/parties/:id' do
let!(:party) { create(:party, user: user) }
it 'destroys the party and returns the destroyed party view' do
delete "/api/v1/parties/#{party.id}", headers: headers
expect(response).to have_http_status(:ok)
expect { party.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
describe 'POST /api/v1/parties/:id/remix' do
let!(:party) { create(:party, user: user, name: 'Original Party') }
let(:remix_params) { { party: { local_id: party.local_id } } }
it 'creates a remixed copy of the party' do
post "/api/v1/parties/#{party.shortcode}/remix", params: remix_params.to_json, headers: headers
expect(response).to have_http_status(:created)
json = JSON.parse(response.body)
expect(json['party']['source_party']['id']).to eq(party.id)
end
end
describe 'GET /api/v1/parties' do
before { create_list(:party, 3, user: user, visibility: 1) }
it 'lists parties with pagination' do
get '/api/v1/parties', headers: headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['results']).to be_an(Array)
expect(json['meta']).to have_key('count')
end
before do
# For index, assume the controller builds the query with defaults turned on.
# Create one party that meets the default thresholds and one that does not.
# Defaults: weapons_count >= 5, characters_count >= 3, summons_count >= 2.
@good_party = create(:party, user: user,
weapons_count: 5,
characters_count: 4,
summons_count: 2,
visibility: 1)
@bad_party = create(:party, user: user,
weapons_count: 2, # below default threshold
characters_count: 2,
summons_count: 1,
visibility: 1)
end
it 'returns only parties meeting the default filters' do
get '/api/v1/parties', headers: headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
party_ids = json['results'].map { |p| p['id'] }
expect(party_ids).to include(@good_party.id)
expect(party_ids).not_to include(@bad_party.id)
end
end
describe 'GET /api/v1/parties/favorites' do
let(:other_user) { create(:user) }
let!(:party) { create(:party, user: other_user, visibility: 1) }
before do
# Create associated records so that the party meets the default filtering minimums:
# - At least 3 characters,
# - At least 5 weapons,
# - At least 2 summons.
create_list(:grid_character, 3, party: party)
create_list(:grid_weapon, 5, party: party)
create_list(:grid_summon, 2, party: party)
party.reload # Reload to update counter caches.
create(:favorite, user: user, party: party)
end
before { create(:favorite, user: user, party: party) }
it 'lists parties favorited by the current user' do
get '/api/v1/parties/favorites', headers: headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['results']).not_to be_empty
expect(json['results'].first).to include('favorited' => true)
end
end
describe 'Preview Management Endpoints' do
let(:user) { create(:user) }
let!(:party) { create(:party, user: user, shortcode: 'PREV01', element: 0) }
let(:headers) do
{ 'Authorization' => "Bearer #{Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public').token}",
'Content-Type' => 'application/json' }
end
describe 'GET /api/v1/parties/:id/preview' do
before do
# Stub send_file on the correctly namespaced controller.
allow_any_instance_of(Api::V1::PartiesController).to receive(:send_file) do |instance, *args|
instance.render plain: 'dummy image content', content_type: 'image/png', status: 200
end
end
it 'serves the preview image (returns 200)' do
get "/api/v1/parties/#{party.shortcode}/preview", headers: headers
expect(response).to have_http_status(200)
expect(response.content_type).to eq('image/png; charset=utf-8')
expect(response.body).to eq('dummy image content')
end
end
describe 'GET /api/v1/parties/:id/preview_status' do
it 'returns the preview status of the party' do
get "/api/v1/parties/#{party.shortcode}/preview_status", headers: headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json).to have_key('state')
end
end
describe 'POST /api/v1/parties/:id/regenerate_preview' do
it 'forces preview regeneration when requested by the owner' do
post "/api/v1/parties/#{party.shortcode}/regenerate_preview", headers: headers
expect(response.status).to(satisfy { |s| [200, 422].include?(s) })
end
end
end
# Debug block: prints debug info if an example fails.
after(:each) do |example|
if example.exception && defined?(response) && response.present?
error_message = begin
JSON.parse(response.body)['exception']
rescue JSON::ParserError
response.body
end
puts "\nDEBUG: Error Message for '#{example.full_description}': #{error_message}"
# Parse once and grab the trace safely
parsed_body = JSON.parse(response.body)
trace = parsed_body.dig('traces', 'Application Trace')
ap trace if trace # Only print if trace is not nil
end
end
end