Implement validation and testing for user. It's no longer test-first, but since devise is special, I wanted to implement it to the point where it works, so the order is out of order.
First, prepare the files required for the test. The user model was generated with devise_token_auth, so there are no rspec and factoryBot files. Generate with the following command.
$ rails g rspec:model user
      create  spec/models/user_spec.rb
      invoke  factory_bot
      create    spec/factories/users.rb
Create the factory first.
spec/factories/users.rb
# frozen_string_literal: true
FactoryBot.define do
  factory :user do
    provider { "email" }
    sequence(:email) { |n| "test#{n}@example.com" }
    uid { email }
    password { "password" }
    remember_created_at { nil }
    name { "MyString" }
    tokens { nil }
  end
end
What happened to the columns in the user table? Then, you can check the output result by looking at db / schema.rb.
There are three things to note in the factory file.
    sequence(:email) { |n| "test#{n}@example.com" }     uid { email }     password { "password" }
These are three.
sequence(:email) { |n| "test#{n}@example.com" }
A serial number is entered in n of this process. The first record is [email protected], the second record is [email protected],….
The reason for doing this is that the email column is uniquely restricted and cannot be registered if it is the same character string.
For example, if this is a constant ʻemail {"[email protected]"} , create_list (: user, 10) `will result in two or more corresponding email addresses and moss.
uid { email }
It's just a simple uid with an email variable.
The behavior of devise is uid = email if the provider is email.
password { "password" }
The encrypted_password is on the DB column, but the hashed string is stored there.
The column name does not match schema.rb because you need to enter a value for password when setting the password.
I want to run a test similar to post, so copy spec / models / post_spec.rb.
Replace Post with ʻUser, subjectwithname, and body with ʻemail.
spec/models/user_spec.rb
# frozen_string_literal: true
require "rails_helper"
RSpec.describe User, type: :model do
  describe "name" do
    context "When blank" do
      let(:user) do
        build(:user, name: "")
      end
      it "Become invalid" do
        expect(user).not_to be_valid
      end
    end
    context "by maxlength" do
      context "For 30 characters" do
        let(:user) do
          build(:user, name: "Ah" * 30)
        end
        it "Become valid" do
          expect(user).to be_valid
        end
      end
      context "For 31 characters" do
        let(:user) do
          build(:user, name: "Ah" * 31)
        end
        it "Become invalid" do
          expect(user).not_to be_valid
        end
      end
    end
  end
  describe "email" do
    context "When blank" do
      let(:user) do
        build(:user, email: "")
      end
      it "Become invalid" do
        expect(user).not_to be_valid
      end
    end
    context "by maxlength" do
      context "For 100 characters" do
        let(:user) do
          build(:user, email: "@example.com".rjust(100, "a"))
        end
        it "Become valid" do
          expect(user).to be_valid
        end
      end
      context "For 101 characters" do
        let(:user) do
          build(:user, email: "@example.com".rjust(101, "a"))
        end
        it "Become invalid" do
          expect(user).not_to be_valid
        end
      end
    end
    context "By email format" do
      context "If the string is correct" do
        let(:user) do
          build(:user, email: "[email protected]")
        end
        it "Become valid" do
          expect(user).to be_valid
        end
      end
      context "In case of incorrect string" do
        let(:user) do
          build(:user, email: "test@example")
        end
        it "Become invalid" do
          expect(user).not_to be_valid
        end
      end
    end
  end
end
The following parts are not copied from post but replaced independently.
build(:user, email: "@example.com".rjust(100, "a"))
build(:user, email: "@example.com".rjust(101, "a"))
rjust is a method that fills the string with the specified characters so that it is right-justified.
Try running it with rails c.
$ rails c
[1] pry(main)> "@example.com".rjust(100, "a")
=> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com"
[2] pry(main)> "@example.com".rjust(100, "a").length
=> 100
By doing this, you can generate dummy data that is perfect for 100 characters.
app/models/user.rb
 # frozen_string_literal: true
 #
 #User class
 #
 class User < ActiveRecord::Base
   # Include default devise modules. Others available are:
   # :confirmable, :lockable, :timeoutable and :omniauthable
   devise :database_authenticatable, :registerable,
          :rememberable, :validatable
   include DeviseTokenAuth::Concerns::User
+  validates :name, presence: true, length: { maximum: 30 }
+  validates :email, presence: true, length: { maximum: 100 }
end
Now it will pass the rspec test.
that? I haven't written the format validation of the email address, but why is it OK? If you feel it, it's sharp.
Actually, the format of email is checked by : validatable of devise, so it is not necessary to specify the email format confirmation validation in the case of devise dependent model.
In this tutorial, I'll finish by writing a simple test that only requires registration and login.
$ rails g rspec:request v1/auth
      create  spec/requests/v1/auths_spec.rb
$ mv spec/requests/v1/auths_spec.rb spec/requests/v1/auth_spec.rb
Since auths is unpleasant, rename it to auth. Basically, I will write auth_spec.rb while referring to spec / requests / v1 / posts_spec.rb.
spec/requests/v1/auth_spec.rb
# frozen_string_literal: true
require "rails_helper"
RSpec.describe "V1::Auth", type: :request do
  describe "POST /v1/auth#create" do
    let(:user) do
      attributes_for(:user, email: "[email protected]", name: "signup test")
    end
    it "Normal response code is returned" do
      post v1_user_registration_url, params: user
      expect(response.status).to eq 200
    end
    it "One more case will be returned" do
      expect do
        post v1_user_registration_url, params: user
      end.to change { User.count }.by(1)
    end
    it "name is returned correctly" do
      post v1_user_registration_url, params: user
      json = JSON.parse(response.body)
      expect(json["data"]["name"]).to eq("signup test")
    end
    it "Errors are returned when the parameter is invalid" do
      post v1_user_registration_url, params: {}
      json = JSON.parse(response.body)
      expect(json.key?("errors")).to be true
    end
  end
  describe "POST /v1/auth/sign_in#create" do
    let(:user) do
      create(:user, email: "[email protected]", name: "signin test")
      { email: "[email protected]", password: "password" }
    end
    it "Normal response code is returned" do
      post v1_user_session_url, params: user, as: :json
      expect(response.status).to eq 200
    end
    it "name is returned correctly" do
      post v1_user_session_url, params: user
      json = JSON.parse(response.body)
      expect(json["data"]["name"]).to eq("signin test")
    end
    it "Errors are returned when the parameter is invalid" do
      post v1_user_session_url, params: {}
      json = JSON.parse(response.body)
      expect(json.key?("errors")).to be true
    end
  end
end
After writing so far, if rubocop and rspec pass normally, commit.
→ Building a bulletin board API with authentication authorization in Rails 6 # 12 Association of user and post [To the serial table of contents]