広場投稿追加画面の刷新 (#399) (#413)

Reviewed-on: #413
Co-authored-by: miteruzo <miteruzo@naver.com>
Co-committed-by: miteruzo <miteruzo@naver.com>
このコミットはPull リクエスト #413 でマージされました.
このコミットが含まれているのは:
2026-07-19 00:03:10 +09:00
committed by みてるぞ
コミット f1181e8510
99個のファイルの変更10242行の追加1126行の削除
+77 -25
ファイルの表示
@@ -1,10 +1,10 @@
require "rails_helper"
require 'rails_helper'
RSpec.describe "nico:sync" do
RSpec.describe 'nico:sync' do
def stub_python(json_array)
status = instance_double(Process::Status, success?: true)
allow(Open3).to receive(:capture3).and_return([json_array.to_json, "", status])
allow(Open3).to receive(:capture3).and_return([json_array.to_json, '', status])
end
def create_tag!(name, category:)
@@ -16,17 +16,21 @@ RSpec.describe "nico:sync" do
NicoTagRelation.create!(nico_tag_id: nico_tag.id, tag_id: tag.id)
end
it "既存 post を見つけて、nico tag と linked tag を追加し、差分が出たら bot を付ける" do
it '既存 post を見つけて、nico tag と linked tag を追加し、差分が出たら bot を付ける' do
# 既存 post(正規表現で拾われるURL)
post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)
post = Post.create!(
title: 'old',
url: 'https://www.nicovideo.jp/watch/sm9',
uploaded_user: nil
)
# 既存の非nicoタグ(kept_non_nico_ids)
kept_general = create_tag!("spec_kept", category: "general")
kept_general = create_tag!('spec_kept', category: 'general')
PostTag.create!(post: post, tag: kept_general)
# 追加される linked tag を準備(nico tag に紐付く一般タグ)
linked = create_tag!("spec_linked", category: "general")
nico = create_tag!("nico:AAA", category: "nico")
linked = create_tag!('spec_linked', category: 'general')
nico = create_tag!('nico:AAA', category: 'nico')
link_nico_to_tag!(nico, linked)
# bot / tagme は task 内で使うので作っておく(Tag.bot/tagme がある前提)
@@ -42,43 +46,91 @@ RSpec.describe "nico:sync" do
'deleted_at' => '2026-01-31 00:00:00' }])
# 外部HTTPは今回「既存 post なので呼ばれない」はずだが、念のため塞ぐ
allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
run_rake_task("nico:sync")
run_rake_task('nico:sync')
post.reload
active_tag_names = post.tags.joins(:tag_name).pluck("tag_names.name")
active_tag_names = post.tags.joins(:tag_name).pluck('tag_names.name')
expect(active_tag_names).to include("spec_kept")
expect(active_tag_names).to include("nico:AAA")
expect(active_tag_names).to include("spec_linked")
expect(active_tag_names).to include('spec_kept')
expect(active_tag_names).to include('nico:AAA')
expect(active_tag_names).to include('spec_linked')
expect(post.original_created_from).to eq(Time.iso8601('2026-01-01T03:34:00Z'))
expect(post.original_created_before).to eq(Time.iso8601('2026-01-01T03:35:00Z'))
# 差分が出るので bot が付く(kept_non_nico_ids != desired_non_nico_ids)
expect(active_tag_names).to include("bot操作")
expect(active_tag_names).to include('bot操作')
end
it "既存 post にあった古い nico tag は active から外され、履歴として discard される" do
post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)
it '既存 post のサムネール取得に共通 attach 経路を使ふ' do
post = Post.create!(
title: 'old',
url: 'https://www.nicovideo.jp/watch/sm9',
uploaded_user: nil)
Tag.bot
Tag.tagme
stub_python([{ 'code' => 'sm9', 'title' => 't', 'tags' => [] }])
allow(URI).to receive(:open) do
StringIO.new(
'<meta name="thumbnail" content="https://example.com/thumb.jpg">')
end
expect_any_instance_of(Post).to receive(:attach_thumbnail_from_url!)
.with('https://example.com/thumb.jpg')
run_rake_task('nico:sync')
end
it 'サムネール取得失敗後も次回同期で再試行できる' do
post = Post.create!(
title: 'old',
url: 'https://www.nicovideo.jp/watch/sm9',
uploaded_user: nil)
Tag.bot
Tag.tagme
stub_python([{ 'code' => 'sm9', 'title' => 't', 'tags' => [] }])
allow(URI).to receive(:open) do
StringIO.new(
'<meta name="thumbnail" content="https://example.com/thumb.jpg">')
end
calls = 0
allow_any_instance_of(Post).to receive(:attach_thumbnail_from_url!) do
calls += 1
raise Post::RemoteThumbnailFetchFailed, 'failed'
end
2.times do
run_rake_task('nico:sync')
end
expect(calls).to eq(2)
end
it '既存 post にあった古い nico tag は active から外され、履歴として discard される' do
post = Post.create!(
title: 'old',
url: 'https://www.nicovideo.jp/watch/sm9',
uploaded_user: nil
)
# 旧nicoタグ(今回の同期結果に含まれない)
old_nico = create_tag!("nico:OLD", category: "nico")
old_nico = create_tag!('nico:OLD', category: 'nico')
old_pt = PostTag.create!(post: post, tag: old_nico)
expect(old_pt.discarded_at).to be_nil
# 今回は NEW のみ欲しい
new_nico = create_tag!("nico:NEW", category: "nico")
new_nico = create_tag!('nico:NEW', category: 'nico')
# bot/tagme 念のため
Tag.bot
Tag.tagme
stub_python([{ "code" => "sm9", "title" => "t", "tags" => ["NEW"] }])
allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))
stub_python([{ 'code' => 'sm9', 'title' => 't', 'tags' => ['NEW'] }])
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
run_rake_task("nico:sync")
run_rake_task('nico:sync')
# OLD は active から外れる(discarded_at が入る)
old_pts = PostTag.where(post_id: post.id, tag_id: old_nico.id).order(:id).to_a
@@ -86,9 +138,9 @@ RSpec.describe "nico:sync" do
# NEW は active にいる
post.reload
active_names = post.tags.joins(:tag_name).pluck("tag_names.name")
expect(active_names).to include("nico:NEW")
expect(active_names).not_to include("nico:OLD")
active_names = post.tags.joins(:tag_name).pluck('tag_names.name')
expect(active_names).to include('nico:NEW')
expect(active_names).not_to include('nico:OLD')
end
def snapshot_tags(post)