require 'digest' require 'rails_helper' require 'stringio' RSpec.describe 'WikiAssets API', type: :request do def dummy_upload(content = 'dummy-image', filename: 'dummy.png', content_type: 'image/png') Rack::Test::UploadedFile.new(StringIO.new(content), content_type, original_filename: filename) end let(:member) { create(:user, :member, name: 'member user') } let(:guest) { create(:user, name: 'guest user') } let!(:tag_name) { TagName.create!(name: 'spec_wiki_asset_page') } let!(:page) do WikiPage.create!(tag_name: tag_name, created_user: member, updated_user: member).tap do |p| Wiki::Commit.content!(page: p, body: 'init', created_user: member, message: 'init') end end describe 'GET /wiki/:wiki_page_id/assets' do subject(:do_request) do get "/wiki/#{wiki_page_id}/assets" end let(:wiki_page_id) { page.id } let!(:asset) do WikiAsset.new(wiki_page: page, no: 1, alt_text: 'spec alt', sha256: Digest::SHA256.digest('asset-1'), created_by_user: member).tap do |record| record.file.attach(dummy_upload('asset-1')) record.save! end end context 'when wiki page exists' do it 'returns assets for the page' do do_request expect(response).to have_http_status(:ok) expect(json).to be_an(Array) expect(json.size).to eq(1) expect(json.first).to include( 'wiki_page_id' => page.id, 'no' => 1) end it 'does not include assets from other pages' do other_tag_name = TagName.create!(name: 'spec_other_wiki_asset_page') other_page = WikiPage.create!(tag_name: other_tag_name, created_user: member, updated_user: member) Wiki::Commit.content!(page: other_page, body: 'other', created_user: member, message: 'other') WikiAsset.new(wiki_page: other_page, no: 1, alt_text: 'other alt', sha256: Digest::SHA256.digest('asset-2'), created_by_user: member).tap do |record| record.file.attach(dummy_upload('asset-2', filename: 'other.png')) record.save! end do_request expect(response).to have_http_status(:ok) expect(json.size).to eq(1) expect(json.first['wiki_page_id']).to eq(page.id) end end context 'when wiki page does not exist' do let(:wiki_page_id) { 999_999_999 } it 'returns 404' do do_request expect(response).to have_http_status(:not_found) end end end describe 'POST /wiki/:wiki_page_id/assets' do subject(:do_request) do post "/wiki/#{wiki_page_id}/assets", params: params end let(:wiki_page_id) { page.id } let(:params) do { file: dummy_upload(upload_content), alt_text: 'uploaded alt' } end let(:upload_content) { 'uploaded-image-binary' } context 'when not logged in' do it 'returns 401' do sign_out do_request expect(response).to have_http_status(:unauthorized) end end context 'when logged in but not member' do it 'returns 403' do sign_in_as(guest) do_request expect(response).to have_http_status(:forbidden) end end context 'when wiki page does not exist' do let(:wiki_page_id) { 999_999_999 } it 'returns 404' do sign_in_as(member) do_request expect(response).to have_http_status(:not_found) end end context 'when file is blank' do let(:params) { { alt_text: 'uploaded alt' } } it 'returns 400' do sign_in_as(member) do_request expect(response).to have_http_status(:bad_request) end end context 'when success' do before do sign_in_as(member) end it 'creates asset, attaches file, increments next_asset_no, and returns json' do expect { do_request } .to change(WikiAsset, :count).by(1) expect(response).to have_http_status(:ok) asset = WikiAsset.order(:id).last expect(asset.wiki_page_id).to eq(page.id) expect(asset.no).to eq(1) expect(asset.alt_text).to eq('uploaded alt') expect(asset.sha256).to eq(Digest::SHA256.digest(upload_content)) expect(asset.created_by_user_id).to eq(member.id) expect(asset.file).to be_attached expect(asset.file.download).to eq(upload_content) expect(page.reload.next_asset_no).to eq(2) expect(json).to include( 'wiki_page_id' => page.id, 'no' => 1, 'url' => asset.url ) end it 'uses the next page-local number when assets already exist' do existing = WikiAsset.new(wiki_page: page, no: 1, alt_text: 'existing alt', sha256: Digest::SHA256.digest('existing'), created_by_user: member) existing.file.attach(dummy_upload('existing', filename: 'existing.png')) existing.save! page.update!(next_asset_no: 2) do_request expect(response).to have_http_status(:ok) asset = WikiAsset.order(:id).last expect(asset.no).to eq(2) expect(page.reload.next_asset_no).to eq(3) expect(json).to include( 'wiki_page_id' => page.id, 'no' => 2, 'url' => asset.url ) end end end end