コミットを比較
2
コミット
| 作成者 | SHA1 | 日付 | |
|---|---|---|---|
|
|
63ea2727f0 | ||
|
|
e13a52db9a |
+1
-1
@@ -424,7 +424,7 @@ races according to the target constraint's business meaning.
|
||||
and JSON keys are generally snake_case.
|
||||
- Preserve existing HTTP status conventions:
|
||||
`:unauthorized` for no user, `:forbidden` for insufficient role or banned
|
||||
user, `:not_found` for missing records, and `:unprocessable_entity` for
|
||||
user, `:not_found` for missing records, and `:unprocessable_content` for
|
||||
validation failures.
|
||||
- For diagnostic or internal helper JSON, prefer a deliberately light response
|
||||
shape over full representation classes when callers only need identifiers,
|
||||
|
||||
@@ -95,7 +95,7 @@ class ApplicationController < ActionController::API
|
||||
render_validation_error base: ['すでに存在してゐます.']
|
||||
end
|
||||
|
||||
def render_validation_error record = nil, fields: { }, base: [], status: :unprocessable_entity
|
||||
def render_validation_error record = nil, fields: { }, base: [], status: :unprocessable_content
|
||||
errors = { }
|
||||
|
||||
if record
|
||||
|
||||
@@ -18,7 +18,7 @@ class CountsExportsController < ApplicationController
|
||||
render json: { error: 'private_condition' }, status: :forbidden
|
||||
rescue CountsTableQuery::TooManyColumns
|
||||
render json: { error: 'too_many_columns', max_columns: CountsTableQuery::MAX_COLUMNS },
|
||||
status: :unprocessable_entity
|
||||
status: :unprocessable_content
|
||||
rescue ActiveRecord::StatementTimeout
|
||||
render json: { error: 'counts_query_timeout' }, status: :service_unavailable
|
||||
rescue ArgumentError, TypeError, KeyError, JSON::ParserError
|
||||
@@ -63,7 +63,7 @@ class CountsExportsController < ApplicationController
|
||||
render json: { error: 'private_condition' }, status: :forbidden
|
||||
rescue CountsTableQuery::TooManyColumns
|
||||
render json: { error: 'too_many_columns', max_columns: CountsTableQuery::MAX_COLUMNS },
|
||||
status: :unprocessable_entity
|
||||
status: :unprocessable_content
|
||||
rescue ActiveRecord::StatementTimeout
|
||||
render json: { error: 'counts_query_timeout' }, status: :service_unavailable
|
||||
rescue ArgumentError, TypeError, KeyError, JSON::ParserError
|
||||
@@ -107,7 +107,7 @@ class CountsExportsController < ApplicationController
|
||||
render json: { error: 'private_condition' }, status: :forbidden
|
||||
rescue CountsTableQuery::TooManyColumns
|
||||
render json: { error: 'too_many_columns', max_columns: CountsTableQuery::MAX_COLUMNS },
|
||||
status: :unprocessable_entity
|
||||
status: :unprocessable_content
|
||||
rescue ActiveRecord::StatementTimeout
|
||||
render json: { error: 'counts_query_timeout' }, status: :service_unavailable
|
||||
rescue ArgumentError, TypeError, KeyError, JSON::ParserError
|
||||
|
||||
@@ -24,7 +24,7 @@ class CountsTablesController < ApplicationController
|
||||
render json: { error: 'private_condition' }, status: :forbidden
|
||||
rescue CountsTableQuery::TooManyColumns
|
||||
render json: { error: 'too_many_columns', max_columns: CountsTableQuery::MAX_COLUMNS },
|
||||
status: :unprocessable_entity
|
||||
status: :unprocessable_content
|
||||
rescue CountsPivotTotals::TimedOut
|
||||
Rails.logger.warn('counts_query_timeout: pivot_totals')
|
||||
render json: { error: 'counts_query_timeout', stage: 'totals',
|
||||
|
||||
@@ -15,7 +15,7 @@ class GekanatorGamesController < ApplicationController
|
||||
answers:)
|
||||
|
||||
if game.invalid?
|
||||
render json: { errors: game.errors.full_messages }, status: :unprocessable_entity
|
||||
render json: { errors: game.errors.full_messages }, status: :unprocessable_content
|
||||
return
|
||||
end
|
||||
|
||||
@@ -31,7 +31,7 @@ class GekanatorGamesController < ApplicationController
|
||||
learned_example_count:
|
||||
}, status: :created
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
render json: { errors: e.record.errors.full_messages }, status: :unprocessable_entity
|
||||
render json: { errors: e.record.errors.full_messages }, status: :unprocessable_content
|
||||
end
|
||||
|
||||
def extra_questions
|
||||
|
||||
@@ -536,7 +536,7 @@ class MaterialsController < ApplicationController
|
||||
errors: { },
|
||||
base_errors: ['ZIP export に必要な素材ファイルが欠損しています.'],
|
||||
missing_files: },
|
||||
status: :unprocessable_entity
|
||||
status: :unprocessable_content
|
||||
end
|
||||
|
||||
def build_uploaded_material_blob! file, file_sha256
|
||||
|
||||
@@ -429,7 +429,7 @@ class PostsController < ApplicationController
|
||||
filters = literals.map do |literal|
|
||||
internal, = source_ids.fetch(literal[:name])
|
||||
name = internal.empty? ? literal[:name] : names[internal.first]
|
||||
return head :unprocessable_entity unless name && internal.length <= 1
|
||||
return head :unprocessable_content unless name && internal.length <= 1
|
||||
|
||||
literal[:negative] ? "not:#{ name }" : name
|
||||
end
|
||||
@@ -438,7 +438,7 @@ class PostsController < ApplicationController
|
||||
literals.zip(translated).each do |literal, translation|
|
||||
unless (source_ids.fetch(literal[:name]).map(&:sort) ==
|
||||
target_ids.fetch(translation[:name]).map(&:sort))
|
||||
return head :unprocessable_entity
|
||||
return head :unprocessable_content
|
||||
end
|
||||
end
|
||||
index = 0
|
||||
|
||||
@@ -55,7 +55,7 @@ class TheatresController < ApplicationController
|
||||
theatre = Theatre.find_by(id: params[:id])
|
||||
return head :not_found unless theatre
|
||||
requested_post_id = params[:post_id].to_i
|
||||
return head :unprocessable_entity if requested_post_id <= 0
|
||||
return head :unprocessable_content if requested_post_id <= 0
|
||||
|
||||
skipped = false
|
||||
conflicted = false
|
||||
@@ -95,7 +95,7 @@ class TheatresController < ApplicationController
|
||||
theatre = Theatre.find_by(id: params[:id])
|
||||
return head :not_found unless theatre
|
||||
requested_post_id = params[:post_id].to_i
|
||||
return head :unprocessable_entity if requested_post_id <= 0
|
||||
return head :unprocessable_content if requested_post_id <= 0
|
||||
|
||||
conflicted = false
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ RSpec.describe 'Counts table API', type: :request do
|
||||
tags: '', tags_json: [], parent_post_ids: '', created_at: Time.utc(2024, 3))
|
||||
end
|
||||
get '/counts/query', params: base.merge(mode: 'summary', rows: '', cols: 'title', sort: '')
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(response.parsed_body).to eq('error' => 'too_many_columns', 'max_columns' => 100)
|
||||
end
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ RSpec.describe 'error responses', type: :request do
|
||||
|
||||
patch "/tags/#{ tag.id }", params: { category: 'nico' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json).to include(
|
||||
'type' => 'validation_error',
|
||||
'message' => '入力内容を確認してください.',
|
||||
@@ -37,7 +37,7 @@ RSpec.describe 'error responses', type: :request do
|
||||
|
||||
put "/users/#{ user.id }", params: { name: 'a' * 256 }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json).to include(
|
||||
'type' => 'validation_error',
|
||||
'message' => '入力内容を確認してください.')
|
||||
|
||||
@@ -49,7 +49,7 @@ RSpec.describe 'Gekanator games API', type: :request do
|
||||
question_count: 4,
|
||||
answers: [{ question_id: 'tag:1', answer: 'no' }] }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'returns unauthorized without a user' do
|
||||
|
||||
@@ -126,7 +126,7 @@ RSpec.describe 'Gekanator learning API', type: :request do
|
||||
}
|
||||
}.not_to change { GekanatorGame.count }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'stores a game result for a non-admin user' do
|
||||
@@ -785,7 +785,7 @@ RSpec.describe 'Gekanator learning API', type: :request do
|
||||
}
|
||||
}.not_to change { GekanatorQuestionExample.count }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'rejects non-accepted questions' do
|
||||
@@ -805,7 +805,7 @@ RSpec.describe 'Gekanator learning API', type: :request do
|
||||
]
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'rejects non-post_similarity questions' do
|
||||
@@ -829,7 +829,7 @@ RSpec.describe 'Gekanator learning API', type: :request do
|
||||
]
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'allows a non-admin user to answer extra questions for their own game' do
|
||||
|
||||
@@ -55,7 +55,7 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
deprecated: false, aliases: 'other_primary', parent_tags: '' }
|
||||
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(other_primary.reload).to have_attributes(tag_id: other_tag.id, primary_flg: true)
|
||||
expect(TagName.where(tag: other_tag, language_code: 'ja', primary_flg: true))
|
||||
.to contain_exactly(other_primary)
|
||||
@@ -289,7 +289,7 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
aliases: 'other_ainu_primary', parent_tags: '' }
|
||||
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(other_primary.reload).to have_attributes(
|
||||
tag_id: other_tag.id, language_code: 'ain', primary_flg: true)
|
||||
expect(TagName.where(tag: other_tag, language_code: 'ain', primary_flg: true))
|
||||
|
||||
@@ -289,7 +289,7 @@ RSpec.describe 'Materials API', type: :request do
|
||||
it 'returns 422 when tag is blank' do
|
||||
post '/materials', params: { tag: ' ', file: dummy_upload }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'tag' => ['タグは必須です.'])
|
||||
end
|
||||
@@ -297,7 +297,7 @@ RSpec.describe 'Materials API', type: :request do
|
||||
it 'returns 422 when both file and url are blank' do
|
||||
post '/materials', params: { tag: 'material_create_blank' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'file' => ['ファイルまたは URL は必須です.'],
|
||||
'url' => ['ファイルまたは URL は必須です.'])
|
||||
@@ -381,7 +381,7 @@ RSpec.describe 'Materials API', type: :request do
|
||||
file: dummy_upload
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'persists url-only material' do
|
||||
@@ -424,7 +424,7 @@ RSpec.describe 'Materials API', type: :request do
|
||||
}
|
||||
end.not_to change(Material, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'file' => ['抑止された素材です: copyright_high_risk']
|
||||
)
|
||||
@@ -484,7 +484,7 @@ RSpec.describe 'Materials API', type: :request do
|
||||
file: dummy_upload
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'tag' => ['タグは必須です.'])
|
||||
end
|
||||
@@ -695,7 +695,7 @@ RSpec.describe 'Materials API', type: :request do
|
||||
file: dummy_upload(filename: 'blocked.png', body: 'blocked-update')
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(material.reload.file.blob.filename.to_s).to eq('old.png')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -218,7 +218,7 @@ RSpec.describe 'NicoTags', type: :request do
|
||||
|
||||
patch "/tags/nico/#{nico_tag.id}", params: { tags: 'nico:linked_ng' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'tags' => ['ニコニコ・タグ同士は連携できません.'])
|
||||
end
|
||||
@@ -239,7 +239,7 @@ RSpec.describe 'NicoTags', type: :request do
|
||||
|
||||
expect([Tag.count, TagName.count, TagVersion.count]).to eq(before_counts)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors').fetch('tags')).to include(
|
||||
a_string_including('タグ名 “invalid”:', '名前に使用できない文字が含まれてゐます.'))
|
||||
end
|
||||
|
||||
@@ -48,7 +48,7 @@ RSpec.describe 'Post filter identity across locales', type: :request do
|
||||
primary_tag_name_for(tag, 'ja').update_columns(name: 'nico:shared')
|
||||
get '/posts/tag_filters', params: {
|
||||
locale: 'ja', target_locale: 'ain-Kana', tags: 'nico:shared' }
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'rejects removed reference parameters instead of overriding the name' do
|
||||
|
||||
@@ -1042,7 +1042,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
|
||||
get '/posts/metadata', params: { url: 'file:///etc/passwd' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to have_key('url')
|
||||
end
|
||||
end
|
||||
@@ -1180,7 +1180,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
)
|
||||
}.not_to change(Post, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'thumbnail' => ['サムネイル画像の変換に失敗しました.']
|
||||
)
|
||||
@@ -1219,7 +1219,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'tags' => ['廃止済みタグがあります: deprecated_direct_tag']
|
||||
)
|
||||
@@ -1265,7 +1265,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json).to include(
|
||||
'type' => 'validation_error',
|
||||
'message' => '入力内容を確認してください.'
|
||||
@@ -1333,7 +1333,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'video_ms' => ['タグ区間の終端が動画時間を超えてゐます.']
|
||||
)
|
||||
@@ -1444,7 +1444,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'video_ms' => ['タグ区間の開始が動画時間以上です.']
|
||||
)
|
||||
@@ -1465,7 +1465,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity), response.body
|
||||
expect(response).to have_http_status(:unprocessable_content), response.body
|
||||
expect(json).to include(
|
||||
'type' => 'validation_error',
|
||||
'message' => '入力内容を確認してください.',
|
||||
@@ -1485,7 +1485,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
tags: 'spec_tag', # 既存タグ名を投げる
|
||||
thumbnail: dummy_upload)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1499,7 +1499,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
tags: 'spec_tag', # 既存タグ名を投げる
|
||||
thumbnail: dummy_upload)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1601,7 +1601,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload }
|
||||
}.not_to change(Post, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to be_present
|
||||
end
|
||||
end
|
||||
@@ -1620,7 +1620,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
)
|
||||
}.not_to change(Post, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to be_present
|
||||
end
|
||||
end
|
||||
@@ -1639,7 +1639,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
)
|
||||
}.not_to change(PostImplication, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to be_present
|
||||
end
|
||||
end
|
||||
@@ -1770,7 +1770,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
tags: 'deprecated_update_tag'
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'tags' => ['廃止済みタグは付与できません.']
|
||||
)
|
||||
@@ -1789,7 +1789,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
title: 'updated title',
|
||||
tags: 'nico:nico_tag')
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity), response.body
|
||||
expect(response).to have_http_status(:unprocessable_content), response.body
|
||||
expect(json).to include(
|
||||
'type' => 'validation_error',
|
||||
'message' => '入力内容を確認してください.',
|
||||
@@ -1896,7 +1896,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
title: 'updated title',
|
||||
tags: 'spec_tag' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to be_present
|
||||
end
|
||||
end
|
||||
@@ -1922,7 +1922,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
parent_post_ids: 'abc'
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(post_record.reload.parent_posts.pluck(:id)).to eq([parent_post.id])
|
||||
end
|
||||
end
|
||||
@@ -1948,7 +1948,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
parent_post_ids: '999999999'
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(post_record.reload.parent_posts.pluck(:id)).to eq([parent_post.id])
|
||||
end
|
||||
end
|
||||
@@ -1964,7 +1964,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
parent_post_ids: post_record.id.to_s
|
||||
)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
|
||||
expect(PostImplication.exists?(
|
||||
post_id: post_record.id,
|
||||
@@ -2669,7 +2669,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload)
|
||||
end.not_to change(PostVersion, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'does not create a version when PUT /posts/:id is invalid' do
|
||||
@@ -2685,7 +2685,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
original_created_before: Time.zone.local(2020, 1, 1, 0, 0, 0).iso8601)
|
||||
end.not_to change(PostVersion, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'rejects second-bearing original created timestamps on POST /posts' do
|
||||
@@ -2698,7 +2698,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload,
|
||||
original_created_from: '2020-01-01T00:00:01Z')
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'original_created_from' => ['オリジナルの作成日時は分単位で入力してください.']
|
||||
)
|
||||
@@ -2715,7 +2715,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
thumbnail: dummy_upload,
|
||||
original_created_before: '2020-01-01T00:00:00.123Z')
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'original_created_before' => ['オリジナルの作成日時は分単位で入力してください.']
|
||||
)
|
||||
@@ -2733,7 +2733,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
original_created_from: '2020-01-01T00:00Z',
|
||||
original_created_before: '2020-01-01T00:00Z')
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'original_created_at' => ['オリジナルの作成日時の順番がをかしぃです.']
|
||||
)
|
||||
@@ -2767,7 +2767,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
tags: 'spec_tag',
|
||||
original_created_from: 'not-a-time')
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'original_created_from' => ['オリジナルの作成日時の形式が不正です.']
|
||||
)
|
||||
|
||||
@@ -64,7 +64,7 @@ RSpec.describe "TagChildren", type: :request do
|
||||
do_request
|
||||
}.not_to change(TagImplication, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(TagImplication.where(tag: child, parent_tag: parent)).not_to exist
|
||||
end
|
||||
end
|
||||
|
||||
@@ -303,7 +303,7 @@ RSpec.describe 'Tag description native API', type: :request do
|
||||
headers
|
||||
before_state = stored_state
|
||||
native_write(body: '')
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json).to include('type' => 'validation_error',
|
||||
'errors' => include('body' => a_kind_of(Array)))
|
||||
expect(stored_state).to eq(before_state)
|
||||
|
||||
@@ -84,7 +84,7 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
put "/wiki/#{ group.id }", params: {
|
||||
locale: 'ain-Kana', title: 'タググループ:partial rename', body: '- japanese_member' },
|
||||
headers: headers
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
@@ -117,7 +117,7 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
expect(representation.fetch('members').sole.fetch('tag').fetch('name')).to be_nil
|
||||
expect(representation.fetch('placements').sole.fetch('tag').fetch('name')).to be_nil
|
||||
get "/wiki/#{ old_group.id }", params: { locale: 'ain-Kana', version: version.id }
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(response.body).not_to include('historical_japanese', 'current_ainu')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -133,7 +133,7 @@ RSpec.describe 'Tag group Markdown round trips through the Wiki facade', type: :
|
||||
|
||||
get group_title_path('混在構造')
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_rows('tag_groups', id:).sole.fetch('id')).to eq(id)
|
||||
end
|
||||
|
||||
@@ -142,7 +142,7 @@ RSpec.describe 'Tag group Markdown round trips through the Wiki facade', type: :
|
||||
|
||||
get group_title_path('未配置構造')
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_rows('tag_groups', id:).sole.fetch('id')).to eq(id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,7 +21,7 @@ RSpec.describe 'Tag group Wiki facade writes', type: :request do
|
||||
before_state = group_state
|
||||
yield
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
expect(response.media_type).to eq('application/json')
|
||||
expect(response.body).not_to be_empty
|
||||
|
||||
@@ -27,7 +27,7 @@ RSpec.describe 'Tag group write integrity', type: :request do
|
||||
def expect_no_writes
|
||||
before_state = group_state
|
||||
yield
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ RSpec.describe 'Tag group native API', type: :request do
|
||||
before_state = group_state
|
||||
native_write(operation, payload.merge(invalid))
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
end
|
||||
@@ -158,7 +158,7 @@ RSpec.describe 'Tag group native API', type: :request do
|
||||
before_state = group_state
|
||||
invalid = [{ tag_id: tag.id, section_name: '不正', children: [] }]
|
||||
native_write(operation, payload.merge(placements: invalid))
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
@@ -167,7 +167,7 @@ RSpec.describe 'Tag group native API', type: :request do
|
||||
before_state = group_state
|
||||
native_write(operation, payload.merge(
|
||||
members: [{ tag_id: missing }], placements: [{ tag_id: missing, children: [] }]))
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
@@ -177,7 +177,7 @@ RSpec.describe 'Tag group native API', type: :request do
|
||||
native_write(operation, payload.merge(
|
||||
members: [{ tag_group_id: missing }],
|
||||
placements: [{ tag_group_id: missing, children: [] }]))
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
@@ -186,7 +186,7 @@ RSpec.describe 'Tag group native API', type: :request do
|
||||
6.times { nodes = [{ tag_id: tag.id, children: nodes }] }
|
||||
before_state = group_state
|
||||
native_write(operation, payload.merge(placements: nodes))
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
end
|
||||
@@ -206,7 +206,7 @@ RSpec.describe 'Tag group native API', type: :request do
|
||||
before_state = group_state
|
||||
native_write(:update, payload.merge(
|
||||
members: [{ tag_group_id: parent }], placements: []))
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
@@ -214,7 +214,7 @@ RSpec.describe 'Tag group native API', type: :request do
|
||||
before_state = group_state
|
||||
native_write(:update, payload.merge(
|
||||
members: [{ tag_group_id: group_id }], placements: []))
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ RSpec.describe 'Tags deerjikists API', type: :request do
|
||||
do_request
|
||||
}.not_to change { Deerjikist.where(tag: tag).map { |d| [d.platform, d.code] } }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json).to include(
|
||||
'type' => 'validation_error',
|
||||
'message' => '入力内容を確認してください.',
|
||||
@@ -321,7 +321,7 @@ RSpec.describe 'Tags deerjikists API', type: :request do
|
||||
do_request
|
||||
}.not_to change { Deerjikist.where(tag: tag).map { |d| [d.platform, d.code] } }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'deerjikists.0.platform' => [be_present],
|
||||
)
|
||||
@@ -352,7 +352,7 @@ RSpec.describe 'Tags deerjikists API', type: :request do
|
||||
do_request
|
||||
}.not_to change { Deerjikist.order(:platform, :code).pluck(:platform, :code, :tag_id) }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'deerjikists.1.code' => [include('existing-deerjikist')],
|
||||
)
|
||||
|
||||
@@ -696,7 +696,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
it 'nico category への変更は 422 を返す' do
|
||||
patch "/tags/#{tag.id}", params: { name: 'new', category: 'nico' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(primary_tag_name_for(tag.reload, 'ja').name).to eq('spec_tag')
|
||||
expect(tag.category).to eq('general')
|
||||
end
|
||||
@@ -740,7 +740,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
patch "/tags/#{tag.id}", params: { category: 'nico' }
|
||||
}.not_to change(TagVersion, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(tag.reload.category).to eq('general')
|
||||
end
|
||||
|
||||
@@ -824,7 +824,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
|
||||
patch "/tags/#{ tag.id }", params: { name: 'unknown' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'name' => ['その名前は既に使はれてゐます.']
|
||||
)
|
||||
@@ -840,7 +840,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
|
||||
patch "/tags/#{ system_tag.id }", params: { name: 'patch_system_tag_renamed' }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(primary_tag_name_for(system_tag.reload, 'ja').name).to eq('bot操作')
|
||||
end
|
||||
end
|
||||
@@ -1144,7 +1144,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
parent_tags: '',
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(primary_tag_name_for(tag.reload, 'ja').name).to eq('spec_tag')
|
||||
end
|
||||
|
||||
@@ -1156,7 +1156,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
parent_tags: '',
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(primary_tag_name_for(tag.reload, 'ja').name).to eq('spec_tag')
|
||||
expect(tag.category).to eq('general')
|
||||
end
|
||||
@@ -1169,7 +1169,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
parent_tags: '',
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'deprecated' => ['廃止状態は必須です.']
|
||||
)
|
||||
@@ -1366,7 +1366,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
}
|
||||
}.not_to change(TagVersion, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
|
||||
expect(primary_tag_name_for(tag.reload, 'ja').name).to eq('spec_tag')
|
||||
expect(tag.category).to eq('general')
|
||||
@@ -1387,7 +1387,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
}
|
||||
}.not_to change(TagVersion, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
|
||||
expect(primary_tag_name_for(system_tag.reload, 'ja').name).to eq(old_name)
|
||||
expect(system_tag.category).to eq(old_category)
|
||||
@@ -1569,7 +1569,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
deprecated: '0',
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
|
||||
expect(TagImplication.where(tag:, parent_tag: child)).not_to exist
|
||||
end
|
||||
|
||||
@@ -131,7 +131,7 @@ RSpec.describe 'TheatreComments', type: :request do
|
||||
post "/theatres/#{theatre.id}/comments", params: { content: ' ' }
|
||||
}.not_to change(TheatreComment, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'theatre が存在しなければ 404 を返す' do
|
||||
|
||||
@@ -376,7 +376,7 @@ RSpec.describe 'Theatres API', type: :request do
|
||||
put "/theatres/#{theatre.id}/skip_vote", params: { post_id: 'invalid' }
|
||||
}.not_to change(TheatreSkipVote, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'records a vote and returns the current vote status before majority' do
|
||||
|
||||
@@ -79,7 +79,7 @@ RSpec.describe 'user settings', type: :request do
|
||||
|
||||
patch '/users/settings', params: { theme: 1 }, as: :json
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json).to include('type' => 'validation_error')
|
||||
expect(json.fetch('errors')).to include(
|
||||
'theme' => ['値の型が不正です.'])
|
||||
@@ -90,7 +90,7 @@ RSpec.describe 'user settings', type: :request do
|
||||
|
||||
patch '/users/settings', params: { theme: 'neon' }, as: :json
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json).to include('type' => 'validation_error')
|
||||
expect(json.fetch('errors').fetch('theme')).to be_present
|
||||
end
|
||||
|
||||
@@ -84,7 +84,7 @@ RSpec.describe 'user theme slots', type: :request do
|
||||
params: { tokens: 'not-object' },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'base_theme' => ['値が不正です.'])
|
||||
end
|
||||
@@ -96,7 +96,7 @@ RSpec.describe 'user theme slots', type: :request do
|
||||
params: { tokens: 'not-object' },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'tokens' => ['JSON object で指定してください.'])
|
||||
end
|
||||
|
||||
@@ -119,7 +119,7 @@ RSpec.describe 'Users', type: :request do
|
||||
params: { name: ' ' },
|
||||
headers: auth_headers(user)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'name' => ['名前は必須です.'])
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ RSpec.describe 'Wiki creation freeze', type: :request do
|
||||
it "rejects invalid description body #{ body.inspect } atomically" do
|
||||
before_state = group_state
|
||||
put "/wiki/#{ page.id }", params: { title: tag.name('ja'), body: }, headers: headers
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,12 +100,12 @@ RSpec.describe 'Wiki API', type: :request do
|
||||
context 'when params invalid' do
|
||||
it 'returns 422 when title blank' do
|
||||
post endpoint, params: { title: '', body: 'Hello' }, headers: auth_headers(member)
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
|
||||
it 'returns 422 when body blank' do
|
||||
post endpoint, params: { title: 'Test', body: '' }, headers: auth_headers(member)
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -160,7 +160,7 @@ RSpec.describe 'Wiki API', type: :request do
|
||||
put "/wiki/#{page.id}",
|
||||
params: { title: 'TestPage', body: '' },
|
||||
headers: auth_headers(member)
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ RSpec.describe 'Wiki title collision', type: :request do
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
|
||||
source.reload
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ RSpec.describe 'Removed standalone Wiki resources', type: :request do
|
||||
before_state = group_state
|
||||
post '/wiki', params: { title:, body: 'body' },
|
||||
headers: cookie_headers(user)
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response).to have_http_status(:unprocessable_content)
|
||||
expect(group_state).to eq(before_state)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,13 +36,10 @@ const replaceToken = (value: string, start: number, end: number, text: string) =
|
||||
type Props = Omit<ComponentPropsWithoutRef<'textarea'>, 'value' | 'onChange' | 'onBlur'> & {
|
||||
tags: string
|
||||
setTags: (tags: string) => void
|
||||
label?: ReactNode
|
||||
errors?: ReactNode[] }
|
||||
|
||||
|
||||
const PostFormTagsArea: FC<Props> = (
|
||||
{ tags, setTags, label: fieldLabel, errors, ...rest },
|
||||
) => {
|
||||
const PostFormTagsArea: FC<Props> = ({ tags, setTags, errors, ...rest }) => {
|
||||
const { label } = useUITranslation ('navigation')
|
||||
const locale = useLocale ()
|
||||
const ref = useRef<HTMLTextAreaElement> (null)
|
||||
@@ -120,10 +117,7 @@ const PostFormTagsArea: FC<Props> = (
|
||||
}, [locale])
|
||||
|
||||
return (
|
||||
<FormField
|
||||
className="relative w-full"
|
||||
label={fieldLabel ?? label ('tags')}
|
||||
messages={errors}>
|
||||
<FormField className="relative w-full" label={label ('tags')} messages={errors}>
|
||||
{({ describedBy, invalid }) => (
|
||||
<>
|
||||
<TextArea
|
||||
|
||||
@@ -70,6 +70,16 @@ describe ('SidebarComponent', () => {
|
||||
vi.spyOn (HTMLElement.prototype, 'hasPointerCapture').mockReturnValue (true)
|
||||
})
|
||||
|
||||
it ('limits sidebar scrolling to desktop to avoid clipping mobile suggestions', () => {
|
||||
renderSidebar ()
|
||||
|
||||
// jsdom has no layout; guard the responsive classes responsible for clipping.
|
||||
const sidebar = screen.getByText ('Sidebar body')
|
||||
|
||||
expect (sidebar).not.toHaveClass ('overflow-y-auto')
|
||||
expect (sidebar).toHaveClass ('md:overflow-y-auto')
|
||||
})
|
||||
|
||||
it ('uses maxWidth without applying the container main-width reserve twice', async () => {
|
||||
localStorage.setItem ('sidebar:test-sidebar:left:width', '700')
|
||||
const onWidthChange = vi.fn ()
|
||||
|
||||
@@ -339,7 +339,7 @@ const SidebarComponent: FC<Props> = ({
|
||||
</style>
|
||||
</Helmet>
|
||||
|
||||
<div className="h-full overflow-y-auto p-4 sidebar">
|
||||
<div className="h-full md:overflow-y-auto p-4 sidebar">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -162,13 +162,12 @@ describe ('NicoTagListPage', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it ('saves links after completing the tag at the cursor', async () => {
|
||||
it ('updates links from a tag card', async () => {
|
||||
api.apiGet
|
||||
.mockResolvedValueOnce ({
|
||||
tags: [buildNicoTag ({ id: 7, name: 'nico:source' })],
|
||||
count: 1,
|
||||
})
|
||||
.mockResolvedValueOnce ([buildTag ({ id: 8, name: '連携先', postCount: 3 })])
|
||||
.mockResolvedValueOnce ({
|
||||
tags: [
|
||||
buildNicoTag ({
|
||||
@@ -184,24 +183,8 @@ describe ('NicoTagListPage', () => {
|
||||
renderPage ()
|
||||
|
||||
fireEvent.click (await screen.findByRole ('button', { name: '編集' }))
|
||||
const textarea = screen.getByLabelText ('連携する広場タグ')
|
||||
fireEvent.change (textarea, { target: { value: '既存 連携\n後続' } })
|
||||
fireEvent.focus (textarea)
|
||||
fireEvent.select (textarea, {
|
||||
target: { selectionStart: 4, selectionEnd: 4 } })
|
||||
|
||||
await waitFor (() => {
|
||||
expect (api.apiGet).toHaveBeenCalledWith (
|
||||
'/tags/autocomplete',
|
||||
{ locale: 'ja', params: { q: '連携', nico: '0' },
|
||||
signal: expect.any (AbortSignal) })
|
||||
})
|
||||
fireEvent.mouseDown (await screen.findByText ('連携先'))
|
||||
|
||||
expect (textarea).toHaveValue ('既存 連携先 \n後続')
|
||||
await waitFor (() => {
|
||||
expect ((textarea as HTMLTextAreaElement).selectionStart).toBe (7)
|
||||
expect ((textarea as HTMLTextAreaElement).selectionEnd).toBe (7)
|
||||
fireEvent.change (screen.getByLabelText ('連携する広場タグ'), {
|
||||
target: { value: '連携先' },
|
||||
})
|
||||
fireEvent.click (screen.getByRole ('button', { name: '保存' }))
|
||||
|
||||
@@ -212,8 +195,6 @@ describe ('NicoTagListPage', () => {
|
||||
{ locale: 'ja', headers: { 'Content-Type': 'multipart/form-data' } },
|
||||
)
|
||||
})
|
||||
const payload = api.apiPut.mock.calls[0][1] as FormData
|
||||
expect (payload.get ('tags')).toBe ('既存 連携先 \n後続')
|
||||
expect (await screen.findByText ('1 件')).toBeInTheDocument ()
|
||||
})
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@ import { useLocation } from 'react-router-dom'
|
||||
import { useLocale, useLocaleNavigate } from '@/lib/useLocale'
|
||||
import TagLink from '@/components/TagLink'
|
||||
import SortHeader from '@/components/SortHeader'
|
||||
import PostFormTagsArea from '@/components/PostFormTagsArea'
|
||||
import FieldError from '@/components/common/FieldError'
|
||||
import FormField from '@/components/common/FormField'
|
||||
import PageTitle from '@/components/common/PageTitle'
|
||||
import Pagination from '@/components/common/Pagination'
|
||||
import TextArea from '@/components/common/TextArea'
|
||||
import useDialogue from '@/lib/dialogues/useDialogue'
|
||||
import MainArea from '@/components/layout/MainArea'
|
||||
import { toast } from '@/components/ui/use-toast'
|
||||
@@ -356,18 +357,21 @@ const NicoTagListPage: FC<Props> = ({ user }) => {
|
||||
dark:bg-rose-950/30">
|
||||
<td colSpan={editable ? 5 : 4} className="p-3">
|
||||
<div className="space-y-2">
|
||||
<PostFormTagsArea
|
||||
<label htmlFor={`nico-links-${ tag.id }`}
|
||||
className="block text-sm font-semibold">
|
||||
{label ('nico.tagsToLink')}
|
||||
</label>
|
||||
<TextArea
|
||||
id={`nico-links-${ tag.id }`}
|
||||
label={label ('nico.tagsToLink')}
|
||||
aria-label={message ('nico.tagsToLink').text}
|
||||
tags={rawTags[tag.id] ?? ''}
|
||||
errors={errors}
|
||||
value={rawTags[tag.id] ?? ''}
|
||||
invalid={(errorsByTagId[tag.id] ?? []).length > 0}
|
||||
className="min-h-24 resize-y"
|
||||
placeholder={message ('nico.tagsPlaceholder').text}
|
||||
lang={message ('nico.tagsPlaceholder').language}
|
||||
setTags={value => setRawTags (rawTags => ({
|
||||
onChange={e => setRawTags (rawTags => ({
|
||||
...rawTags,
|
||||
[tag.id]: value}))}/>
|
||||
[tag.id]: e.target.value}))}/>
|
||||
<FieldError messages={errors}/>
|
||||
<div className="flex justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -35,6 +35,10 @@ const renderPage = () =>
|
||||
describe ('TagDetailPage', () => {
|
||||
beforeEach (() => {
|
||||
vi.clearAllMocks ()
|
||||
tagsApi.fetchTag.mockReset ()
|
||||
api.apiPut.mockReset ()
|
||||
api.isApiError.mockReset ()
|
||||
toastApi.toast.mockReset ()
|
||||
api.isApiError.mockReturnValue (false)
|
||||
})
|
||||
|
||||
@@ -51,8 +55,11 @@ describe ('TagDetailPage', () => {
|
||||
})
|
||||
|
||||
it ('submits edited tag fields', async () => {
|
||||
tagsApi.fetchTag.mockResolvedValueOnce (buildTag ({ id: 7, name: 'old' }))
|
||||
api.apiPut.mockResolvedValueOnce (buildTag ({ id: 7, name: 'new', aliases: ['alias'] }))
|
||||
const updatedTag = buildTag ({ id: 7, name: 'new', aliases: ['alias'] })
|
||||
tagsApi.fetchTag
|
||||
.mockResolvedValue (updatedTag)
|
||||
.mockResolvedValueOnce (buildTag ({ id: 7, name: 'old' }))
|
||||
api.apiPut.mockResolvedValueOnce (updatedTag)
|
||||
|
||||
renderPage ()
|
||||
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする