diff --git a/Gemfile b/Gemfile index 99d8e519..84aaec00 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,15 @@ ruby '3.0.2' gem 'pg' gem 'sinatra' +gem 'sinatra-contrib' +gem 'sinatra-flash' +gem 'psql' +gem 'launchy' +gem 'thin' +gem 'puma' +gem 'reel' +gem 'http' +gem 'webrick' group :test do gem 'capybara' diff --git a/Gemfile.lock b/Gemfile.lock index 7d4eb449..21826b1e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -18,6 +18,8 @@ GEM mini_mime (1.1.1) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) + nokogiri (1.12.3-arm64-darwin) + racc (~> 1.4) nokogiri (1.12.3-x86_64-darwin) racc (~> 1.4) parallel (1.20.1) @@ -83,6 +85,7 @@ GEM nokogiri (~> 1.8) PLATFORMS + arm64-darwin-21 x86_64-darwin-20 DEPENDENCIES diff --git a/app.rb b/app.rb index 2450fb92..2c0d86fe 100644 --- a/app.rb +++ b/app.rb @@ -1,8 +1,42 @@ require 'sinatra/base' +require './lib/messages' +require './lib/database_connection' +require './spec/db_setup_helper' class Chitter < Sinatra::Base - get '/test' do - 'Test page' + enable :sessions + configure do + enable :reloader + end + + get '/newuser' do + erb :'users/new' + end + + post '/newuser' do + @user = User.create(params[:email], params[:password]) + session["email"] = params[:email] + redirect '/chitter' + end + + get '/chitter' do + @email = session["email"] + erb :index + end + + get '/peeps' do + @messages = Messages.all + erb :allpeeps + end + + get '/drafts' do + erb :post + end + + post '/postpeep' do + peep = params['message'] + Messages.create(message: peep) + redirect('/chitter') end run! if app_file == $0 diff --git a/db/migrations/02_create_user_table.sql b/db/migrations/02_create_user_table.sql new file mode 100644 index 00000000..b2899572 --- /dev/null +++ b/db/migrations/02_create_user_table.sql @@ -0,0 +1 @@ +CREATE TABLE users(id SERIAL PRIMARY KEY, email VARCHAR(60), password VARCHAR(140)); diff --git a/lib/database_connection.rb b/lib/database_connection.rb new file mode 100644 index 00000000..c2a83987 --- /dev/null +++ b/lib/database_connection.rb @@ -0,0 +1,15 @@ +require 'pg' + +class DatabaseConnection + def initialize + @connect + end + + def self.setup(dbname) + @connect = PG.connect(dbname: dbname) + end + + def self.query(query, params = []) + @connect.exec_params(query, params) + end +end diff --git a/lib/messages.rb b/lib/messages.rb new file mode 100644 index 00000000..03670f1c --- /dev/null +++ b/lib/messages.rb @@ -0,0 +1,30 @@ +require 'pg' + +class Messages + attr_reader :id, :message + + def initialize(id:, message:) + @id = id + @message = message + end + + def self.all + if ENV['ENVIRONMENT'] == 'test' + connection = PG.connect(dbname: 'chitter_test') + else + connection = PG.connect(dbname: 'chitter') + end + result = connection.exec("SELECT * FROM peeps") + result.map do |m| + Messages.new(id: m['id'], message: m['message']) + m['message'] + end + end + + def self.create(message:) + result = DatabaseConnection.query( + "INSERT INTO peeps (message) VALUES ($1) RETURNING id, message;", [message] + ) + Messages.new(id: result[0]['id'],message: result[0]['message']) + end +end diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 00000000..8b9225c6 --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,17 @@ +require_relative './database_connection.rb' + +class User + attr_reader :id, :email + + def initialize(id:, email:) + @id = id + @email = email + end + + def self.create(email, password) + result = DatabaseConnection.query( + "INSERT INTO users (email, password) VALUES($1, $2) RETURNING id, email;", [email, password] + ) + User.new(id: result[0]['id'], email: result[0]['email']) + end +end \ No newline at end of file diff --git a/public/styles.css b/public/styles.css new file mode 100644 index 00000000..e69de29b diff --git a/spec/databaseconnection_spec.rb b/spec/databaseconnection_spec.rb new file mode 100644 index 00000000..a0a39f06 --- /dev/null +++ b/spec/databaseconnection_spec.rb @@ -0,0 +1,13 @@ +require 'pg' +require 'database_connection' + +describe DatabaseConnection do + it 'connects to the database and shows message' do + DatabaseConnection.query("INSERT INTO peeps (message) VALUES ($1);", ['Hi there Chitter!']) + result = DatabaseConnection.query( + "SELECT * FROM peeps;", + ) + result.map { |message| { "id" => message['id'], "message" => message['message'] } } + expect(result[0]['message']).to eq 'Hi there Chitter!' + end +end diff --git a/spec/db_setup_helper.rb b/spec/db_setup_helper.rb new file mode 100644 index 00000000..3752224f --- /dev/null +++ b/spec/db_setup_helper.rb @@ -0,0 +1,8 @@ +require './lib/database_connection' + +p "Reading the Environment Variable" +if ENV['ENVIRONMENT'] == 'test' + DatabaseConnection.setup('chitter_test') +else + DatabaseConnection.setup('chitter') +end diff --git a/spec/features/adding_peep_spec.rb b/spec/features/adding_peep_spec.rb new file mode 100644 index 00000000..30001768 --- /dev/null +++ b/spec/features/adding_peep_spec.rb @@ -0,0 +1,15 @@ +feature 'Viewing added peeps' do + scenario 'adds peeps to the list' do + visit('/chitter') + click_button('Post a Peep') + + expect(current_path).to eq '/drafts' + + fill_in('message', with: 'This is my first peep!') + click_button('Submit') + expect(current_path).to eq '/chitter' + click_button('View all Peeps') + + expect(page).to have_content "This is my first peep!" + end +end diff --git a/spec/features/registration_spec.rb b/spec/features/registration_spec.rb new file mode 100644 index 00000000..e6549b56 --- /dev/null +++ b/spec/features/registration_spec.rb @@ -0,0 +1,10 @@ +feature 'registration' do + scenario 'a user is able to sign up' do + visit '/newuser' + fill_in('email', with: 'test@example.com') + fill_in('password', with: 'password1') + click_button 'Submit' + expect(current_path).to eq '/chitter' + expect(page).to have_content 'Welcome to Chitter test@example.com' + end +end \ No newline at end of file diff --git a/spec/features/test_page_spec.rb b/spec/features/test_page_spec.rb deleted file mode 100644 index b65ac196..00000000 --- a/spec/features/test_page_spec.rb +++ /dev/null @@ -1,6 +0,0 @@ -feature 'Viewing test page' do - scenario 'visiting the test page' do - visit('/test') - expect(page).to have_content "Test page" - end -end diff --git a/spec/features/view_messages_spec.rb b/spec/features/view_messages_spec.rb new file mode 100644 index 00000000..7d1257d7 --- /dev/null +++ b/spec/features/view_messages_spec.rb @@ -0,0 +1,16 @@ +require 'pg' + +feature 'Viewing messages' do + scenario 'shows all messages' do + Messages.create(message: 'Update - I am in Paris') + Messages.create(message: 'Just got back from the park!') + Messages.create(message: 'Hi Chitter.') + + visit ('/peeps') + + expect(current_path).to eq '/peeps' + expect(page).to have_content 'Update - I am in Paris' + expect(page).to have_content 'Just got back from the park!' + expect(page).to have_content 'Hi Chitter.' + end +end diff --git a/spec/messages_spec.rb b/spec/messages_spec.rb new file mode 100644 index 00000000..f364839e --- /dev/null +++ b/spec/messages_spec.rb @@ -0,0 +1,28 @@ +require 'messages' +require 'pg' + +describe Messages do + describe '.all' do + it 'returns a list of messages' do + message1 = Messages.create(message: 'Hello') + Messages.create(message: 'Hi!') + Messages.create(message: 'Hiya.') + + messages = Messages.all + + expect(messages.length).to eq 3 + expect(message1).to be_a Messages + expect(messages).to include "Hello" + expect(messages).to include "Hi!" + expect(messages).to include "Hiya." + end + end + + describe '.create' do + it 'creates a new posted peep' do + Messages.create(message: "This is my first peep!") + + expect(Messages.all).to include 'This is my first peep!' + end + end +end diff --git a/spec/persisted_data.rb b/spec/persisted_data.rb new file mode 100644 index 00000000..fbcd2b5d --- /dev/null +++ b/spec/persisted_data.rb @@ -0,0 +1,7 @@ +require 'pg' +require 'db_setup_helper' + +def persisted_data(id:, table:) + connection = PG.connect(dbname: 'chitter_test') + connection.query("SELECT * FROM #{table} WHERE id = '#{id}';") +end diff --git a/spec/setup_test_database.rb b/spec/setup_test_database.rb index af832f7d..88c354bb 100644 --- a/spec/setup_test_database.rb +++ b/spec/setup_test_database.rb @@ -2,7 +2,7 @@ def setup_test_database connection = PG.connect(dbname: 'chitter_test') - connection.exec("TRUNCATE peeps;") + connection.exec("TRUNCATE peeps, users;") end def add_row_to_test_database diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 74046cad..905cf495 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,19 +1,6 @@ -# This file was generated by the `rspec --init` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. -# -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. -# -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -# Require all the testing gems +p "Test Environment Initiated" +ENV['ENVIRONMENT'] = 'test' +require File.join(File.dirname(__FILE__), '..', 'app.rb') require 'capybara' require 'capybara/rspec' require 'rspec' @@ -24,18 +11,10 @@ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ SimpleCov::Formatter::Console, - # Want a nice code coverage website? Uncomment this next line! - # SimpleCov::Formatter::HTMLFormatter + SimpleCov::Formatter::HTMLFormatter ]) SimpleCov.start -ENV['RACK_ENV'] = 'test' -ENV['ENVIRONMENT'] = 'test' - -# Bring in the contents of the `app.rb` file. The below is equivalent to: require_relative '../app.rb' -require File.join(File.dirname(__FILE__), '..', 'app.rb') - -# Tell Capybara to talk to Chitter Capybara.app = Chitter RSpec.configure do |config| @@ -51,87 +30,13 @@ end RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" expectations.include_chain_clauses_in_custom_matcher_descriptions = true end - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. mocks.verify_partial_doubles = true end - # This option will default to `:apply_to_host_groups` in RSpec 4 (and will - # have no way to turn it off -- the option exists only for backwards - # compatibility in RSpec 3). It causes shared context metadata to be - # inherited by the metadata hash of host groups and examples, rather than - # triggering implicit auto-inclusion in groups with matching metadata. config.shared_context_metadata_behavior = :apply_to_host_groups - -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # This allows you to limit a spec run to individual examples or groups - # you care about by tagging them with `:focus` metadata. When nothing - # is tagged with `:focus`, all examples get run. RSpec also provides - # aliases for `it`, `describe`, and `context` that include `:focus` - # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - config.filter_run_when_matching :focus - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - config.disable_monkey_patching! - - # This setting enables warnings. It's recommended, but in some cases may - # be too noisy due to issues in dependencies. - config.warnings = true - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = "doc" - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end end diff --git a/spec/user_spec.rb b/spec/user_spec.rb new file mode 100644 index 00000000..01e1d9d5 --- /dev/null +++ b/spec/user_spec.rb @@ -0,0 +1,16 @@ +require 'user' +require './lib/database_connection' +require 'persisted_data' + +RSpec.describe User do + describe '.create' do + it 'creates a User and adds them to the database' do + user = User.create("test@example.com", "password1") + persisted_data = persisted_data(id: user.id, table: 'users') + + expect(user.id).to eq persisted_data.first['id'] + expect(user.email).to eq "test@example.com" + expect(user).to be_a User + end + end +end \ No newline at end of file diff --git a/views/allpeeps.erb b/views/allpeeps.erb new file mode 100644 index 00000000..31c59b1f --- /dev/null +++ b/views/allpeeps.erb @@ -0,0 +1,6 @@ +

All Peeps:

+ diff --git a/views/index.erb b/views/index.erb new file mode 100644 index 00000000..f938cfca --- /dev/null +++ b/views/index.erb @@ -0,0 +1,10 @@ +<% if @email%> +

Welcome to Chitter <%= @email%>

+<% end %> +
+ +
+ +
+ +
diff --git a/views/post.erb b/views/post.erb new file mode 100644 index 00000000..099342fc --- /dev/null +++ b/views/post.erb @@ -0,0 +1,5 @@ +

Post a Peep:

+
+ + +
diff --git a/views/users/new.erb b/views/users/new.erb new file mode 100644 index 00000000..6dd6768b --- /dev/null +++ b/views/users/new.erb @@ -0,0 +1,5 @@ +
+ + + +
\ No newline at end of file