Browse Source

#61

feature/061
みてるぞ 1 week ago
parent
commit
5581d6e1cc
1 changed files with 219 additions and 55 deletions
  1. +219
    -55
      backend/spec/requests/tags_spec.rb

+ 219
- 55
backend/spec/requests/tags_spec.rb View File

@@ -11,16 +11,180 @@ RSpec.describe 'Tags API', type: :request do
let!(:tn2) { TagName.create!(name: 'unknown') }
let!(:tag2) { Tag.create!(tag_name: tn2, category: :general) }

def response_tags
json.fetch('tags')
end

def response_names
response_tags.map { |t| t.fetch('name') }
end

describe 'GET /tags' do
it 'returns tags with name' do
it 'returns tags with count and metadata' do
get '/tags'

expect(response).to have_http_status(:ok)
expect(json).to include('tags', 'count')
expect(response_tags).to be_an(Array)
expect(json['count']).to be_an(Integer)
expect(json['count']).to be >= response_tags.size

row = response_tags.find { |t| t['name'] == 'spec_tag' }
expect(row).to include(
'id' => tag.id,
'name' => 'spec_tag',
'category' => 'general',
'post_count' => 1,
'has_wiki' => false)
expect(row).to have_key('created_at')
expect(row).to have_key('updated_at')
end

expect(json).to be_an(Array)
expect(json).not_to be_empty
expect(json[0]).to have_key('name')
expect(json.map { |t| t['name'] }).to include('spec_tag')
it 'filters tags by post id' do
get '/tags', params: { post: post.id }

expect(response).to have_http_status(:ok)
expect(json['count']).to eq(1)
expect(response_names).to eq(['spec_tag'])
end

it 'filters tags by partial name' do
get '/tags', params: { name: 'spec' }

expect(response).to have_http_status(:ok)
expect(response_names).to include('spec_tag')
expect(response_names).not_to include('unknown')
end

it 'filters tags by category' do
meme = Tag.create!(tag_name: TagName.create!(name: 'meme_only'), category: :meme)

get '/tags', params: { category: 'meme' }

expect(response).to have_http_status(:ok)
expect(response_names).to eq(['meme_only'])
expect(response_tags.first['id']).to eq(meme.id)
end

it 'filters tags by post_count range' do
low = Tag.create!(tag_name: TagName.create!(name: 'pc_low'), category: :general)
mid = Tag.create!(tag_name: TagName.create!(name: 'pc_mid'), category: :general)
high = Tag.create!(tag_name: TagName.create!(name: 'pc_high'), category: :general)

low.update_columns(post_count: 1)
mid.update_columns(post_count: 3)
high.update_columns(post_count: 5)

get '/tags', params: {
name: 'pc_',
post_count_gte: 2,
post_count_lte: 4,
order: 'post_count:asc',
}

expect(response).to have_http_status(:ok)
expect(response_names).to eq(['pc_mid'])
end

it 'filters tags by created_at range' do
old_tag = Tag.create!(tag_name: TagName.create!(name: 'created_old'), category: :general)
new_tag = Tag.create!(tag_name: TagName.create!(name: 'created_new'), category: :general)

old_time = Time.zone.local(2024, 1, 1, 0, 0, 0)
new_time = Time.zone.local(2024, 2, 1, 0, 0, 0)

old_tag.update_columns(created_at: old_time, updated_at: old_time)
new_tag.update_columns(created_at: new_time, updated_at: new_time)

get '/tags', params: {
name: 'created_',
created_from: Time.zone.local(2024, 1, 15, 0, 0, 0).iso8601,
order: 'created_at:asc',
}

expect(response).to have_http_status(:ok)
expect(response_names).to eq(['created_new'])
end

it 'filters tags by updated_at range' do
old_tag = Tag.create!(tag_name: TagName.create!(name: 'updated_old'), category: :general)
new_tag = Tag.create!(tag_name: TagName.create!(name: 'updated_new'), category: :general)

old_time = Time.zone.local(2024, 3, 1, 0, 0, 0)
new_time = Time.zone.local(2024, 4, 1, 0, 0, 0)

old_tag.update_columns(created_at: old_time, updated_at: old_time)
new_tag.update_columns(created_at: new_time, updated_at: new_time)

get '/tags', params: {
name: 'updated_',
updated_to: Time.zone.local(2024, 3, 15, 0, 0, 0).iso8601,
order: 'updated_at:asc',
}

expect(response).to have_http_status(:ok)
expect(response_names).to eq(['updated_old'])
end

it 'orders tags by custom category order' do
Tag.create!(tag_name: TagName.create!(name: 'cat_deerjikist'), category: :deerjikist)
Tag.create!(tag_name: TagName.create!(name: 'cat_meme'), category: :meme)
Tag.create!(tag_name: TagName.create!(name: 'cat_character'), category: :character)
Tag.create!(tag_name: TagName.create!(name: 'cat_general'), category: :general)
Tag.create!(tag_name: TagName.create!(name: 'cat_material'), category: :material)
Tag.create!(tag_name: TagName.create!(name: 'cat_meta'), category: :meta)
Tag.create!(tag_name: TagName.create!(name: 'nico:cat_nico'), category: :nico)

get '/tags', params: { name: 'cat_', order: 'category:asc', limit: 20 }

expect(response).to have_http_status(:ok)
expect(response_names).to eq(%w[
cat_deerjikist
cat_meme
cat_character
cat_general
cat_material
cat_meta
nico:cat_nico
])
end

it 'paginates and keeps total count' do
%w[pag_a pag_b pag_c].each do |name|
Tag.create!(tag_name: TagName.create!(name:), category: :general)
end

get '/tags', params: { name: 'pag_', order: 'name:asc', page: 2, limit: 2 }

expect(response).to have_http_status(:ok)
expect(json['count']).to eq(3)
expect(response_names).to eq(%w[pag_c])
end

it 'falls back to default ordering when order is invalid' do
low = Tag.create!(tag_name: TagName.create!(name: 'fallback_low'), category: :general)
high = Tag.create!(tag_name: TagName.create!(name: 'fallback_high'), category: :general)

low.update_columns(post_count: 1)
high.update_columns(post_count: 9)

get '/tags', params: { name: 'fallback_', order: 'nope:sideways' }

expect(response).to have_http_status(:ok)
expect(response_names.first).to eq('fallback_high')
end

it 'normalises invalid page and limit' do
%w[norm_a norm_b].each do |name|
Tag.create!(tag_name: TagName.create!(name:), category: :general)
end

get '/tags', params: { name: 'norm_', order: 'name:asc', page: 0, limit: 0 }

expect(response).to have_http_status(:ok)
expect(json['count']).to eq(2)
expect(response_tags.size).to eq(1)
expect(response_names).to eq(['norm_a'])
end
end

@@ -37,9 +201,13 @@ RSpec.describe 'Tags API', type: :request do
expect(response).to have_http_status(:ok)

expect(json).to include(
'id' => tag.id,
'name' => 'spec_tag',
'category' => 'general')
'id' => tag.id,
'name' => 'spec_tag',
'category' => 'general',
'post_count' => 1,
'has_wiki' => false)
expect(json).to have_key('created_at')
expect(json).to have_key('updated_at')
end
end

@@ -61,7 +229,7 @@ RSpec.describe 'Tags API', type: :request do

expect(json).to be_an(Array)
expect(json.map { |t| t['name'] }).to include('spec_tag')
t = json.find { |t| t['name'] == 'spec_tag' }
t = json.find { |x| x['name'] == 'spec_tag' }
expect(t).to have_key('matched_alias')
expect(t['matched_alias']).to be(nil)
end
@@ -73,9 +241,9 @@ RSpec.describe 'Tags API', type: :request do

expect(json).to be_an(Array)
expect(json.map { |t| t['name'] }).to include('spec_tag')
t = json.find { |t| t['name'] == 'spec_tag' }
t = json.find { |x| x['name'] == 'spec_tag' }
expect(t['matched_alias']).to eq('unko')
expect(json.map { |t| t['name'] }).not_to include('unknown')
expect(json.map { |x| x['name'] }).not_to include('unknown')
end
end

@@ -85,10 +253,14 @@ RSpec.describe 'Tags API', type: :request do

expect(response).to have_http_status(:ok)

expect(json).to have_key('id')
expect(json).to have_key('name')
expect(json['id']).to eq(tag.id)
expect(json['name']).to eq('spec_tag')
expect(json).to include(
'id' => tag.id,
'name' => 'spec_tag',
'category' => 'general',
'post_count' => 1,
'has_wiki' => false)
expect(json).to have_key('created_at')
expect(json).to have_key('updated_at')
end

it 'returns 404 when not found' do
@@ -97,7 +269,6 @@ RSpec.describe 'Tags API', type: :request do
end
end

# member? を持つ user を想定(Factory 側で trait 作ってもOK)
let(:member_user) { create(:user) }
let(:non_member_user) { create(:user) }

@@ -110,87 +281,80 @@ RSpec.describe 'Tags API', type: :request do
allow(non_member_user).to receive(:gte_member?).and_return(false)
end

describe "PATCH /tags/:id" do
context "未ログイン" do
describe 'PATCH /tags/:id' do
context '未ログイン' do
before { stub_current_user(nil) }

it "401 を返す" do
patch "/tags/#{tag.id}", params: { name: "new" }
it '401 を返す' do
patch "/tags/#{ tag.id }", params: { name: 'new' }
expect(response).to have_http_status(:unauthorized)
end
end

context "ログインしてゐるが member でない" do
context 'ログインしてゐるが member でない' do
before { stub_current_user(non_member_user) }

it "403 を返す" do
patch "/tags/#{tag.id}", params: { name: "new" }
it '403 を返す' do
patch "/tags/#{ tag.id }", params: { name: 'new' }
expect(response).to have_http_status(:forbidden)
end
end

context "member" do
context 'member' do
before { stub_current_user(member_user) }

it "name だけ更新できる" do
patch "/tags/#{tag.id}", params: { name: "new" }
it 'name だけ更新できる' do
patch "/tags/#{ tag.id }", params: { name: 'new' }

expect(response).to have_http_status(:ok)

tag.reload
expect(tag.name).to eq("new")
expect(tag.category).to eq("general")
expect(tag.name).to eq('new')
expect(tag.category).to eq('general')

json = JSON.parse(response.body)
expect(json["id"]).to eq(tag.id)
expect(json["name"]).to eq("new")
expect(json["category"]).to eq("general")
body = JSON.parse(response.body)
expect(body['id']).to eq(tag.id)
expect(body['name']).to eq('new')
expect(body['category']).to eq('general')
end

it "category だけ更新できる" do
patch "/tags/#{tag.id}", params: { category: "meme" }
it 'category だけ更新できる' do
patch "/tags/#{ tag.id }", params: { category: 'meme' }

expect(response).to have_http_status(:ok)

tag.reload
expect(tag.name).to eq("spec_tag")
expect(tag.category).to eq("meme")
expect(tag.name).to eq('spec_tag')
expect(tag.category).to eq('meme')
end

it "空文字は presence により無視され、更新は走らない(値が変わらない)" do
patch "/tags/#{tag.id}", params: { name: "", category: " " }
it '空文字は presence により無視され、更新は走らない(値が変わらない)' do
patch "/tags/#{ tag.id }", params: { name: '', category: ' ' }

expect(response).to have_http_status(:ok)

tag.reload
expect(tag.name).to eq("spec_tag")
expect(tag.category).to eq("general")
expect(tag.name).to eq('spec_tag')
expect(tag.category).to eq('general')
end

it "両方更新できる" do
patch "/tags/#{tag.id}", params: { name: "n", category: "meta" }
it '両方更新できる' do
patch "/tags/#{ tag.id }", params: { name: 'n', category: 'meta' }

expect(response).to have_http_status(:ok)

tag.reload
expect(tag.name).to eq("n")
expect(tag.category).to eq("meta")
expect(tag.name).to eq('n')
expect(tag.category).to eq('meta')
end

it "存在しない id だと RecordNotFound になる(通常は 404)" do
# Rails 設定次第で例外がそのまま上がる/404になる
# APIなら rescue_from で 404 にしてることが多いので、その場合は 404 を期待。
patch "/tags/999999999", params: { name: "x" }

it '存在しない id だと RecordNotFound になる(通常は 404)' do
patch '/tags/999999999', params: { name: 'x' }
expect(response.status).to be_in([404, 500])
end

it "バリデーションで update! が失敗したら(通常は 422 か 500)" do
patch "/tags/#{tag.id}", params: { name: 'new', category: 'nico' }

# rescue_from の実装次第で変はる:
# - RecordInvalid を 422 にしてるなら 422
# - 未処理なら 500
it 'バリデーションで update! が失敗したら(通常は 422 か 500)' do
patch "/tags/#{ tag.id }", params: { name: 'new', category: 'nico' }
expect(response.status).to be_in([422, 500])
end
end


Loading…
Cancel
Save