From 00cdba25133b99ffad9045803c8a75db552e0d0e Mon Sep 17 00:00:00 2001 From: Carlos Araoz Date: Thu, 27 Apr 2023 09:14:08 -0600 Subject: [PATCH 1/2] Part2: Increase test coverage --- app/bot_tools/bot_tool.rb | 4 - app/controllers/bots_controller.rb | 1 - app/controllers/chats_controller.rb | 7 +- app/models/setting_field.rb | 1 + spec/constraints/admin_constraint_spec.rb | 31 +++++++ spec/factories/bot.rb | 2 +- spec/factories/chats.rb | 5 ++ spec/factories/messages.rb | 1 + spec/factories/users.rb | 10 +-- spec/models/chat_spec.rb | 8 ++ spec/models/message_spec.rb | 6 ++ spec/requests/chats_controller_spec.rb | 103 ++++++++++++++++++++++ spec/requests/home_controller_spec.rb | 27 ++++++ spec/requests/sessions_controller_spec.rb | 30 +++++++ spec/requests/settings_spec.rb | 32 +++++++ spec/support/controller_helpers.rb | 25 ++++++ 16 files changed, 278 insertions(+), 15 deletions(-) delete mode 100644 app/bot_tools/bot_tool.rb create mode 100644 spec/constraints/admin_constraint_spec.rb create mode 100644 spec/requests/chats_controller_spec.rb create mode 100644 spec/requests/home_controller_spec.rb create mode 100644 spec/requests/sessions_controller_spec.rb create mode 100644 spec/requests/settings_spec.rb diff --git a/app/bot_tools/bot_tool.rb b/app/bot_tools/bot_tool.rb deleted file mode 100644 index 1a739e3..0000000 --- a/app/bot_tools/bot_tool.rb +++ /dev/null @@ -1,4 +0,0 @@ -class BotTool < ApplicationJob - queue_as :high_priority_queue - -end diff --git a/app/controllers/bots_controller.rb b/app/controllers/bots_controller.rb index 5feaba3..3ceebd2 100644 --- a/app/controllers/bots_controller.rb +++ b/app/controllers/bots_controller.rb @@ -24,7 +24,6 @@ def update end end - private def bot_params diff --git a/app/controllers/chats_controller.rb b/app/controllers/chats_controller.rb index 53fd6ee..0325f85 100644 --- a/app/controllers/chats_controller.rb +++ b/app/controllers/chats_controller.rb @@ -56,8 +56,9 @@ def show end def readonly - @chat = Chat.find(params[:id]) - if @chat.public_access? + @chat = Chat.find_by(id: params[:id]) + + if @chat&.public_access? render :show else redirect_to root_path, notice: "Chat not found" @@ -69,6 +70,4 @@ def readonly def chat_params params.require(:chat).permit(:first_message, :engine, :bot_id) end - - end diff --git a/app/models/setting_field.rb b/app/models/setting_field.rb index 801200d..506f29e 100644 --- a/app/models/setting_field.rb +++ b/app/models/setting_field.rb @@ -10,6 +10,7 @@ def initialize(current_user, form, key, value) @form = form @current_user = current_user @key = key + @value = value end def label diff --git a/spec/constraints/admin_constraint_spec.rb b/spec/constraints/admin_constraint_spec.rb new file mode 100644 index 0000000..11c916d --- /dev/null +++ b/spec/constraints/admin_constraint_spec.rb @@ -0,0 +1,31 @@ +require 'rails_helper' + +describe AdminConstraint, type: :routing do + subject { described_class.matches?(request) } + + let(:request) { double('request') } + + before do + allow(request).to receive(:session).and_return({ + user_id: user&.id + }) + end + + context 'when user is not present' do + let(:user) { nil } + + it { is_expected.to eq false } + end + + context 'when user is not admin' do + let(:user) { create(:user) } + + it { is_expected.to eq false } + end + + context 'when user is admin' do + let(:user) { create(:admin) } + + it { is_expected.to eq true } + end +end diff --git a/spec/factories/bot.rb b/spec/factories/bot.rb index 482b195..f91fdcb 100644 --- a/spec/factories/bot.rb +++ b/spec/factories/bot.rb @@ -1,7 +1,7 @@ FactoryBot.define do factory :bot do goals { {} } - name { 'My Bot' } + name { Faker::Name.name } settings { {} } end end diff --git a/spec/factories/chats.rb b/spec/factories/chats.rb index 480c5d1..b4e9973 100644 --- a/spec/factories/chats.rb +++ b/spec/factories/chats.rb @@ -27,6 +27,7 @@ factory :chat do engine { 'engine' } analysis { {} } + public_access { false } association :bot association :user @@ -38,5 +39,9 @@ after(:create) do |chat, evaluator| create_list(:message, evaluator.message_count, chat: chat) end + + trait :public do + public_access { true } + end end end diff --git a/spec/factories/messages.rb b/spec/factories/messages.rb index 55edb3b..394013e 100644 --- a/spec/factories/messages.rb +++ b/spec/factories/messages.rb @@ -31,6 +31,7 @@ factory :message do role { 'user' } content { Faker::Hipster.sentence } + tokens_count { rand(1..100) } association :chat end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index ae5e070..2e38526 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -22,13 +22,13 @@ email { Faker::Internet.email } name { Faker::Name.name } - oauth_uid { Faker::Number.number(digits: 21) } - oauth_provider { 'Google' } + oauth_uid { Faker::Number.number(digits: 9).to_s } + oauth_provider { 'google_oauth2' } image_url { Faker::Internet.url } + end - trait :admin do - admin { true } - end + factory :admin, parent: :user do + admin { true } end end diff --git a/spec/models/chat_spec.rb b/spec/models/chat_spec.rb index 4b67684..af1b678 100644 --- a/spec/models/chat_spec.rb +++ b/spec/models/chat_spec.rb @@ -218,4 +218,12 @@ end end end + + describe '#total_token_count' do + let(:chat) { build(:chat, message_count: 5) } + + it 'sums up messages token_count' do + expect(chat.total_token_count).to eq chat.messages.sum(:tokens_count) + end + end end diff --git a/spec/models/message_spec.rb b/spec/models/message_spec.rb index 95e9ce2..833d8e9 100644 --- a/spec/models/message_spec.rb +++ b/spec/models/message_spec.rb @@ -91,6 +91,12 @@ end end + describe '#to_partial_path' do + subject(:result) { described_class.new.to_partial_path } + + it { is_expected.to eq 'messages/message' } + end + describe '#reanalyze' do let(:message) { create(:message) } let(:chat) { message.chat } diff --git a/spec/requests/chats_controller_spec.rb b/spec/requests/chats_controller_spec.rb new file mode 100644 index 0000000..d8a7afb --- /dev/null +++ b/spec/requests/chats_controller_spec.rb @@ -0,0 +1,103 @@ +require 'rails_helper' + +RSpec.describe ChatsController, type: :request do + before { allow(Gpt).to receive(:chat) } + + shared_examples_for 'logged out' do + context 'when logged out' do + let(:user) { nil } + + it 'redirects to home' do + expect(response).to redirect_to root_url + end + end + end + + describe 'GET /index' do + before do + login_user(user) + + get chats_url + end + + it_behaves_like 'logged out' + + context 'when user has chats' do + let(:user) do + user = create(:user) + create(:chat, user: user) + + user + end + + it 'responds with http 200' do + expect(response).to have_http_status :ok + end + end + + context 'when user has no chats' do + let(:user) { create(:user) } + + it 'redirects to chats' do + expect(response).to redirect_to new_chat_url + end + end + end + + describe 'GET /chats/:id' do + let(:user) { chat.user } + let(:chat) { create(:chat) } + + before do + login_user(user) + + get chats_url(chat) + end + + it_behaves_like 'logged out' + + it 'responds with http 200' do + expect(response).to have_http_status :ok + end + end + + describe 'read only chat' do + let(:chat) { create(:chat, :public) } + + shared_examples_for 'readonly requests' do + it 'responds with http 200' do + expect(response).to have_http_status :ok + end + + context 'when chat is not public' do + let(:chat) { create(:chat, public_access: false) } + + it 'redirects to /', :aggregate_failures do + expect(response).to redirect_to root_path + expect(flash[:notice]).to eq 'Chat not found' + end + end + + context 'when chat is not found' do + let(:chat) { instance_double(Chat, id: '1234') } + + it 'redirects to /', :aggregate_failures do + expect(response).to redirect_to root_path + expect(flash[:notice]).to eq 'Chat not found' + end + end + end + + describe 'GET /chats/:id/readonly' do + before { get readonly_chat_url(id: chat.id) } + + it_behaves_like 'readonly requests' + end + + describe 'GET /c/:id' do + before { get readonly_url(id: chat.id) } + + it_behaves_like 'readonly requests' + end + end +end diff --git a/spec/requests/home_controller_spec.rb b/spec/requests/home_controller_spec.rb new file mode 100644 index 0000000..5049c4b --- /dev/null +++ b/spec/requests/home_controller_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' + +RSpec.describe HomeController, type: :request do + before { allow(Gpt).to receive(:chat) } + + describe 'GET /index' do + let(:user) { nil } + + before do + login_user(user) + + get home_index_url + end + + it 'responds with http 200' do + expect(response).to have_http_status :ok + end + + context 'when logged in' do + let(:user) { create(:user) } + + it 'redirects to chats' do + expect(response).to redirect_to chats_url + end + end + end +end diff --git a/spec/requests/sessions_controller_spec.rb b/spec/requests/sessions_controller_spec.rb new file mode 100644 index 0000000..b92b428 --- /dev/null +++ b/spec/requests/sessions_controller_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe SessionsController, type: :request do + describe 'GET /auth/:provider/callback' do + let(:params) { { provider: :google } } + let(:user) { create(:user) } + + before do + mock_omniauth(user) + + get '/auth/:provider/callback', params: params + end + + it 'signs the user in', :aggregate_failures do + expect(response).to redirect_to '/chats' + expect(flash[:notice]).to eq 'Signed in!' + expect(session[:user_id]).to eq user.id + end + end + + describe 'GET /logout' do + it 'signs the user out' do + get logout_url + + expect(response).to redirect_to root_url + expect(flash[:notice]).to eq 'Signed out!' + expect(session[:user_id]).to eq nil + end + end +end diff --git a/spec/requests/settings_spec.rb b/spec/requests/settings_spec.rb new file mode 100644 index 0000000..eeb763a --- /dev/null +++ b/spec/requests/settings_spec.rb @@ -0,0 +1,32 @@ +require 'rails_helper' + +RSpec.describe "Settings", type: :request do + let(:user) { create(:user) } + + before { login_user(user) } + + describe "GET /show" do + xit "returns http success" do + get "/settings/show" + expect(response).to have_http_status(:success) + end + end + + describe 'PATCH /settings' do + let(:params) do + { + user: { + preferred_language: 'Baby Talk' + } + } + end + + it 'updates user settings', :aggregate_failures do + patch settings_url, params: params + + expect(response).to redirect_to settings_path + expect(flash[:notice]).to eq('Settings updated') + expect(user.reload.settings.new_setting).to eq params.dig(:user, :new_setting) + end + end +end diff --git a/spec/support/controller_helpers.rb b/spec/support/controller_helpers.rb index 8a720cf..48c2ce9 100644 --- a/spec/support/controller_helpers.rb +++ b/spec/support/controller_helpers.rb @@ -4,4 +4,29 @@ def login_user(user) .to receive(:current_user) .and_return(user) end + + def mock_omniauth(user) + OmniAuth.config.test_mode = true + omniauth_hash = Faker::Omniauth.google(name: user.name, uid: user.oauth_uid) + OmniAuth.config.mock_auth[:google_oauth2] = OmniAuth::AuthHash.new(omniauth_hash) + Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[:google_oauth2] + end +end + +shared_examples_for 'admin - forbidden' do + context 'when logged out' do + let(:user) { nil } + + it 'redirects to root' do + expect(response).to redirect_to root_path + end + end + + context 'when logged in user is not admin' do + let(:user) { create(:user) } + + it 'redirects to root' do + expect(response).to redirect_to root_path + end + end end From 225e12c945f600118042a777420343e0e6a77067 Mon Sep 17 00:00:00 2001 From: Carlos Araoz Date: Fri, 28 Apr 2023 11:19:30 -0600 Subject: [PATCH 2/2] CircleCI - build tailwindcss and save test results --- .circleci/config.yml | 5 +++-- spec/rails_helper.rb | 8 ++++++++ spec/support/simplecov.rb | 7 ------- 3 files changed, 11 insertions(+), 9 deletions(-) delete mode 100644 spec/support/simplecov.rb diff --git a/.circleci/config.yml b/.circleci/config.yml index 1c36818..0b27ce2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,8 +51,9 @@ jobs: steps: - install-dependencies - setup-database + - run: bundle exec rails tailwindcss:build - run: - command: bundle exec rspec --format progress --format RspecJunitFormatter -o ~/rspec/rspec.xml + command: bundle exec rspec --format progress --format RspecJunitFormatter -o ~/test_results/rspec/rspec.xml when: always - store_test_results: - path: ~/rspec + path: ~/test_results diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 960d62a..b59f1ae 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,5 +1,13 @@ # This file is copied to spec/ when you run 'rails generate rspec:install' require 'spec_helper' +require 'simplecov' + +SimpleCov.start 'rails' do + add_group 'Services', 'app/services' + add_group 'Reflexes', 'app/reflexes' + add_group 'Constraints', 'app/constraints' +end + ENV['RAILS_ENV'] ||= 'test' require_relative '../config/environment' # Prevent database truncation if the environment is production diff --git a/spec/support/simplecov.rb b/spec/support/simplecov.rb deleted file mode 100644 index a2fd86b..0000000 --- a/spec/support/simplecov.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'simplecov' - -SimpleCov.start 'rails' do - add_group 'Services', 'app/services' - add_group 'Reflexes', 'app/reflexes' - add_group 'Constraints', 'app/constraints' -end