Commit beea8054 by Neha

implemented user module with models test cases

parent ebb60b88
......@@ -53,7 +53,7 @@ end
group :test do
gem 'factory_bot_rails'
gem 'faker'
gem 'faker'
gem 'capybara'
gem 'capybara-screenshot', '~> 1.0.11'
gem 'selenium-webdriver'
......
......@@ -48,6 +48,8 @@ GEM
bindex (0.8.1)
bootsnap (1.4.8)
msgpack (~> 1.0)
bootsnap (1.4.8-java)
msgpack (~> 1.0)
builder (3.2.4)
byebug (11.0.1)
capybara (3.15.1)
......@@ -75,6 +77,9 @@ GEM
faker (2.12.0)
i18n (>= 1.6, < 2)
ffi (1.13.1)
ffi (1.13.1-java)
ffi (1.13.1-x64-mingw32)
ffi (1.13.1-x86-mingw32)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.8.5)
......@@ -83,6 +88,9 @@ GEM
activesupport (>= 5.0.0)
launchy (2.4.3)
addressable (~> 2.3)
launchy (2.4.3-java)
addressable (~> 2.3)
spoon (~> 0.0.1)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
......@@ -100,12 +108,24 @@ GEM
mini_portile2 (2.4.0)
minitest (5.14.2)
msgpack (1.3.3)
msgpack (1.3.3-java)
msgpack (1.3.3-x64-mingw32)
msgpack (1.3.3-x86-mingw32)
nio4r (2.5.2)
nio4r (2.5.2-java)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
nokogiri (1.10.10-java)
nokogiri (1.10.10-x64-mingw32)
mini_portile2 (~> 2.4.0)
nokogiri (1.10.10-x86-mingw32)
mini_portile2 (~> 2.4.0)
pg (1.2.3)
pg (1.2.3-x64-mingw32)
pg (1.2.3-x86-mingw32)
public_suffix (4.0.6)
puma (3.12.6)
puma (3.12.6-java)
rack (2.2.3)
rack-proxy (0.6.5)
rack
......@@ -173,6 +193,8 @@ GEM
selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
spoon (0.0.6)
ffi
spring (2.0.2)
activesupport (>= 4.2)
spring-watcher-listen (2.0.1)
......@@ -187,12 +209,15 @@ GEM
sprockets (>= 3.0.0)
thor (1.0.1)
thread_safe (0.3.6)
thread_safe (0.3.6-java)
tilt (2.0.10)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (1.2.7)
thread_safe (~> 0.1)
tzinfo-data (1.2020.1)
tzinfo (>= 1.0.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
web-console (3.7.0)
......@@ -206,12 +231,18 @@ GEM
railties (>= 4.2)
websocket-driver (0.7.3)
websocket-extensions (>= 0.1.0)
websocket-driver (0.7.3-java)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
PLATFORMS
java
ruby
x64-mingw32
x86-mingw32
x86-mswin32
DEPENDENCIES
bootsnap (>= 1.1.0)
......
class Api::V1::UsersController < ApplicationController
def index
user = User.all.order(created_at: :desc)
render json: user
end
def create
user = User.create!(user_params)
if user
render json: user
else
render json: user.errors
end
end
def show
if user
render json: user
else
render json: user.errors
end
end
def destroy
user&.destroy
render json: { message: 'User deleted!' }
end
private
def user_params
params.permit(:firstName, :lastName, :email, :phone)
end
def user
@user ||= User.find(params[:id])
end
end
......@@ -27,6 +27,14 @@ export default () => (
>
View Employees
</Link>
<br></br>
<Link
to="/users"
className="btn btn-lg custom-button"
role="button"
>
View Users
</Link>
</div>
</div>
</div>
......
import React from "react";
import { Link } from "react-router-dom";
class NewUser extends React.Component {
constructor(props) {
super(props);
this.state = {
firstName: "",
lastName: "",
email: "",
phone: ""
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.stripHtmlEntities = this.stripHtmlEntities.bind(this);
}
stripHtmlEntities(str) {
return String(str)
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
}
onChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
onSubmit(event) {
event.preventDefault();
const url = "/api/v1/users/create";
const { firstName, lastName, email, phone } = this.state;
if (firstName.length == 0 || lastName.length == 0 || email.length == 0 || phone.length == 0)
return;
const body = {
firstName,
lastName,
phone,
email
};
const token = document.querySelector('meta[name="csrf-token"]').content;
fetch(url, {
method: "POST",
headers: {
"X-CSRF-Token": token,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
})
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error("Network response was not ok.");
})
.then(response => this.props.history.push(`/user/${response.id}`))
.catch(error => console.log(error.message));
}
render() {
return (
<div className="container mt-5">
<div className="row">
<div className="col-sm-12 col-lg-6 offset-lg-3">
<h1 className="font-weight-normal mb-5">
Add New User Details
</h1>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label htmlFor="userFirstName">First Name</label>
<input
type="text"
name="firstName"
id="userFirstName"
className="form-control"
required
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="userLastName">Last Name</label>
<input
type="text"
name="lastName"
id="userLastName"
className="form-control"
required
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<input
type="email"
name="email"
id="email"
className="form-control"
required
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="phone">Phone Number</label>
<input
type="text"
name="phone"
id="phone"
className="form-control"
required
onChange={this.onChange}
/>
</div>
<button type="submit" className="btn custom-button mt-3">
Create User
</button>
<Link to="/users" className="btn btn-link mt-3">
Back to Users
</Link>
</form>
</div>
</div>
</div>
);
}
}
export default NewUser;
\ No newline at end of file
import React from "react";
import { Link } from "react-router-dom";
class User extends React.Component {
constructor(props) {
super(props);
this.state = { user: { } };
this.addHtmlEntities = this.addHtmlEntities.bind(this);
this.deleteUser = this.deleteUser.bind(this);
}
async componentDidMount() {
const {
match: {
params: { id }
}
} = this.props;
const url = `/api/v1/user/show/${id}`;
await fetch(url)
.then(response => {
if (response.ok) {
return response.json()
}
throw new Error("Network response was not ok.");
})
.then(response => this.setState({ user: response }))
.catch(() => this.props.history.push("/users"));
}
/**
* addHtmlEntities method, which takes a string and replaces all escaped opening
* and closing brackets with their HTML entities.
*/
addHtmlEntities(str) {
return String(str)
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">");
}
render() {
const { user } = this.state;
console.log("user == ",user);
return (
<div className="">
<div className="hero position-relative d-flex align-items-center justify-content-center">
<div className="overlay bg-dark position-absolute" />
<h3> User Details </h3>
<p className="display-6 position-relative text-white">Name - {user.firstName + ' ' + user.lastName}</p>
<p className="display-6 position-relative text-white">Email - {user.email}</p>
<p className="display-6 position-relative text-white">Phone - {user.phone}</p>
{/* <h1 className="display-4 position-relative text-white">
{user.firstName + ' ' + user.lastName}
</h1> */}
{/* <h3 className="display-4 position-relative text-white">
{user.email}
</h3>
<h3 className="display-4 position-relative text-white">
{user.phone}
</h3>
*/}
</div>
<div className="container py-5">
<div className="row">
<div className="col-sm-12 col-lg-2">
<button type="button" className="btn btn-danger" onClick={this.deleteUser}>
Delete User
</button>
</div>
</div>
<Link to="/users" className="btn btn-link">
Back to Users
</Link>
</div>
</div>
);
}
deleteUser() {
const {
match: {
params: { id }
}
} = this.props;
const url = `/api/v1/user/destroy/${id}`;
const token = document.querySelector('meta[name="csrf-token"]').content;
fetch(url, {
method: "DELETE",
headers: {
"X-CSRF-Token": token,
"Content-Type": "application/json"
}
})
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error("Network response was not ok.");
})
.then(() => this.props.history.push("/users"))
.catch(error => console.log(error.message));
}
}
export default User;
\ No newline at end of file
import React from "react";
import {Link} from "react-router-dom";
class Users extends React.Component {
constructor(props) {
super(props);
this.state = {
users: []
};
}
componentDidMount() {
const url = "/api/v1/users/index";
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error("Network response was not ok.");
})
.then(response => this.setState({ users: response }))
.catch(() => this.props.history.push("/"));
}
render() {
const { users } = this.state;
const allUsers = users.map((user, index) => (
<div key={index} className="col-md-6 col-lg-4">
<div className="card mb-4">
<div className="card-body">
<h5 className="card-title">{user.firstName + ' ' + user.lastName}</h5>
<Link to={`/user/${user.id}`} className="btn custom-button" name="View User"
id="View User">
View User
</Link>
</div>
</div>
</div>
));
const noUser = (
<div className="vw-100 vh-50 d-flex align-items-center justify-content-center">
<h4>
No User yet. Why not <Link to="/new_user">create one</Link>
</h4>
</div>
);
return (
<>
<section className="jumbotron jumbotron-fluid text-center">
<div className="container py-5">
<h1 className="display-4">User</h1>
</div>
</section>
<div className="py-5">
<main className="container">
<div className="text-right mb-3">
<Link to="/user" className="btn custom-button" id="Save">
Create New User
</Link>
</div>
<div className="row">
{users.length > 0 ? allUsers : noUser}
</div>
<Link to="/" className="btn btn-link">
Home
</Link>
</main>
</div>
</>
);
}
}
export default Users;
\ No newline at end of file
......@@ -7,6 +7,11 @@ import NewRecipe from "../components/NewRecipe";
import Employees from "../components/Employees";
import Employee from "../components/Employee";
import NewEmployee from "../components/NewEmployee";
import Users from "../components/Users";
import User from "../components/User";
import NewUser from "../components/NewUser";
export default (
<Router>
......@@ -18,6 +23,10 @@ export default (
<Route path="/employees" exact component={Employees} />
<Route path="/employee/:id" exact component={Employee} />
<Route path="/employee" exact component={NewEmployee} />
<Route path="/users" exact component={Users} />
<Route path="/user/:id" exact component={User} />
<Route path="/user" exact component={NewUser} />
</Switch>
</Router>
);
\ No newline at end of file
class User < ApplicationRecord
validates :firstName, presence: true
validates :lastName, presence: true
validates :email, presence: true
validates :phone, presence: true
end
......@@ -32,7 +32,7 @@ development:
username: agami
# The password associated with the postgres role (username).
password: agami
password:
# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
......
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
get 'users/index'
post 'users/create'
get 'user/show/:id', to: 'users#show'
delete 'user/destroy/:id', to: 'users#destroy'
end
end
namespace :api do
namespace :v1 do
get 'employees/index'
post 'employees/create'
get 'employee/show/:id', to: 'employees#show'
......
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :firstName, null: false
t.string :lastName, null: false
t.string :phone, null: false
t.string :email, null: false
t.timestamps
end
end
end
\ No newline at end of file
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_09_30_024252) do
ActiveRecord::Schema.define(version: 2020_09_31_025252) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -36,4 +36,13 @@ ActiveRecord::Schema.define(version: 2020_09_30_024252) do
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "firstName", null: false
t.string "lastName", null: false
t.string "phone", null: false
t.string "email", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
......@@ -21,4 +21,11 @@
address: "Noida, UP",
dob: "11/11/1111"
)
User.create(
firstName: "User #{i}",
lastName: "Last Name",
email: "email#{i}@agami.com",
phone: "00000000#{i}"
)
end
\ No newline at end of file
FactoryBot.define do
factory :user do
firstName {'Neha'}
lastName {'Mangla'}
email {'neha@getnada.com'}
phone {'9729063967'}
end
factory :random_user, class: User do
firstName { Faker::Name.name }
lastName { Faker::Name.name }
email { Faker::Internet.email }
phone { Faker::PhoneNumber.cell_phone }
end
end
......@@ -3,4 +3,5 @@ describe "GET '/' - from API", :type => :feature do
visit('http://localhost:3000/')
expect(page).to have_title "RailsReactRecipe"
end
end
\ No newline at end of file
end
# describe "GET '/' - from API", :type => :feature do
# it 'checks the user page renders or not' do
# puts 'coing in user'
# visit('http://localhost:3000/users')
# # fill_in('userFirstName', :with => 'John')
# expect(page).to have_title "RailsReactRecipe"
# end
# end
# require "rails_helper"
# RSpec.feature "User submits a link" do
# scenario "they see the page for the submitted link" do
# link_title = "Create New User"
# link_url = "http://localhost:3000/user"
# visit root_path
# # click_on "Submit a new link"
# fill_in "link_title", with: link_title
# fill_in "link_url", with: link_url
# click_on "Submit!"
# expect(page).to have_link link_title, href: link_url
# end
# end
require 'rails_helper'
RSpec.describe User, type: :model do
let(:user) { build(:user) }
it 'validate first name' do
user = User.new(lastName: 'last', email: 'neha@getnada.com', phone: '0909128031').save
expect(user).to eq(false)
end
it 'validate last name' do
user = User.new(firstName: 'neha', email: 'neha@getnada.com', phone: '0909128031').save
expect(user).to eq(false)
end
it 'validate email' do
user = User.new(firstName:'neha',lastName: 'last', phone: '0909128031').save
expect(user).to eq(false)
end
it 'validate phone' do
user = User.new(firstName: 'neha', lastName:'last', email: 'neha@getnada.com').save
expect(user).to eq(false)
end
it 'should save successfully' do
user = User.new(firstName: 'neha', lastName:'last', email: 'neha@getnada.com', phone:'6354736').save
expect(user).to eq(true)
end
end
# context 'scope_tests' do
# let (:params) { {firstName:'first', lastName:'last', email:'demo@getnada.com', phone:'4567676'} }
# before(:each) do
# User.new(params).save
# User.new(params).save
# User.new(params.merge(active:true)).save
# User.new(params.merge(active:false)).save
# User.new(params.merge(active:false)).save
# end
# it 'should return active users' do
# expect(User.active_users.size).to eq(3)
# end
# it 'should return inactive users' do
# expect(User.inactive_users.size).to eq(3)
# end
# end
require 'rails_helper'
RSpec.describe "Api::V1::Users", type: :request do
describe "GET /index" do
it "populate an array of users" do
get "/api/v1/users/index"
data = JSON.parse(response.body)
puts 'data'
print(data)
expect(response).to have_http_status(:success)
end
end
describe "POST /create" do
it "returns http success" do
get "/api/v1/users/create"
expect(response).to have_http_status(:success)
end
end
describe "GET /show" do
it "returns http success" do
get "/api/v1/users/show"
expect(response).to have_http_status(:success)
end
end
describe "GET /destroy" do
it "returns http success" do
get "/api/v1/users/destroy"
expect(response).to have_http_status(:success)
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment