diff --git a/.travis.yml b/.travis.yml index 97194ada2e..a2c07c4d7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ rvm: '2.5.0' +services: + - postgresql + script: - mkdir -p spec && bundle exec rspec spec @@ -9,3 +12,7 @@ before_install: before_script: - psql -c 'create database chitter_test;' -U postgres + - psql chitter_test -c 'CREATE TABLE peeps(id SERIAL PRIMARY KEY, text VARCHAR(280));' + - psql chitter_test -c 'ALTER TABLE peeps ADD time timestamp DEFAULT NOW();' + - psql chitter_test -c 'CREATE TABLE users(id SERIAL PRIMARY KEY, email VARCHAR(60), password VARCHAR(60), name VARCHAR(60), username VARCHAR(60));' + - psql chitter_test -c 'ALTER TABLE peeps ADD userid INT;' diff --git a/Gemfile b/Gemfile index 905e0cf49d..a81fa13251 100644 --- a/Gemfile +++ b/Gemfile @@ -2,10 +2,14 @@ source 'https://rubygems.org' ruby '2.5.0' +gem 'pg' gem 'rake' gem 'rubocop', '0.56.0' +gem 'sinatra' +gem 'sinatra-flash' group :test do + gem 'capybara' gem 'rspec' gem 'simplecov', require: false gem 'simplecov-console', require: false diff --git a/Gemfile.lock b/Gemfile.lock index e6b4ce7c9b..42565913c8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,18 +1,41 @@ GEM remote: https://rubygems.org/ specs: + addressable (2.6.0) + public_suffix (>= 2.0.2, < 4.0) ansi (1.5.0) ast (2.4.0) + capybara (3.20.2) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.2) + xpath (~> 3.2) diff-lcs (1.3) docile (1.1.5) hirb (0.7.3) json (2.1.0) + mini_mime (1.0.1) + mini_portile2 (2.4.0) + mustermann (1.0.3) + nokogiri (1.10.3) + mini_portile2 (~> 2.4.0) parallel (1.12.1) parser (2.5.1.0) ast (~> 2.4.0) + pg (1.1.4) powerpack (0.1.1) + public_suffix (3.0.3) + rack (2.0.7) + rack-protection (2.0.5) + rack + rack-test (1.1.0) + rack (>= 1.0, < 3) rainbow (3.0.0) rake (12.3.0) + regexp_parser (1.5.1) rspec (3.7.0) rspec-core (~> 3.7.0) rspec-expectations (~> 3.7.0) @@ -43,20 +66,34 @@ GEM hirb simplecov simplecov-html (0.10.2) + sinatra (2.0.5) + mustermann (~> 1.0) + rack (~> 2.0) + rack-protection (= 2.0.5) + tilt (~> 2.0) + sinatra-flash (0.3.0) + sinatra (>= 1.0.0) + tilt (2.0.9) unicode-display_width (1.3.2) + xpath (3.2.0) + nokogiri (~> 1.8) PLATFORMS ruby DEPENDENCIES + capybara + pg rake rspec rubocop (= 0.56.0) simplecov simplecov-console + sinatra + sinatra-flash RUBY VERSION ruby 2.5.0p0 BUNDLED WITH - 1.16.1 + 1.17.2 diff --git a/README.md b/README.md index 8f0ad8f8b7..89ebcc4cad 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,14 @@ Chitter Challenge ================= -* Challenge time: rest of the day and weekend, until Monday 9am -* Feel free to use Google, your notes, books, etc. but work on your own -* If you refer to the solution of another coach or student, please put a link to that in your README -* If you have a partial solution, **still check in a partial solution** -* You must submit a pull request to this repo with your code by 9am Monday morning - -Challenge: +The challenge: ------- -As usual please start by forking this repo. - -We are going to write a small Twitter clone that will allow the users to post messages to a public stream. +* The goal was to create a twitter clone, which lets a user sign up, log in, post, and log out -Features: -------- +* User stories as follows: ``` -STRAIGHT UP - As a Maker So that I can let people know what I am doing I want to post a message (peep) to chitter @@ -36,8 +25,6 @@ As a Maker So that I can post messages on Chitter as me I want to sign up for Chitter -HARDER - As a Maker So that only I can post messages on Chitter as me I want to log in to Chitter @@ -46,88 +33,79 @@ As a Maker So that I can avoid others posting messages on Chitter as me I want to log out of Chitter -ADVANCED - -As a Maker -So that I can stay constantly tapped in to the shouty box of Chitter -I want to receive an email if I am tagged in a Peep ``` -Technical Approach: ------ - -This week you integrated a database into Bookmark Manager using the `PG` gem and `SQL` queries. You can continue to use this approach when building Chitter Challenge. - -If you'd like more technical challenge this weekend, try using an [Object Relational Mapper](https://en.wikipedia.org/wiki/Object-relational_mapping) as the database interface. +* Signing up with an in-use email or username should display a relevant prompt -Some useful resources: -**DataMapper** -- [DataMapper ORM](https://datamapper.org/) -- [Sinatra, PostgreSQL & DataMapper recipe](http://recipes.sinatrarb.com/p/databases/postgresql-datamapper) +* Logging in with incorrect details should display a prompt -**ActiveRecord** -- [ActiveRecord ORM](https://guides.rubyonrails.org/active_record_basics.html) -- [Sinatra, PostgreSQL & ActiveRecord recipe](http://recipes.sinatrarb.com/p/databases/postgresql-activerecord?#article) Notes on functionality: ------ * You don't have to be logged in to see the peeps. -* Makers sign up to chitter with their email, password, name and a username (e.g. samm@makersacademy.com, password123, Sam Morgan, sjmog). +* Users sign up to chitter with their email, password, name and a username (e.g. samm@makersacademy.com, password123, Sam Morgan, sjmog). * The username and email are unique. * Peeps (posts to chitter) have the name of the maker and their user handle. * Your README should indicate the technologies used, and give instructions on how to install and run the tests. -Bonus: + +How to use: ----- -If you have time you can implement the following: +* Clone this directory -* In order to start a conversation as a maker I want to reply to a peep from another maker. +* Download postgres sql (e.g. by typing brew install postgressql in the command line) -And/Or: +* Open postgres (psql in the command line) and create two databases called chitter and chitter_test using the following command: -* Work on the CSS to make it look good. +``` +CREATE DATABASE database_name +``` + +* For each database enter the commands in db/migrations (in order!) + +* Run bundle install in the command line + +* Run rackup in the command line and visit localhost in a browser with the correct port number + +* To run tests enter rspec in the command line from the root directory -Good luck and let the chitter begin! +* Visit the /peeps route and interact! Click 'Sign up' to register a username/ email, +'Peep' to post a peep, 'Log out' to sign out and 'Log in' to sign in -Code Review ------------ +![homepagescreenshot](./images/screenshot1.png) +Viewing the page while logged out: only the sign up and sign in options are available. -In code review we'll be hoping to see: +![signuppagescreenshot](./images/screenshot2.png) +Viewing the sign up page. -* All tests passing -* High [Test coverage](https://github.com/makersacademy/course/blob/master/pills/test_coverage.md) (>95% is good) -* The code is elegant: every class has a clear responsibility, methods are short etc. +![signedinhomepage](./images/screenshot3.png) +While signed in users have the options to post and sign out! -Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance may make the challenge somewhat easier. You should be the judge of how much challenge you want this weekend. -Automated Tests: +Technical Approach: ----- -Opening a pull request against this repository will will trigger Travis CI to perform a build of your application and run your full suite of RSpec tests. If any of your tests rely on a connection with your database - and they should - this is likely to cause a problem. The build of your application created by has no connection to the local database you will have created on your machine, so when your tests try to interact with it they'll be unable to do so and will fail. +* TDD approach, outside-in (i.e. feature tests first, then unit tests) -If you want a green tick against your pull request you'll need to configure Travis' build process by adding the necessary steps for creating your database to the `.travis.yml` file. +* Used the MVC pattern -- [Travis Basics](https://docs.travis-ci.com/user/tutorial/) -- [Travis - Setting up Databases](https://docs.travis-ci.com/user/database-setup/) +* Stored user and peep information (timestamp, text, username and so on) within tables of a database. Accessed these using sql and wrapped them in user and peep ruby objects respectively -Notes on test coverage ----------------------- +* One-to-many relationship between users and peeps meant storing userid as a foreign key within the peeps table -Please ensure you have the following **AT THE TOP** of your spec_helper.rb in order to have test coverage stats generated -on your pull request: -```ruby -require 'simplecov' -require 'simplecov-console' +Thoughts +----- -SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ - SimpleCov::Formatter::Console, - # Want a nice code coverage website? Uncomment this next line! - # SimpleCov::Formatter::HTMLFormatter -]) -SimpleCov.start -``` +* Storing passwords in plaintext, probably not a good idea! Could use a gem to encrypt these + +* Did not test the timestamping, could use Time.now in ruby rather than handling this on the database +side. Would make testing easier (e.g. using the gem timecop or a mock) + +* Parts of the controller are a little long, will have to consider if it's possible to refactor + +* Could have used an ORM such as datamapper -You can see your test coverage when you run your tests. If you want this in a graphical form, uncomment the `HTMLFormatter` line and see what happens! +* Improvements to HTML/ CSS would be nice to have diff --git a/app.rb b/app.rb new file mode 100644 index 0000000000..a35e683cf3 --- /dev/null +++ b/app.rb @@ -0,0 +1,73 @@ +require 'sinatra/base' +require 'sinatra/flash' +require_relative './lib/peep.rb' +require_relative './lib/user.rb' +require_relative './lib/database_connection_setup.rb' + +class Chitter < Sinatra::Base + enable :sessions + register Sinatra::Flash + + get '/peeps' do + @peeps = Peep.all + @logged_in = !session[:userid].nil? + @name = session[:name] + erb(:'peeps/index') + end + + get '/peeps/post' do + erb(:'peeps/post') + end + + post '/peeps' do + Peep.post(text: params[:text], userid: session[:userid]) + redirect '/peeps' + end + + get '/users/signup' do + erb(:'users/signup') + end + + post '/users' do + if !User.unique_email?(params[:email]) + flash[:notice] = 'Email in use' + redirect '/users/signup' + elsif !User.unique_username?(params[:username]) + flash[:notice] = 'Username in use' + redirect '/users/signup' + end + + user = User.sign_up(email: params[:email], password: params[:password], + name: params[:name], username: params[:username]) + + session[:userid] = user.id + session[:name] = user.name + + redirect '/peeps' + end + + get '/login/new' do + erb(:'users/login') + end + + post '/login' do + user = User.authenticate(email: params[:email], password: params[:password]) + + if user + session[:userid] = user.id + session[:name] = user.name + redirect '/peeps' + else + flash[:notice] = 'Your email or password is incorrect' + redirect '/login/new' + end + end + + post '/logout' do + session.clear + flash[:notice] = 'You have logged out' + redirect '/peeps' + end + + run! if app_file == $0 +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000000..dfe7fd55ac --- /dev/null +++ b/config.ru @@ -0,0 +1,3 @@ +require_relative './app.rb' + +run Chitter diff --git a/db/migrations/01_create_peeps_table.sql b/db/migrations/01_create_peeps_table.sql new file mode 100644 index 0000000000..b28098082d --- /dev/null +++ b/db/migrations/01_create_peeps_table.sql @@ -0,0 +1 @@ +CREATE TABLE peeps(id SERIAL PRIMARY KEY, text VARCHAR(280)); diff --git a/db/migrations/02_add_time_column.sql b/db/migrations/02_add_time_column.sql new file mode 100644 index 0000000000..8892061ff1 --- /dev/null +++ b/db/migrations/02_add_time_column.sql @@ -0,0 +1 @@ +ALTER TABLE peeps ADD time timestamp DEFAULT NOW(); diff --git a/db/migrations/03_create_users_table.sql b/db/migrations/03_create_users_table.sql new file mode 100644 index 0000000000..31184641fc --- /dev/null +++ b/db/migrations/03_create_users_table.sql @@ -0,0 +1 @@ +CREATE TABLE users(id SERIAL PRIMARY KEY, email VARCHAR(60), password VARCHAR(60), name VARCHAR(60), username VARCHAR(60)); diff --git a/db/migrations/04_add_userid_column.sql b/db/migrations/04_add_userid_column.sql new file mode 100644 index 0000000000..b0f49ce9c1 --- /dev/null +++ b/db/migrations/04_add_userid_column.sql @@ -0,0 +1 @@ +ALTER TABLE peeps ADD userid INT; diff --git a/images/screenshot1.png b/images/screenshot1.png new file mode 100644 index 0000000000..f93dc475f5 Binary files /dev/null and b/images/screenshot1.png differ diff --git a/images/screenshot2.png b/images/screenshot2.png new file mode 100644 index 0000000000..b7e6bcfbf4 Binary files /dev/null and b/images/screenshot2.png differ diff --git a/images/screenshot3.png b/images/screenshot3.png new file mode 100644 index 0000000000..60f8136007 Binary files /dev/null and b/images/screenshot3.png differ diff --git a/lib/database_connection.rb b/lib/database_connection.rb new file mode 100644 index 0000000000..1d019533b9 --- /dev/null +++ b/lib/database_connection.rb @@ -0,0 +1,15 @@ +require 'pg' + +class DatabaseConnection + def self.setup(dbname) + @connection = PG.connect(dbname: dbname) + end + + def self.query(sql) + @connection.exec(sql) + end + + class << self + attr_reader :connection + end +end diff --git a/lib/database_connection_setup.rb b/lib/database_connection_setup.rb new file mode 100644 index 0000000000..73789b73c0 --- /dev/null +++ b/lib/database_connection_setup.rb @@ -0,0 +1,7 @@ +require_relative './database_connection.rb' + +if ENV['ENVIRONMENT'] == 'test' + DatabaseConnection.setup('chitter_test') +else + DatabaseConnection.setup('chitter') +end diff --git a/lib/peep.rb b/lib/peep.rb new file mode 100644 index 0000000000..cd82b32ee8 --- /dev/null +++ b/lib/peep.rb @@ -0,0 +1,41 @@ +require_relative './database_connection.rb' + +class Peep + attr_reader :id, :text, :time, :userid + + def initialize(id:, text:, time:, userid:) + @id = id + @text = text + @time = time + @userid = userid + end + + def self.post(text:, userid:) + sql = "INSERT INTO peeps (text, userid) VALUES('#{text}', #{userid}) + RETURNING id, text, to_char(time,'HH24:MI - DD Mon YYYY') AS time, + userid;" + + peep = DatabaseConnection.query(sql).first + + Peep.new(id: peep['id'], text: peep['text'], time: peep['time'], + userid: peep['userid']) + end + + def self.all + sql = "SELECT id, text, to_char(time, 'HH24:MI - DD Mon YYYY') AS time, + userid + FROM peeps ORDER BY id DESC;" + + result = DatabaseConnection.query(sql) + + result.map do |peep| + Peep.new(id: peep['id'], text: peep['text'], time: peep['time'], + userid: peep['userid']) + end + end + + def user_info + sql = "SELECT name, username FROM users WHERE id = #{@userid}" + DatabaseConnection.query(sql).first + end +end diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 0000000000..368613582e --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,46 @@ +require_relative './database_connection.rb' + +class User + attr_reader :id, :email, :name, :username + + def initialize(id:, email:, password:, name:, username:) + @id = id + @email = email + @password = password + @name = name + @username = username + end + + def self.sign_up(email:, password:, name:, username:) + sql = "INSERT INTO users (email, password, name, username) + VALUES('#{email}', '#{password}', '#{name}', '#{username}') + RETURNING *;" + + user = DatabaseConnection.query(sql).first + + User.new(id: user['id'], email: user['email'], password: user['password'], + name: user['name'], username: user['username']) + end + + def self.unique_email?(email) + sql = "SELECT email FROM users WHERE email = '#{email}';" + result = DatabaseConnection.query(sql) + result.count.zero? + end + + def self.unique_username?(username) + sql = "SELECT username FROM users WHERE username = '#{username}';" + result = DatabaseConnection.query(sql) + result.count.zero? + end + + def self.authenticate(email:, password:) + sql = "SELECT * FROM users WHERE email = '#{email}';" + result = DatabaseConnection.query(sql).first + return if (result.nil? || password != result['password']) + + User.new(id: result['id'], email: result['email'], + password: result['password'], name: result['name'], + username: result['username']) + end +end diff --git a/spec/database_connection_spec.rb b/spec/database_connection_spec.rb new file mode 100644 index 0000000000..03761022f5 --- /dev/null +++ b/spec/database_connection_spec.rb @@ -0,0 +1,24 @@ +require 'database_connection' + +describe DatabaseConnection do + describe '#setup' do + it 'should set up a connection to the database' do + expect(PG).to receive(:connect).with(dbname: 'chitter_test') + + DatabaseConnection.setup('chitter_test') + end + + it 'should be a persistent connection' do + connection = DatabaseConnection.setup('chitter_test') + expect(DatabaseConnection.connection).to eq(connection) + end + end + + describe '#query' do + it 'should execute a query' do + connection = DatabaseConnection.setup('chitter_test') + expect(connection).to receive(:exec).with('SELECT * FROM peeps;') + DatabaseConnection.query('SELECT * FROM peeps;') + end + end +end diff --git a/spec/database_helpers.rb b/spec/database_helpers.rb new file mode 100644 index 0000000000..f9b76ad916 --- /dev/null +++ b/spec/database_helpers.rb @@ -0,0 +1,11 @@ +require 'pg' + +def persisted_data_peeps(id:) + connection = PG.connect(dbname: 'chitter_test') + connection.query("SELECT * FROM peeps WHERE id = '#{id}';") +end + +def persisted_data_users(id:) + connection = PG.connect(dbname: 'chitter_test') + connection.query("SELECT * FROM users WHERE id = '#{id}';") +end diff --git a/spec/features/authentication_spec.rb b/spec/features/authentication_spec.rb new file mode 100644 index 0000000000..05c3b437e5 --- /dev/null +++ b/spec/features/authentication_spec.rb @@ -0,0 +1,39 @@ +feature 'authentication' do + scenario 'users can sign in' do + User.sign_up(email: 'a@a.com', password: '123', name: 'test user', + username: 'test_user') + + visit '/peeps' + click_button('Log in') + sign_in + expect(page).to have_content('Welcome, test user') + end + + scenario 'users see a prompt if their email is incorrect' do + visit '/login/new' + sign_in + expect(page).to have_content('Your email or password is incorrect') + end + + scenario 'users see a prompt if their password if incorrect' do + User.sign_up(email: 'a@a.com', password: '123', name: 'test user', + username: 'test_user') + + visit '/login/new' + fill_in('email', with: 'a@a.com') + fill_in('password', with: '1234') + click_button('Sign in') + expect(page).to have_content('Your email or password is incorrect') + end + + scenario 'users are able to sign out' do + User.sign_up(email: 'a@a.com', password: '123', name: 'test user', + username: 'test_user') + + visit '/login/new' + sign_in + click_button 'Log out' + expect(page).to have_content('You have logged out') + expect(page).not_to have_content('Welcome, test user') + end +end diff --git a/spec/features/posting_spec.rb b/spec/features/posting_spec.rb new file mode 100644 index 0000000000..04510c472a --- /dev/null +++ b/spec/features/posting_spec.rb @@ -0,0 +1,7 @@ +feature "posting" do + scenario "peeps are visible on the index page after posting" do + sign_up_user + post_a_peep + expect(page).to have_content('I feel grrrrrreat') + end +end diff --git a/spec/features/signing_up_spec.rb b/spec/features/signing_up_spec.rb new file mode 100644 index 0000000000..c99218d7c6 --- /dev/null +++ b/spec/features/signing_up_spec.rb @@ -0,0 +1,20 @@ +feature "signing up" do + scenario "returns you to the sign up page if email is not unique" do + sign_up_user + click_button('Log out') + sign_up_same_email + expect(page).to have_content('Email in use') + end + + scenario "returns you to the sign up page if username is not unique" do + sign_up_user + click_button('Log out') + sign_up_same_username + expect(page).to have_content('Username in use') + end + + scenario "takes you to the homepage with your username present" do + sign_up_user + expect(page).to have_content('Welcome, test user') + end +end diff --git a/spec/features/viewing_index_spec.rb b/spec/features/viewing_index_spec.rb new file mode 100644 index 0000000000..3f5b293a20 --- /dev/null +++ b/spec/features/viewing_index_spec.rb @@ -0,0 +1,21 @@ +feature "index" do + scenario 'post button should not appear if not signed up' do + visit '/peeps' + expect(page).not_to have_selector(:link_or_button, 'Post') + end + + scenario 'page should have multiple peeps listed' do + sign_up_user + post_a_peep + post_another_peep + expect(page).to have_content('I feel grrrrrreat') + expect(page).to have_content('I really do') + end + + scenario 'page should show name and user handle with peeps' do + sign_up_user + post_a_peep + expect(page).to have_content('test user') + expect(page).to have_content('@test_user1') + end +end diff --git a/spec/peep_spec.rb b/spec/peep_spec.rb new file mode 100644 index 0000000000..d18571f2bc --- /dev/null +++ b/spec/peep_spec.rb @@ -0,0 +1,40 @@ +require 'peep' +require 'database_helpers' + +describe Peep do + let(:userid) { 123 } + + describe '#post' do + it 'should insert an entry into the peep table' do + peep = Peep.post(text: 'I feel grrrrrreat', userid: userid) + persisted_data = persisted_data_peeps(id: peep.id) + + expect(peep).to be_an_instance_of Peep + expect(peep.id).to eq(persisted_data.first['id']) + expect(peep.text).to eq('I feel grrrrrreat') + end + end + + describe '#all' do + it 'should produce an array of peep objects' do + Peep.post(text: 'I feel grrrrrreat', userid: userid) + Peep.post(text: 'I really do', userid: userid) + peeps = Peep.all + expect(peeps.all? { |peep| peep.is_a?(Peep) }).to eq(true) + end + end + + describe '#user_info' do + it 'should return the name and username of the peep poster' do + peep = Peep.post(text: 'I feel grrrrrreat', userid: userid) + + sql = "INSERT INTO users (id, email, password, name, username) + VALUES('#{userid}', 'a@a.com', '123', 'Laurence', 'L123');" + + DatabaseConnection.query(sql) + hash = peep.user_info + expect(hash['name']).to eq('Laurence') + expect(hash['username']).to eq('L123') + end + end +end diff --git a/spec/setup_test_database.rb b/spec/setup_test_database.rb new file mode 100644 index 0000000000..89a4d1797e --- /dev/null +++ b/spec/setup_test_database.rb @@ -0,0 +1,8 @@ +require 'pg' + +def setup_test_database + connection = PG.connect(dbname: 'chitter_test') + + connection.exec("TRUNCATE peeps") + connection.exec("TRUNCATE users") +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 252747d899..9a025b60d9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,17 @@ +ENV['RACK_ENV'] = 'test' +ENV['ENVIRONMENT'] = 'test' + +require_relative '../app.rb' +require_relative './setup_test_database' + +require 'capybara' +require 'capybara/rspec' +require 'rspec' require 'simplecov' require 'simplecov-console' +Capybara.app = Chitter + SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ SimpleCov::Formatter::Console, # Want a nice code coverage website? Uncomment this next line! @@ -9,6 +20,12 @@ SimpleCov.start RSpec.configure do |config| + require 'web_helpers' + + config.before(:each) do + setup_test_database + end + config.after(:suite) do puts puts "\e[33mHave you considered running rubocop? It will help you improve your code!\e[0m" diff --git a/spec/user_spec.rb b/spec/user_spec.rb new file mode 100644 index 0000000000..2d79707f86 --- /dev/null +++ b/spec/user_spec.rb @@ -0,0 +1,70 @@ +require 'user' +require 'database_helpers' + +describe User do + let(:user_signup) do + User.sign_up(email: 'test@test.com', + password: 'password123', + name: 'test user', + username: 'test_user') + end + + describe '#sign_up' do + it 'should add a user to the database' do + persisted_data = persisted_data_users(id: user_signup.id) + + expect(user_signup).to be_an_instance_of(User) + expect(user_signup.id).to eq(persisted_data.first['id']) + expect(user_signup.email).to eq('test@test.com') + expect(user_signup.name).to eq('test user') + expect(user_signup.username).to eq('test_user') + end + end + + describe '#unique_email?' do + before(:each) do + user_signup + end + + it 'should return true if email is unique' do + expect(User.unique_email?('unique@unique.com')).to eq(true) + end + + it 'should return false if email is not unique' do + expect(User.unique_email?('test@test.com')).to eq(false) + end + end + + describe '#unique_username?' do + before(:each) do + user_signup + end + + it 'should return true if username is unique' do + expect(User.unique_username?('unique_user')).to eq(true) + end + + it 'should return false if username is not unique' do + expect(User.unique_username?('test_user')).to eq(false) + end + end + + describe '#authenticate' do + it 'should return a user if passed correct login details' do + user = user_signup + authenticated_user = User.authenticate(email: 'test@test.com', + password: 'password123') + + expect(user.id).to eq(authenticated_user.id) + end + + it 'should return nil if email is incorrect' do + expect(User.authenticate(email: 'a@a.com', password: '123')).to be_nil + end + + it 'should return nil if password is incorrect' do + user_signup + expect(User.authenticate(email: 'test@test.com', password: '1')).to be_nil + end + end +end diff --git a/spec/web_helpers.rb b/spec/web_helpers.rb new file mode 100644 index 0000000000..71cd4e6c68 --- /dev/null +++ b/spec/web_helpers.rb @@ -0,0 +1,49 @@ +def post_a_peep + visit '/peeps' + click_button('Post') + fill_in('text', with: 'I feel grrrrrreat') + click_button('Peep') +end + +def post_another_peep + visit '/peeps' + click_button('Post') + fill_in('text', with: 'I really do') + click_button('Peep') +end + +def sign_up_user + visit '/peeps' + click_button 'Sign up' + fill_in('email', with: 'test@test.com') + fill_in('password', with: 'password123') + fill_in('name', with: 'test user') + fill_in('username', with: 'test_user1') + click_button('Submit') +end + +def sign_up_same_email + visit '/peeps' + click_button 'Sign up' + fill_in('email', with: 'test@test.com') + fill_in('password', with: 'password123') + fill_in('name', with: 'test user') + fill_in('username', with: 'test_user2') + click_button('Submit') +end + +def sign_up_same_username + visit '/peeps' + click_button 'Sign up' + fill_in('email', with: 'unique@unique.com') + fill_in('password', with: 'password123') + fill_in('name', with: 'test user') + fill_in('username', with: 'test_user1') + click_button('Submit') +end + +def sign_in + fill_in('email', with: 'a@a.com') + fill_in('password', with: '123') + click_button('Sign in') +end diff --git a/views/peeps/index.erb b/views/peeps/index.erb new file mode 100644 index 0000000000..56c3b0d935 --- /dev/null +++ b/views/peeps/index.erb @@ -0,0 +1,52 @@ + + +