add artifact specs and factories
This commit is contained in:
parent
cc7ac1956b
commit
233b3430ef
11 changed files with 1212 additions and 0 deletions
63
spec/factories/artifact_skills.rb
Normal file
63
spec/factories/artifact_skills.rb
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :artifact_skill do
|
||||
skill_group { :group_i }
|
||||
# Use high sequence numbers to avoid conflicts with seeded data (modifiers 1-29 used)
|
||||
sequence(:modifier) { |n| 1000 + n }
|
||||
sequence(:name_en) { |n| "Test Skill #{n}" }
|
||||
name_jp { 'テストスキル' }
|
||||
base_values { [1320, 1440, 1560, 1680, 1800] }
|
||||
growth { 300.0 }
|
||||
suffix_en { '' }
|
||||
suffix_jp { '' }
|
||||
polarity { :positive }
|
||||
|
||||
trait :group_i do
|
||||
skill_group { :group_i }
|
||||
end
|
||||
|
||||
trait :group_ii do
|
||||
skill_group { :group_ii }
|
||||
end
|
||||
|
||||
trait :group_iii do
|
||||
skill_group { :group_iii }
|
||||
end
|
||||
|
||||
trait :atk do
|
||||
modifier { 1 }
|
||||
name_en { 'ATK' }
|
||||
name_jp { '攻撃力' }
|
||||
base_values { [1320, 1440, 1560, 1680, 1800] }
|
||||
growth { 300.0 }
|
||||
end
|
||||
|
||||
trait :hp do
|
||||
modifier { 2 }
|
||||
name_en { 'HP' }
|
||||
name_jp { 'HP' }
|
||||
base_values { [660, 720, 780, 840, 900] }
|
||||
growth { 150.0 }
|
||||
end
|
||||
|
||||
trait :ca_dmg do
|
||||
modifier { 3 }
|
||||
name_en { 'C.A. DMG' }
|
||||
name_jp { '奥義ダメ' }
|
||||
base_values { [13.2, 14.4, 15.6, 16.8, 18.0] }
|
||||
growth { 3.0 }
|
||||
suffix_en { '%' }
|
||||
suffix_jp { '%' }
|
||||
end
|
||||
|
||||
trait :negative do
|
||||
polarity { :negative }
|
||||
growth { -6.0 }
|
||||
end
|
||||
|
||||
trait :no_growth do
|
||||
growth { nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
33
spec/factories/artifacts.rb
Normal file
33
spec/factories/artifacts.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :artifact do
|
||||
# Use high sequence numbers to avoid conflicts with seeded data
|
||||
sequence(:granblue_id) { |n| "39999#{n.to_s.rjust(4, '0')}" }
|
||||
sequence(:name_en) { |n| "Test Artifact #{n}" }
|
||||
name_jp { 'テストアーティファクト' }
|
||||
proficiency { :sabre }
|
||||
rarity { :standard }
|
||||
release_date { Date.new(2025, 3, 10) }
|
||||
|
||||
trait :quirk do
|
||||
rarity { :quirk }
|
||||
proficiency { nil }
|
||||
sequence(:granblue_id) { |n| "38888#{n.to_s.rjust(4, '0')}" }
|
||||
sequence(:name_en) { |n| "Quirk Artifact #{n}" }
|
||||
name_jp { 'クィルクアーティファクト' }
|
||||
end
|
||||
|
||||
trait :dagger do
|
||||
proficiency { :dagger }
|
||||
end
|
||||
|
||||
trait :spear do
|
||||
proficiency { :spear }
|
||||
end
|
||||
|
||||
trait :staff do
|
||||
proficiency { :staff }
|
||||
end
|
||||
end
|
||||
end
|
||||
58
spec/factories/collection_artifacts.rb
Normal file
58
spec/factories/collection_artifacts.rb
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :collection_artifact do
|
||||
association :user
|
||||
association :artifact
|
||||
element { 'fire' }
|
||||
level { 1 }
|
||||
proficiency { nil }
|
||||
nickname { nil }
|
||||
skill1 { { 'modifier' => 1, 'strength' => 1800, 'level' => 1 } }
|
||||
skill2 { { 'modifier' => 2, 'strength' => 900, 'level' => 1 } }
|
||||
skill3 { { 'modifier' => 1, 'strength' => 18.0, 'level' => 1 } }
|
||||
skill4 { { 'modifier' => 1, 'strength' => 10, 'level' => 1 } }
|
||||
|
||||
trait :max_level do
|
||||
level { 5 }
|
||||
skill1 { { 'modifier' => 1, 'strength' => 1800, 'level' => 2 } }
|
||||
skill2 { { 'modifier' => 2, 'strength' => 900, 'level' => 2 } }
|
||||
skill3 { { 'modifier' => 1, 'strength' => 18.0, 'level' => 2 } }
|
||||
skill4 { { 'modifier' => 1, 'strength' => 10, 'level' => 2 } }
|
||||
end
|
||||
|
||||
trait :quirk do
|
||||
association :artifact, factory: [:artifact, :quirk]
|
||||
proficiency { :sabre }
|
||||
level { 1 }
|
||||
skill1 { {} }
|
||||
skill2 { {} }
|
||||
skill3 { {} }
|
||||
skill4 { {} }
|
||||
end
|
||||
|
||||
trait :with_nickname do
|
||||
nickname { 'My Favorite Artifact' }
|
||||
end
|
||||
|
||||
trait :water do
|
||||
element { 'water' }
|
||||
end
|
||||
|
||||
trait :earth do
|
||||
element { 'earth' }
|
||||
end
|
||||
|
||||
trait :wind do
|
||||
element { 'wind' }
|
||||
end
|
||||
|
||||
trait :light do
|
||||
element { 'light' }
|
||||
end
|
||||
|
||||
trait :dark do
|
||||
element { 'dark' }
|
||||
end
|
||||
end
|
||||
end
|
||||
33
spec/factories/grid_artifacts.rb
Normal file
33
spec/factories/grid_artifacts.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :grid_artifact do
|
||||
association :grid_character
|
||||
association :artifact
|
||||
element { 'fire' }
|
||||
level { 1 }
|
||||
proficiency { nil }
|
||||
skill1 { { 'modifier' => 1, 'strength' => 1800, 'level' => 1 } }
|
||||
skill2 { { 'modifier' => 2, 'strength' => 900, 'level' => 1 } }
|
||||
skill3 { { 'modifier' => 1, 'strength' => 18.0, 'level' => 1 } }
|
||||
skill4 { { 'modifier' => 1, 'strength' => 10, 'level' => 1 } }
|
||||
|
||||
trait :max_level do
|
||||
level { 5 }
|
||||
skill1 { { 'modifier' => 1, 'strength' => 1800, 'level' => 2 } }
|
||||
skill2 { { 'modifier' => 2, 'strength' => 900, 'level' => 2 } }
|
||||
skill3 { { 'modifier' => 1, 'strength' => 18.0, 'level' => 2 } }
|
||||
skill4 { { 'modifier' => 1, 'strength' => 10, 'level' => 2 } }
|
||||
end
|
||||
|
||||
trait :quirk do
|
||||
association :artifact, factory: [:artifact, :quirk]
|
||||
proficiency { :sabre }
|
||||
level { 1 }
|
||||
skill1 { {} }
|
||||
skill2 { {} }
|
||||
skill3 { {} }
|
||||
skill4 { {} }
|
||||
end
|
||||
end
|
||||
end
|
||||
181
spec/models/artifact_skill_spec.rb
Normal file
181
spec/models/artifact_skill_spec.rb
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ArtifactSkill, type: :model do
|
||||
describe 'validations' do
|
||||
subject { build(:artifact_skill) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:skill_group) }
|
||||
it { is_expected.to validate_presence_of(:modifier) }
|
||||
it { is_expected.to validate_presence_of(:name_en) }
|
||||
it { is_expected.to validate_presence_of(:name_jp) }
|
||||
it { is_expected.to validate_presence_of(:base_values) }
|
||||
it { is_expected.to validate_presence_of(:polarity) }
|
||||
|
||||
it 'validates uniqueness of modifier within skill_group' do
|
||||
# Create with unique modifier, then try to create duplicate
|
||||
existing = create(:artifact_skill, skill_group: :group_i, modifier: 5000)
|
||||
duplicate = build(:artifact_skill, skill_group: :group_i, modifier: 5000)
|
||||
expect(duplicate).not_to be_valid
|
||||
expect(duplicate.errors[:modifier]).to include('has already been taken')
|
||||
end
|
||||
|
||||
it 'allows same modifier in different skill groups' do
|
||||
create(:artifact_skill, skill_group: :group_i, modifier: 5001)
|
||||
different_group = build(:artifact_skill, skill_group: :group_ii, modifier: 5001)
|
||||
expect(different_group).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe 'enums' do
|
||||
it 'defines skill_group enum' do
|
||||
expect(ArtifactSkill.skill_groups).to eq(
|
||||
'group_i' => 1,
|
||||
'group_ii' => 2,
|
||||
'group_iii' => 3
|
||||
)
|
||||
end
|
||||
|
||||
it 'defines polarity enum' do
|
||||
expect(ArtifactSkill.polarities).to eq(
|
||||
'positive' => 'positive',
|
||||
'negative' => 'negative'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.for_slot' do
|
||||
before do
|
||||
# Use unique modifiers that won't conflict with seeded data
|
||||
@group_i_skill = create(:artifact_skill, :group_i, modifier: 6000)
|
||||
@group_ii_skill = create(:artifact_skill, :group_ii, modifier: 6001)
|
||||
@group_iii_skill = create(:artifact_skill, :group_iii, modifier: 6002)
|
||||
end
|
||||
|
||||
it 'returns Group I skills for slot 1' do
|
||||
expect(ArtifactSkill.for_slot(1)).to include(@group_i_skill)
|
||||
expect(ArtifactSkill.for_slot(1)).not_to include(@group_ii_skill)
|
||||
end
|
||||
|
||||
it 'returns Group I skills for slot 2' do
|
||||
expect(ArtifactSkill.for_slot(2)).to include(@group_i_skill)
|
||||
expect(ArtifactSkill.for_slot(2)).not_to include(@group_ii_skill)
|
||||
end
|
||||
|
||||
it 'returns Group II skills for slot 3' do
|
||||
expect(ArtifactSkill.for_slot(3)).to include(@group_ii_skill)
|
||||
expect(ArtifactSkill.for_slot(3)).not_to include(@group_i_skill)
|
||||
end
|
||||
|
||||
it 'returns Group III skills for slot 4' do
|
||||
expect(ArtifactSkill.for_slot(4)).to include(@group_iii_skill)
|
||||
expect(ArtifactSkill.for_slot(4)).not_to include(@group_i_skill)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.find_skill' do
|
||||
before do
|
||||
ArtifactSkill.clear_cache!
|
||||
@test_skill = create(:artifact_skill, skill_group: :group_i, modifier: 7000)
|
||||
end
|
||||
|
||||
after do
|
||||
ArtifactSkill.clear_cache!
|
||||
end
|
||||
|
||||
it 'finds skill by group number and modifier' do
|
||||
ArtifactSkill.clear_cache!
|
||||
found = ArtifactSkill.find_skill(1, 7000)
|
||||
expect(found).to eq(@test_skill)
|
||||
end
|
||||
|
||||
it 'returns nil for non-existent skill' do
|
||||
ArtifactSkill.clear_cache!
|
||||
expect(ArtifactSkill.find_skill(1, 99999)).to be_nil
|
||||
end
|
||||
|
||||
it 'caches skills for performance' do
|
||||
ArtifactSkill.clear_cache!
|
||||
ArtifactSkill.find_skill(1, 7000)
|
||||
expect(ArtifactSkill.instance_variable_get(:@cached_skills)).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#calculate_value' do
|
||||
let(:skill) { build(:artifact_skill, growth: 300.0) }
|
||||
|
||||
it 'returns base strength at level 1' do
|
||||
expect(skill.calculate_value(1800, 1)).to eq(1800)
|
||||
end
|
||||
|
||||
it 'adds growth for each level above 1' do
|
||||
expect(skill.calculate_value(1800, 3)).to eq(2400) # 1800 + (300 * 2)
|
||||
end
|
||||
|
||||
it 'handles level 5' do
|
||||
expect(skill.calculate_value(1800, 5)).to eq(3000) # 1800 + (300 * 4)
|
||||
end
|
||||
|
||||
context 'with nil growth' do
|
||||
let(:skill) { build(:artifact_skill, :no_growth) }
|
||||
|
||||
it 'returns base strength regardless of level' do
|
||||
expect(skill.calculate_value(10, 1)).to eq(10)
|
||||
expect(skill.calculate_value(10, 5)).to eq(10)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with negative growth' do
|
||||
let(:skill) { build(:artifact_skill, :negative, growth: -6.0) }
|
||||
|
||||
it 'subtracts growth for each level' do
|
||||
expect(skill.calculate_value(30, 3)).to eq(18) # 30 + (-6 * 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#format_value' do
|
||||
context 'with percentage suffix' do
|
||||
let(:skill) { build(:artifact_skill, suffix_en: '%', suffix_jp: '%') }
|
||||
|
||||
it 'formats with English suffix' do
|
||||
expect(skill.format_value(18.0, :en)).to eq('18.0%')
|
||||
end
|
||||
|
||||
it 'formats with Japanese suffix' do
|
||||
expect(skill.format_value(18.0, :jp)).to eq('18.0%')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no suffix' do
|
||||
let(:skill) { build(:artifact_skill, suffix_en: '', suffix_jp: '') }
|
||||
|
||||
it 'returns value without suffix' do
|
||||
expect(skill.format_value(1800, :en)).to eq('1800')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#valid_strength?' do
|
||||
let(:skill) { build(:artifact_skill, base_values: [1320, 1440, 1560, 1680, 1800]) }
|
||||
|
||||
it 'returns true for valid base values' do
|
||||
expect(skill.valid_strength?(1800)).to be true
|
||||
expect(skill.valid_strength?(1320)).to be true
|
||||
end
|
||||
|
||||
it 'returns false for invalid values' do
|
||||
expect(skill.valid_strength?(1500)).to be false
|
||||
expect(skill.valid_strength?(9999)).to be false
|
||||
end
|
||||
|
||||
context 'with nil in base_values (unknown values)' do
|
||||
let(:skill) { build(:artifact_skill, base_values: [nil]) }
|
||||
|
||||
it 'returns true for any value' do
|
||||
expect(skill.valid_strength?(9999)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
82
spec/models/artifact_spec.rb
Normal file
82
spec/models/artifact_spec.rb
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Artifact, type: :model do
|
||||
describe 'validations' do
|
||||
subject { build(:artifact) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:granblue_id) }
|
||||
it 'validates uniqueness of granblue_id' do
|
||||
create(:artifact)
|
||||
duplicate = build(:artifact, granblue_id: Artifact.first.granblue_id)
|
||||
expect(duplicate).not_to be_valid
|
||||
expect(duplicate.errors[:granblue_id]).to include('has already been taken')
|
||||
end
|
||||
it { is_expected.to validate_presence_of(:name_en) }
|
||||
it { is_expected.to validate_presence_of(:rarity) }
|
||||
|
||||
context 'when standard artifact' do
|
||||
subject { build(:artifact, rarity: :standard) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:proficiency) }
|
||||
end
|
||||
|
||||
context 'when quirk artifact' do
|
||||
subject { build(:artifact, :quirk) }
|
||||
|
||||
it 'requires proficiency to be nil' do
|
||||
subject.proficiency = :sabre
|
||||
expect(subject).not_to be_valid
|
||||
expect(subject.errors[:proficiency]).to include('must be blank')
|
||||
end
|
||||
|
||||
it 'is valid without proficiency' do
|
||||
expect(subject).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'associations' do
|
||||
it { is_expected.to have_many(:collection_artifacts).dependent(:restrict_with_error) }
|
||||
it { is_expected.to have_many(:grid_artifacts).dependent(:restrict_with_error) }
|
||||
end
|
||||
|
||||
describe 'enums' do
|
||||
it 'defines proficiency enum' do
|
||||
expect(Artifact.proficiencies).to include(
|
||||
'sabre' => 1,
|
||||
'dagger' => 2,
|
||||
'spear' => 4
|
||||
)
|
||||
end
|
||||
|
||||
it 'defines rarity enum' do
|
||||
expect(Artifact.rarities).to eq('standard' => 0, 'quirk' => 1)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'scopes' do
|
||||
let!(:standard_artifact) { create(:artifact, rarity: :standard) }
|
||||
let!(:quirk_artifact) { create(:artifact, :quirk) }
|
||||
|
||||
it 'filters by rarity' do
|
||||
expect(Artifact.standard).to include(standard_artifact)
|
||||
expect(Artifact.standard).not_to include(quirk_artifact)
|
||||
expect(Artifact.quirk).to include(quirk_artifact)
|
||||
expect(Artifact.quirk).not_to include(standard_artifact)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#quirk?' do
|
||||
it 'returns true for quirk artifacts' do
|
||||
artifact = build(:artifact, :quirk)
|
||||
expect(artifact.quirk?).to be true
|
||||
end
|
||||
|
||||
it 'returns false for standard artifacts' do
|
||||
artifact = build(:artifact, rarity: :standard)
|
||||
expect(artifact.quirk?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
202
spec/models/collection_artifact_spec.rb
Normal file
202
spec/models/collection_artifact_spec.rb
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CollectionArtifact, type: :model do
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:user) }
|
||||
it { is_expected.to belong_to(:artifact) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
subject { build(:collection_artifact) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:element) }
|
||||
|
||||
it 'validates presence of level' do
|
||||
subject.level = nil
|
||||
expect(subject).not_to be_valid
|
||||
end
|
||||
|
||||
it 'validates level is between 1 and 5' do
|
||||
subject.level = 0
|
||||
expect(subject).not_to be_valid
|
||||
|
||||
subject.level = 6
|
||||
expect(subject).not_to be_valid
|
||||
|
||||
subject.level = 3
|
||||
expect(subject).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe 'enums' do
|
||||
it 'defines element enum' do
|
||||
expect(CollectionArtifact.elements).to include(
|
||||
'wind' => 1,
|
||||
'fire' => 2,
|
||||
'water' => 3,
|
||||
'earth' => 4,
|
||||
'dark' => 5,
|
||||
'light' => 6
|
||||
)
|
||||
end
|
||||
|
||||
it 'defines proficiency enum' do
|
||||
expect(CollectionArtifact.proficiencies).to include(
|
||||
'sabre' => 1,
|
||||
'dagger' => 2
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#effective_proficiency' do
|
||||
context 'for standard artifact' do
|
||||
let(:artifact) { create(:artifact, proficiency: :dagger) }
|
||||
|
||||
it 'returns proficiency from base artifact' do
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: artifact,
|
||||
proficiency: nil,
|
||||
skill1: {}, skill2: {}, skill3: {}, skill4: {}
|
||||
)
|
||||
expect(collection_artifact.effective_proficiency).to eq('dagger')
|
||||
end
|
||||
end
|
||||
|
||||
context 'for quirk artifact' do
|
||||
let(:artifact) { create(:artifact, :quirk) }
|
||||
|
||||
it 'returns proficiency from instance' do
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: artifact,
|
||||
proficiency: :staff,
|
||||
level: 1,
|
||||
skill1: {}, skill2: {}, skill3: {}, skill4: {}
|
||||
)
|
||||
expect(collection_artifact.effective_proficiency).to eq('staff')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'skill validations' do
|
||||
let(:artifact) { create(:artifact) }
|
||||
|
||||
before do
|
||||
# Seed the required artifact skills for validation
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_i, modifier: 1) do |s|
|
||||
s.name_en = 'ATK'
|
||||
s.name_jp = '攻撃力'
|
||||
s.base_values = [1320, 1440, 1560, 1680, 1800]
|
||||
s.growth = 300.0
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_i, modifier: 2) do |s|
|
||||
s.name_en = 'HP'
|
||||
s.name_jp = 'HP'
|
||||
s.base_values = [660, 720, 780, 840, 900]
|
||||
s.growth = 150.0
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_ii, modifier: 1) do |s|
|
||||
s.name_en = 'C.A. DMG'
|
||||
s.name_jp = '奥義ダメ'
|
||||
s.base_values = [13.2, 14.4, 15.6, 16.8, 18.0]
|
||||
s.growth = 3.0
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_iii, modifier: 1) do |s|
|
||||
s.name_en = 'Chain Burst DMG'
|
||||
s.name_jp = 'チェインダメ'
|
||||
s.base_values = [6, 7, 8, 9, 10]
|
||||
s.growth = 2.5
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.clear_cache!
|
||||
end
|
||||
|
||||
it 'is valid with correct skills' do
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: artifact,
|
||||
level: 1,
|
||||
skill1: { 'modifier' => 1, 'strength' => 1800, 'level' => 1 },
|
||||
skill2: { 'modifier' => 2, 'strength' => 900, 'level' => 1 },
|
||||
skill3: { 'modifier' => 1, 'strength' => 18.0, 'level' => 1 },
|
||||
skill4: { 'modifier' => 1, 'strength' => 10, 'level' => 1 }
|
||||
)
|
||||
expect(collection_artifact).to be_valid
|
||||
end
|
||||
|
||||
it 'is invalid when skill1 and skill2 have the same modifier' do
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: artifact,
|
||||
level: 1,
|
||||
skill1: { 'modifier' => 1, 'strength' => 1800, 'level' => 1 },
|
||||
skill2: { 'modifier' => 1, 'strength' => 1800, 'level' => 1 }, # Same modifier
|
||||
skill3: { 'modifier' => 1, 'strength' => 18.0, 'level' => 1 },
|
||||
skill4: { 'modifier' => 1, 'strength' => 10, 'level' => 1 }
|
||||
)
|
||||
expect(collection_artifact).not_to be_valid
|
||||
expect(collection_artifact.errors[:base]).to include('Skill 1 and Skill 2 cannot have the same modifier')
|
||||
end
|
||||
|
||||
it 'validates skill levels sum correctly' do
|
||||
# At level 1, skill levels must sum to 4 (1 + 3)
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: artifact,
|
||||
level: 1,
|
||||
skill1: { 'modifier' => 1, 'strength' => 1800, 'level' => 2 },
|
||||
skill2: { 'modifier' => 2, 'strength' => 900, 'level' => 2 },
|
||||
skill3: { 'modifier' => 1, 'strength' => 18.0, 'level' => 2 },
|
||||
skill4: { 'modifier' => 1, 'strength' => 10, 'level' => 2 }
|
||||
)
|
||||
expect(collection_artifact).not_to be_valid
|
||||
expect(collection_artifact.errors[:base].first).to include('Skill levels must sum to')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'quirk artifact constraints' do
|
||||
let(:quirk_artifact) { create(:artifact, :quirk) }
|
||||
|
||||
it 'requires level 1 for quirk artifacts' do
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: quirk_artifact,
|
||||
proficiency: :sabre,
|
||||
level: 3,
|
||||
skill1: {},
|
||||
skill2: {},
|
||||
skill3: {},
|
||||
skill4: {}
|
||||
)
|
||||
expect(collection_artifact).not_to be_valid
|
||||
expect(collection_artifact.errors[:level]).to include('must be 1 for quirk artifacts')
|
||||
end
|
||||
|
||||
it 'requires empty skills for quirk artifacts' do
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: quirk_artifact,
|
||||
proficiency: :sabre,
|
||||
level: 1,
|
||||
skill1: { 'modifier' => 1, 'strength' => 1800, 'level' => 1 },
|
||||
skill2: {},
|
||||
skill3: {},
|
||||
skill4: {}
|
||||
)
|
||||
expect(collection_artifact).not_to be_valid
|
||||
expect(collection_artifact.errors[:skill1]).to include('must be empty for quirk artifacts')
|
||||
end
|
||||
|
||||
it 'is valid with empty skills and level 1' do
|
||||
collection_artifact = build(:collection_artifact,
|
||||
artifact: quirk_artifact,
|
||||
proficiency: :sabre,
|
||||
level: 1,
|
||||
skill1: {},
|
||||
skill2: {},
|
||||
skill3: {},
|
||||
skill4: {}
|
||||
)
|
||||
expect(collection_artifact).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
96
spec/models/grid_artifact_spec.rb
Normal file
96
spec/models/grid_artifact_spec.rb
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe GridArtifact, type: :model do
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:grid_character) }
|
||||
it { is_expected.to belong_to(:artifact) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
subject { build(:grid_artifact) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:element) }
|
||||
|
||||
it 'validates presence of level' do
|
||||
subject.level = nil
|
||||
expect(subject).not_to be_valid
|
||||
end
|
||||
|
||||
it 'validates level is between 1 and 5' do
|
||||
subject.level = 0
|
||||
expect(subject).not_to be_valid
|
||||
|
||||
subject.level = 6
|
||||
expect(subject).not_to be_valid
|
||||
|
||||
subject.level = 3
|
||||
expect(subject).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe 'enums' do
|
||||
it 'defines element enum' do
|
||||
expect(GridArtifact.elements).to include(
|
||||
'wind' => 1,
|
||||
'fire' => 2,
|
||||
'water' => 3,
|
||||
'earth' => 4
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#effective_proficiency' do
|
||||
context 'for standard artifact' do
|
||||
let(:artifact) { create(:artifact, proficiency: :spear) }
|
||||
|
||||
it 'returns proficiency from base artifact' do
|
||||
grid_artifact = build(:grid_artifact,
|
||||
artifact: artifact,
|
||||
proficiency: nil,
|
||||
skill1: {}, skill2: {}, skill3: {}, skill4: {}
|
||||
)
|
||||
expect(grid_artifact.effective_proficiency).to eq('spear')
|
||||
end
|
||||
end
|
||||
|
||||
context 'for quirk artifact' do
|
||||
let(:artifact) { create(:artifact, :quirk) }
|
||||
|
||||
it 'returns proficiency from instance' do
|
||||
grid_artifact = build(:grid_artifact,
|
||||
artifact: artifact,
|
||||
proficiency: :melee,
|
||||
level: 1,
|
||||
skill1: {}, skill2: {}, skill3: {}, skill4: {}
|
||||
)
|
||||
expect(grid_artifact.effective_proficiency).to eq('melee')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unique constraint on grid_character' do
|
||||
it 'does not allow duplicate grid_artifacts for same grid_character' do
|
||||
grid_character = create(:grid_character)
|
||||
create(:grid_artifact,
|
||||
grid_character: grid_character,
|
||||
skill1: {}, skill2: {}, skill3: {}, skill4: {}
|
||||
)
|
||||
duplicate = build(:grid_artifact,
|
||||
grid_character: grid_character,
|
||||
skill1: {}, skill2: {}, skill3: {}, skill4: {}
|
||||
)
|
||||
expect(duplicate).not_to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe 'amoeba duplication' do
|
||||
let(:grid_character) { create(:grid_character) }
|
||||
let(:grid_artifact) { create(:grid_artifact, grid_character: grid_character) }
|
||||
|
||||
it 'can be duplicated via amoeba' do
|
||||
expect(GridArtifact).to respond_to(:amoeba_block)
|
||||
end
|
||||
end
|
||||
end
|
||||
90
spec/requests/artifact_skills_controller_spec.rb
Normal file
90
spec/requests/artifact_skills_controller_spec.rb
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Artifact Skills API', type: :request do
|
||||
before do
|
||||
# Create test skills in different groups
|
||||
create(:artifact_skill, :group_i, :atk, modifier: 1)
|
||||
create(:artifact_skill, :group_i, :hp, modifier: 2)
|
||||
create(:artifact_skill, :group_ii, modifier: 1, name_en: 'C.A. DMG', name_jp: '奥義ダメ')
|
||||
create(:artifact_skill, :group_iii, modifier: 1, name_en: 'Chain Burst DMG', name_jp: 'チェインダメ')
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/artifact_skills' do
|
||||
it 'returns all artifact skills' do
|
||||
get '/api/v1/artifact_skills'
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact_skills'].length).to eq(4)
|
||||
end
|
||||
|
||||
it 'filters by skill group' do
|
||||
get '/api/v1/artifact_skills', params: { group: 'group_i' }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact_skills'].length).to eq(2)
|
||||
expect(json['artifact_skills'].all? { |s| s['skill_group'] == 'group_i' }).to be true
|
||||
end
|
||||
|
||||
it 'filters by polarity' do
|
||||
create(:artifact_skill, :group_i, :negative, modifier: 99)
|
||||
|
||||
get '/api/v1/artifact_skills', params: { polarity: 'negative' }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact_skills'].all? { |s| s['polarity'] == 'negative' }).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/artifact_skills/for_slot/:slot' do
|
||||
it 'returns Group I skills for slot 1' do
|
||||
get '/api/v1/artifact_skills/for_slot/1'
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact_skills'].all? { |s| s['skill_group'] == 'group_i' }).to be true
|
||||
end
|
||||
|
||||
it 'returns Group I skills for slot 2' do
|
||||
get '/api/v1/artifact_skills/for_slot/2'
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact_skills'].all? { |s| s['skill_group'] == 'group_i' }).to be true
|
||||
end
|
||||
|
||||
it 'returns Group II skills for slot 3' do
|
||||
get '/api/v1/artifact_skills/for_slot/3'
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact_skills'].all? { |s| s['skill_group'] == 'group_ii' }).to be true
|
||||
end
|
||||
|
||||
it 'returns Group III skills for slot 4' do
|
||||
get '/api/v1/artifact_skills/for_slot/4'
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact_skills'].all? { |s| s['skill_group'] == 'group_iii' }).to be true
|
||||
end
|
||||
|
||||
it 'returns error for invalid slot' do
|
||||
get '/api/v1/artifact_skills/for_slot/5'
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['error']).to include('Slot must be between 1 and 4')
|
||||
end
|
||||
|
||||
it 'returns error for slot 0' do
|
||||
get '/api/v1/artifact_skills/for_slot/0'
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
56
spec/requests/artifacts_controller_spec.rb
Normal file
56
spec/requests/artifacts_controller_spec.rb
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Artifacts API', type: :request do
|
||||
describe 'GET /api/v1/artifacts' do
|
||||
let!(:standard_artifact) { create(:artifact, proficiency: :sabre) }
|
||||
let!(:quirk_artifact) { create(:artifact, :quirk) }
|
||||
|
||||
it 'returns all artifacts' do
|
||||
get '/api/v1/artifacts'
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifacts'].length).to eq(2)
|
||||
end
|
||||
|
||||
it 'filters by rarity' do
|
||||
get '/api/v1/artifacts', params: { rarity: 'standard' }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifacts'].length).to eq(1)
|
||||
expect(json['artifacts'].first['rarity']).to eq('standard')
|
||||
end
|
||||
|
||||
it 'filters by proficiency' do
|
||||
create(:artifact, proficiency: :dagger)
|
||||
|
||||
get '/api/v1/artifacts', params: { proficiency: 'sabre' }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifacts'].all? { |a| a['proficiency'] == 'sabre' }).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/artifacts/:id' do
|
||||
let!(:artifact) { create(:artifact) }
|
||||
|
||||
it 'returns the artifact' do
|
||||
get "/api/v1/artifacts/#{artifact.id}"
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['id']).to eq(artifact.id)
|
||||
expect(json['name']['en']).to eq(artifact.name_en)
|
||||
end
|
||||
|
||||
it 'returns not found for non-existent artifact' do
|
||||
get "/api/v1/artifacts/#{SecureRandom.uuid}"
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
318
spec/requests/collection_artifacts_controller_spec.rb
Normal file
318
spec/requests/collection_artifacts_controller_spec.rb
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Collection Artifacts API', type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:other_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
|
||||
|
||||
let(:artifact) { create(:artifact) }
|
||||
let(:quirk_artifact) { create(:artifact, :quirk) }
|
||||
|
||||
before do
|
||||
# Seed required artifact skills for validation
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_i, modifier: 1) do |s|
|
||||
s.name_en = 'ATK'
|
||||
s.name_jp = '攻撃力'
|
||||
s.base_values = [1320, 1440, 1560, 1680, 1800]
|
||||
s.growth = 300.0
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_i, modifier: 2) do |s|
|
||||
s.name_en = 'HP'
|
||||
s.name_jp = 'HP'
|
||||
s.base_values = [660, 720, 780, 840, 900]
|
||||
s.growth = 150.0
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_ii, modifier: 1) do |s|
|
||||
s.name_en = 'C.A. DMG'
|
||||
s.name_jp = '奥義ダメ'
|
||||
s.base_values = [13.2, 14.4, 15.6, 16.8, 18.0]
|
||||
s.growth = 3.0
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.find_or_create_by!(skill_group: :group_iii, modifier: 1) do |s|
|
||||
s.name_en = 'Chain Burst DMG'
|
||||
s.name_jp = 'チェインダメ'
|
||||
s.base_values = [6, 7, 8, 9, 10]
|
||||
s.growth = 2.5
|
||||
s.polarity = :positive
|
||||
end
|
||||
ArtifactSkill.clear_cache!
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/users/:user_id/collection/artifacts' do
|
||||
let!(:collection_artifact1) { create(:collection_artifact, user: user, artifact: artifact) }
|
||||
let!(:collection_artifact2) { create(:collection_artifact, user: user, element: :water) }
|
||||
let!(:other_user_artifact) { create(:collection_artifact, user: other_user) }
|
||||
|
||||
it "returns the user's collection artifacts" do
|
||||
get "/api/v1/users/#{user.id}/collection/artifacts", headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifacts'].length).to eq(2)
|
||||
end
|
||||
|
||||
it 'supports pagination' do
|
||||
get "/api/v1/users/#{user.id}/collection/artifacts", params: { page: 1, limit: 1 }, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifacts'].length).to eq(1)
|
||||
expect(json['meta']['total_pages']).to be >= 2
|
||||
end
|
||||
|
||||
it 'filters by artifact_id' do
|
||||
get "/api/v1/users/#{user.id}/collection/artifacts", params: { artifact_id: artifact.id }, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifacts'].length).to eq(1)
|
||||
end
|
||||
|
||||
it 'filters by element' do
|
||||
get "/api/v1/users/#{user.id}/collection/artifacts", params: { element: 'water' }, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifacts'].all? { |a| a['element'] == 'water' }).to be true
|
||||
end
|
||||
|
||||
it 'returns unauthorized without authentication' do
|
||||
other_user.update!(collection_visibility: 'private')
|
||||
get "/api/v1/users/#{other_user.id}/collection/artifacts"
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/users/:user_id/collection/artifacts/:id' do
|
||||
let!(:collection_artifact) { create(:collection_artifact, user: user, artifact: artifact) }
|
||||
|
||||
it 'returns the collection artifact' do
|
||||
get "/api/v1/users/#{user.id}/collection/artifacts/#{collection_artifact.id}", headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['id']).to eq(collection_artifact.id)
|
||||
expect(json['artifact']['id']).to eq(artifact.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/collection/artifacts' do
|
||||
let(:valid_attributes) do
|
||||
{
|
||||
collection_artifact: {
|
||||
artifact_id: artifact.id,
|
||||
element: 'fire',
|
||||
level: 1,
|
||||
skill1: { modifier: 1, strength: 1800, level: 1 },
|
||||
skill2: { modifier: 2, strength: 900, level: 1 },
|
||||
skill3: { modifier: 1, strength: 18.0, level: 1 },
|
||||
skill4: { modifier: 1, strength: 10, level: 1 }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates a new collection artifact' do
|
||||
expect do
|
||||
post '/api/v1/collection/artifacts', params: valid_attributes.to_json, headers: headers
|
||||
end.to change(CollectionArtifact, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:created)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['artifact']['id']).to eq(artifact.id)
|
||||
expect(json['element']).to eq('fire')
|
||||
end
|
||||
|
||||
it 'allows multiple copies of the same artifact' do
|
||||
create(:collection_artifact, user: user, artifact: artifact)
|
||||
|
||||
expect do
|
||||
post '/api/v1/collection/artifacts', params: valid_attributes.to_json, headers: headers
|
||||
end.to change(CollectionArtifact, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:created)
|
||||
end
|
||||
|
||||
it 'creates artifact with nickname' do
|
||||
attributes_with_nickname = valid_attributes.deep_merge(
|
||||
collection_artifact: { nickname: 'My Best Artifact' }
|
||||
)
|
||||
|
||||
post '/api/v1/collection/artifacts', params: attributes_with_nickname.to_json, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:created)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['nickname']).to eq('My Best Artifact')
|
||||
end
|
||||
|
||||
it 'creates quirk artifact with proficiency' do
|
||||
quirk_attributes = {
|
||||
collection_artifact: {
|
||||
artifact_id: quirk_artifact.id,
|
||||
element: 'dark',
|
||||
proficiency: 'staff',
|
||||
level: 1,
|
||||
skill1: {},
|
||||
skill2: {},
|
||||
skill3: {},
|
||||
skill4: {}
|
||||
}
|
||||
}
|
||||
|
||||
post '/api/v1/collection/artifacts', params: quirk_attributes.to_json, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:created)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['proficiency']).to eq('staff')
|
||||
end
|
||||
|
||||
it 'returns error when skill1 and skill2 have same modifier' do
|
||||
invalid_attributes = valid_attributes.deep_merge(
|
||||
collection_artifact: {
|
||||
skill1: { modifier: 1, strength: 1800, level: 1 },
|
||||
skill2: { modifier: 1, strength: 1800, level: 1 }
|
||||
}
|
||||
)
|
||||
|
||||
post '/api/v1/collection/artifacts', params: invalid_attributes.to_json, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['errors'].to_s).to include('cannot have the same modifier')
|
||||
end
|
||||
|
||||
it 'returns unauthorized without authentication' do
|
||||
post '/api/v1/collection/artifacts', params: valid_attributes.to_json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v1/collection/artifacts/:id' do
|
||||
let!(:collection_artifact) { create(:collection_artifact, user: user, artifact: artifact, level: 1) }
|
||||
|
||||
it 'updates the collection artifact' do
|
||||
update_attributes = {
|
||||
collection_artifact: {
|
||||
nickname: 'Updated Name',
|
||||
element: 'water'
|
||||
}
|
||||
}
|
||||
|
||||
put "/api/v1/collection/artifacts/#{collection_artifact.id}",
|
||||
params: update_attributes.to_json, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['nickname']).to eq('Updated Name')
|
||||
expect(json['element']).to eq('water')
|
||||
end
|
||||
|
||||
it 'returns not found for other user\'s artifact' do
|
||||
other_collection = create(:collection_artifact, user: other_user)
|
||||
|
||||
put "/api/v1/collection/artifacts/#{other_collection.id}",
|
||||
params: { collection_artifact: { nickname: 'Hack' } }.to_json, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/collection/artifacts/:id' do
|
||||
let!(:collection_artifact) { create(:collection_artifact, user: user, artifact: artifact) }
|
||||
|
||||
it 'deletes the collection artifact' do
|
||||
expect do
|
||||
delete "/api/v1/collection/artifacts/#{collection_artifact.id}", headers: headers
|
||||
end.to change(CollectionArtifact, :count).by(-1)
|
||||
|
||||
expect(response).to have_http_status(:no_content)
|
||||
end
|
||||
|
||||
it 'returns not found for other user\'s artifact' do
|
||||
other_collection = create(:collection_artifact, user: other_user)
|
||||
|
||||
expect do
|
||||
delete "/api/v1/collection/artifacts/#{other_collection.id}", headers: headers
|
||||
end.not_to change(CollectionArtifact, :count)
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/collection/artifacts/batch' do
|
||||
let(:artifact2) { create(:artifact, :dagger) }
|
||||
|
||||
it 'creates multiple collection artifacts' do
|
||||
batch_attributes = {
|
||||
collection_artifacts: [
|
||||
{
|
||||
artifact_id: artifact.id,
|
||||
element: 'fire',
|
||||
level: 1,
|
||||
skill1: { modifier: 1, strength: 1800, level: 1 },
|
||||
skill2: { modifier: 2, strength: 900, level: 1 },
|
||||
skill3: { modifier: 1, strength: 18.0, level: 1 },
|
||||
skill4: { modifier: 1, strength: 10, level: 1 }
|
||||
},
|
||||
{
|
||||
artifact_id: artifact2.id,
|
||||
element: 'water',
|
||||
level: 1,
|
||||
skill1: { modifier: 1, strength: 1800, level: 1 },
|
||||
skill2: { modifier: 2, strength: 900, level: 1 },
|
||||
skill3: { modifier: 1, strength: 18.0, level: 1 },
|
||||
skill4: { modifier: 1, strength: 10, level: 1 }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
expect do
|
||||
post '/api/v1/collection/artifacts/batch', params: batch_attributes.to_json, headers: headers
|
||||
end.to change(CollectionArtifact, :count).by(2)
|
||||
|
||||
expect(response).to have_http_status(:created)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['meta']['created']).to eq(2)
|
||||
expect(json['meta']['errors']).to be_empty
|
||||
end
|
||||
|
||||
it 'returns multi_status when some items fail' do
|
||||
batch_attributes = {
|
||||
collection_artifacts: [
|
||||
{
|
||||
artifact_id: artifact.id,
|
||||
element: 'fire',
|
||||
level: 1,
|
||||
skill1: { modifier: 1, strength: 1800, level: 1 },
|
||||
skill2: { modifier: 2, strength: 900, level: 1 },
|
||||
skill3: { modifier: 1, strength: 18.0, level: 1 },
|
||||
skill4: { modifier: 1, strength: 10, level: 1 }
|
||||
},
|
||||
{
|
||||
artifact_id: artifact.id,
|
||||
element: 'invalid_element', # Invalid
|
||||
level: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
post '/api/v1/collection/artifacts/batch', params: batch_attributes.to_json, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:multi_status)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['meta']['created']).to eq(1)
|
||||
expect(json['meta']['errors'].length).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue