require 'rails_helper' RSpec.describe 'user theme slots', type: :request do describe 'GET /users/theme_slots' do it 'requires a current user' do sign_out get '/users/theme_slots' expect(response).to have_http_status(:unauthorized) end it 'returns only the current user slots in stable order' do user = create(:user) other_user = create(:user) sign_in_as(user) UserThemeSlot.create!(user:, base_theme: 'light', slot_no: 2, tokens: { 'a' => 1 }) UserThemeSlot.create!(user:, base_theme: 'dark', slot_no: 1, tokens: { 'b' => 2 }) UserThemeSlot.create!(user: other_user, base_theme: 'dark', slot_no: 3, tokens: { 'c' => 3 }) get '/users/theme_slots' expect(response).to have_http_status(:ok) expect(json.map { |slot| [slot.fetch('base_theme'), slot.fetch('slot_no')] }).to eq( [['dark', 1], ['light', 2]]) expect(json.map { |slot| slot.fetch('tokens') }).to eq( [{ 'b' => 2 }, { 'a' => 1 }]) end end describe 'PUT /users/theme_slots/:base_theme/:slot_no' do it 'requires a current user' do sign_out put '/users/theme_slots/light/1', params: { tokens: { background: '0 0% 100%' } }, as: :json expect(response).to have_http_status(:unauthorized) end it 'creates a theme slot' do user = create(:user) sign_in_as(user) expect { put '/users/theme_slots/light/1', params: { tokens: { background: '0 0% 100%', tagColours: { nico: '#ffffff' } } }, as: :json }.to change(UserThemeSlot, :count).by(1) expect(response).to have_http_status(:ok) expect(json).to include('base_theme' => 'light', 'slot_no' => 1) expect(json.fetch('tokens')).to include( 'background' => '0 0% 100%', 'tagColours' => { 'nico' => '#ffffff' }) expect(user.theme_slots.find_by!(base_theme: 'light', slot_no: 1).tokens).to include( 'background' => '0 0% 100%') end it 'updates an existing theme slot instead of creating a duplicate' do user = create(:user) sign_in_as(user) UserThemeSlot.create!(user:, base_theme: 'dark', slot_no: 2, tokens: { 'old' => true }) expect { put '/users/theme_slots/dark/2', params: { tokens: { background: '222.2 84% 4.9%' } }, as: :json }.not_to change(UserThemeSlot, :count) expect(response).to have_http_status(:ok) expect(user.theme_slots.find_by!(base_theme: 'dark', slot_no: 2).tokens).to eq( 'background' => '222.2 84% 4.9%') end it 'rejects invalid path parameters and token shapes' do sign_in_as(create(:user)) put '/users/theme_slots/system/4', params: { tokens: 'not-object' }, as: :json expect(response).to have_http_status(:unprocessable_entity) expect(json.fetch('errors')).to include( 'base_theme' => ['値が不正です.']) end it 'rejects non-object tokens for valid slots' do sign_in_as(create(:user)) put '/users/theme_slots/light/1', params: { tokens: 'not-object' }, as: :json expect(response).to have_http_status(:unprocessable_entity) expect(json.fetch('errors')).to include( 'tokens' => ['JSON object で指定してください.']) end end end