require "rails_helper" RSpec.describe Api::RegistrationsController, type: :controller do describe "POST #create" do context "with valid parameters" do let(:valid_params) do { user: { nickname: "CaptainNemo", password: "secretpassword" } } end it "creates a new user and returns 201 with user data and JWT token" do expect { post :create, params: valid_params }.to change(User, :count).by(1) expect(response).to have_http_status(:created) json = JSON.parse(response.body) expect(json["token"]).to be_present expect(json["user"]).to include( "nickname" => "CaptainNemo", "avatar_url" => nil ) expect(json["user"]["id"]).to be_present expect(json["user"]["created_at"]).to be_present # Verify token is valid and decodes to created user decoded = JwtService.decode(json["token"]) expect(decoded[:user_id]).to eq(json["user"]["id"]) end it "attaches avatar and returns avatar_url when avatar is provided" do avatar = fixture_file_upload( Rails.root.join("spec", "fixtures", "files", "avatar.png"), "image/png" ) rescue Rack::Test::UploadedFile.new( StringIO.new("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15c4"), "image/png", original_filename: "avatar.png" ) params_with_avatar = valid_params.deep_merge(user: { avatar: avatar }) post :create, params: params_with_avatar expect(response).to have_http_status(:created) json = JSON.parse(response.body) expect(json["user"]["avatar_url"]).to be_present user = User.find(json["user"]["id"]) expect(user.avatar).to be_attached end end context "with invalid parameters" do it "returns 422 unprocessable entity when nickname is missing" do post :create, params: { user: { nickname: "", password: "password123" } } expect(response).to have_http_status(:unprocessable_content) json = JSON.parse(response.body) expect(json["errors"]).to be_an(Array) expect(json["errors"]).to include("Nickname can't be blank") end it "returns 422 unprocessable entity when password is too short" do post :create, params: { user: { nickname: "CaptainNemo", password: "123" } } expect(response).to have_http_status(:unprocessable_content) json = JSON.parse(response.body) expect(json["errors"]).to include("Password is too short (minimum is 6 characters)") end it "returns 422 unprocessable entity when nickname is already taken" do User.create!(nickname: "CaptainNemo", password: "password123") post :create, params: { user: { nickname: "captainnemo", password: "password123" } } expect(response).to have_http_status(:unprocessable_content) json = JSON.parse(response.body) expect(json["errors"]).to include("Nickname has already been taken") end it "returns 422 when avatar has an unsupported content type" do invalid_avatar = Rack::Test::UploadedFile.new( StringIO.new("plain text content"), "text/plain", original_filename: "test.txt" ) post :create, params: { user: { nickname: "CaptainNemo", password: "password123", avatar: invalid_avatar } } expect(response).to have_http_status(:unprocessable_content) json = JSON.parse(response.body) expect(json["errors"]).to include("Avatar must be a PNG, JPEG, GIF or WebP image") end it "raises ParameterMissing when user param is omitted" do expect { post :create, params: {} }.to raise_error(ActionController::ParameterMissing) end end end end