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,
subjectwith
name, 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]