added 260907 version of worker toolkit

This commit is contained in:
2026-09-08 20:30:51 -04:00
parent cbd3f0f8ca
commit 97aca37663
1283 changed files with 142951 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
require "rails_helper"
RSpec.describe Api::V1::CheckinsController do
let!(:user) { create(:user) }
let(:date) { "2016-01-06" }
before { sign_in user }
describe "index" do
context "when checkin exists for the requested date" do
before do
create(:checkin, date: Date.parse(date), user_id: user.id)
create(:checkin, date: Date.parse(date) + 1.hour, user_id: user.id)
create(:checkin, date: Date.parse(date) + 5.days, user_id: user.id)
create(:checkin, date: Date.parse(date) - 5.days, user_id: user.id)
end
it "returns correct checkin" do
get :index, params: {date: date}
expect(response_body[:checkins].count).to eq 2
expect(response_body[:checkins].pluck(:date).map(&:to_s).sort).to eq ["2016-01-06T00:00:00.000+00:00", "2016-01-06T01:00:00.000+00:00"]
returned_checkin = response_body[:checkins][0]
expect(Date.parse(returned_checkin[:date])).to eq Date.parse(date)
end
end
context "when checkin doesn't exist for the passed date" do
it "returns no results" do
get :index, params: {date: date}
expect(response_body[:checkins].count).to eq 0
end
end
end
describe "create" do
it "returns new checkin" do
travel_to(DateTime.new(2020, 1, 2, 3, 4, 5)) do
post :create, params: {checkin: {date: date}}
returned_checkin_1 = response_body[:checkin]
expect(DateTime.parse(returned_checkin_1[:date]).to_s).to eq "2016-01-06T03:04:05+00:00"
end
travel_to(DateTime.new(2020, 1, 2, 3, 4, 6)) do
post :create, params: {checkin: {date: date}}
returned_checkin_2 = response_body[:checkin]
expect(DateTime.parse(returned_checkin_2[:date]).to_s).to eq "2016-01-06T03:04:05+00:00"
end
travel_to(DateTime.new(2020, 1, 2, 3, 4, 7)) do
post :create, params: {checkin: {date: date}}
returned_checkin_3 = response_body[:checkin]
expect(DateTime.parse(returned_checkin_3[:date]).to_s).to eq "2016-01-06T03:04:05+00:00"
end
expect(user.last_checkin.date).to eq(DateTime.new(2016, 1, 6, 3, 4, 7))
end
end
describe "update" do
let(:checkin) { create(:checkin, user_id: user.id, date: Time.zone.today) }
let(:attributes) { {id: checkin.id, checkin: {note: "Blah"}} }
it "returns updated checkin" do
put :update, params: attributes
returned_checkin = response_body[:checkin]
expect(returned_checkin[:id]).to eq checkin.id.to_s
expect(returned_checkin[:note]).to eq attributes[:checkin][:note]
end
end
context "show" do
describe "for new user" do
let(:new_user) { create(:user) }
let(:checkin) { create(:checkin, user_id: new_user.id, date: Time.zone.today) }
let(:attributes) { {id: checkin.id} }
it "promotion visiability" do
get :show, params: attributes
returned_checkin = response_body[:checkin]
expect(returned_checkin[:available_for_promotion]).to be false
expect(returned_checkin[:promotion_skipped_at].blank?).to be true
expect(returned_checkin[:promotion_rate_id].blank?).to be true
end
end
describe "for user created_at 1 week ago" do
let(:old_user) { create(:user, created_at: 1.week.ago) }
context "Promotion rate" do
describe "start visiability" do
let(:checkin) { create(:checkin, user_id: old_user.id, date: Time.zone.today) }
let(:attributes) { {id: checkin.id} }
it "should be available" do
get :show, params: attributes
returned_checkin = response_body[:checkin]
expect(returned_checkin[:available_for_promotion]).to be true
expect(returned_checkin[:promotion_skipped_at].blank?).to be true
expect(returned_checkin[:promotion_rate_id].blank?).to be true
end
end
describe "skipped promotion rate" do
let(:checkin) { create(:checkin, user_id: old_user.id, promotion_skipped_at: Time.now.utc) }
let(:attributes) { {id: checkin.id} }
it "with skipped promotion rate" do
get :show, params: attributes
returned_checkin = response_body[:checkin]
expect(returned_checkin[:available_for_promotion]).to be false
expect(returned_checkin[:promotion_rate_id].blank?).to be true
end
end
describe "skipped promotion becomes available" do
let(:checkin) do
create(:checkin,
user_id: old_user.id,
date: Time.zone.today,
promotion_skipped_at: (Time.zone.today - 1.week))
end
let(:attributes) { {id: checkin.id} }
it "returns false after skipped promotion rate for 1 week" do
get :show, params: attributes
returned_checkin = response_body[:checkin]
expect(returned_checkin[:available_for_promotion]).to be true
end
end
describe "rated promotion becomes unavailable" do
let(:old_checkin) { create(:checkin, user_id: old_user.id, date: (Time.zone.today - 1.day)) }
let!(:promotion_rate) { create(:promotion_rate, checkin_id: old_checkin.id) }
let(:checkin) { create(:checkin, user_id: old_user.id, date: Time.zone.today) }
let(:attributes) { {id: checkin.id} }
it "returns false if user has rated" do
get :show, params: attributes
returned_checkin = response_body[:checkin]
expect(returned_checkin[:available_for_promotion]).to be false
end
end
end
end
end
end

View File

@@ -0,0 +1,47 @@
require "rails_helper"
RSpec.describe Api::V1::ConditionsController do
let!(:user) { create(:user) }
let!(:global_condition) { create(:condition) }
let!(:personal_condition) { create(:user_condition, user: user).condition }
let!(:another_user_condition) { create(:user_condition).condition }
let(:user_abilities) { Ability.new(user) }
let(:accessible_conditions) { Condition.accessible_by(user_abilities) }
before { sign_in user }
describe "index" do
it "returns all accessible conditions" do
get :index
returned_condition_ids = response_body[:conditions].map { |c| c[:id] }
accessible_condition_ids = accessible_conditions.map(&:id)
expect(returned_condition_ids.to_set).to eq accessible_condition_ids.to_set
end
end
describe "show" do
context "when condition is accessible" do
it "return the requested condition" do
get :show, params: {id: global_condition.id}
expect(response_body[:condition][:id]).to eq global_condition.id
end
end
context "when local condition is accessible" do
it "returns 200 (Authorized)" do
get :show, params: {id: another_user_condition.id}
expect(response.status).to eq 200
end
end
end
describe "create" do
let(:condition_attributes) { {name: "Headache"} }
it "creates the condition as personal for the current user" do
post :create, params: {condition: condition_attributes}
created_condition = response_body[:condition]
expect(created_condition[:name]).to eq condition_attributes[:name]
expect(Condition.find(created_condition[:id]).global).to be false
end
end
end

View File

@@ -0,0 +1,72 @@
require "rails_helper"
RSpec.describe Api::V1::CountriesController do
let(:test_country_id) { "IT" }
let(:test_country_name_en) { "Italy" }
let(:test_country_name_it) { "Italia" }
describe "index" do
let(:all_countries_count) { Country.all.count }
it "returns all countries" do
get :index
expect(response_body[:countries].size).to eq all_countries_count
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translations" do
get :index
test_country = response_body[:countries].find { |c| c[:id].eql?(test_country_id) }
expect(test_country[:name]).to eq test_country_name_en
end
end
context "with 'it' locale" do
before { I18n.default_locale = "it" }
it "returns 'it' translations" do
get :index
test_country = response_body[:countries].find { |c| c[:id].eql?(test_country_id) }
expect(test_country[:name]).to eq test_country_name_it
end
after { I18n.default_locale = "en" }
end
end
describe "show" do
it "returns test country" do
get :show, params: {id: test_country_id}
expect(response_body[:country][:id]).to eq test_country_id
end
it "returns test country case-insensitive" do
get :show, params: {id: test_country_id.downcase}
expect(response_body[:country][:id]).to eq test_country_id
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translation" do
get :show, params: {id: test_country_id}
expect(response_body[:country][:name]).to eq test_country_name_en
end
end
context "with 'it' locale" do
before { I18n.default_locale = "it" }
it "returns 'it' translation" do
get :show, params: {id: test_country_id}
expect(response_body[:country][:name]).to eq test_country_name_it
end
after { I18n.default_locale = "en" }
end
context "with unexisting country id" do
let(:unexisting_country_id) { "XY" }
it "returns 404 (Not Found)" do
get :show, params: {id: unexisting_country_id}
expect(response.status).to eq 404
end
end
context "with invalid country id" do
let(:unexisting_country_id) { "X1" }
it "returns 400 (Bad Request)" do
get :show, params: {id: unexisting_country_id}
expect(response.status).to eq 400
end
end
end
end

View File

@@ -0,0 +1,46 @@
require "rails_helper"
RSpec.describe Api::V1::DayHabitsController do
let(:test_day_habit_id) { "lying_down" }
let(:test_day_habit_name_en) { "Lying down" }
let(:test_day_habit_descr_en) { "bedridden" }
describe "index" do
let(:all_day_habits_count) { DayHabit.all.count }
it "returns all day_habits" do
get :index
expect(response_body[:day_habits].size).to eq all_day_habits_count
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translations" do
get :index
test_day_habit = response_body[:day_habits].find { |c| c[:id].eql?(test_day_habit_id) }
expect(test_day_habit[:name]).to eq test_day_habit_name_en
expect(test_day_habit[:description]).to eq test_day_habit_descr_en
end
end
end
describe "show" do
it "returns test day_habit" do
get :show, params: {id: test_day_habit_id}
expect(response_body[:day_habit][:id]).to eq test_day_habit_id
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translation" do
get :show, params: {id: test_day_habit_id}
expect(response_body[:day_habit][:name]).to eq test_day_habit_name_en
expect(response_body[:day_habit][:description]).to eq test_day_habit_descr_en
end
end
context "with invalid day_habit id" do
let(:invalid_day_habit_id) { "blah" }
it "returns 400 (Bad Request)" do
get :show, params: {id: invalid_day_habit_id}
expect(response.status).to eq 400
end
end
end
end

View File

@@ -0,0 +1,43 @@
require "rails_helper"
RSpec.describe Api::V1::EducationLevelsController do
let(:test_education_level_id) { "bachelors_degree" }
let(:test_education_level_name_en) { "Bachelor's degree" }
describe "index" do
let(:all_education_levels_count) { EducationLevel.all.count }
it "returns all education_levels" do
get :index
expect(response_body[:education_levels].size).to eq all_education_levels_count
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translations" do
get :index
test_education_level = response_body[:education_levels].find { |c| c[:id].eql?(test_education_level_id) }
expect(test_education_level[:name]).to eq test_education_level_name_en
end
end
end
describe "show" do
it "returns test education_level" do
get :show, params: {id: test_education_level_id}
expect(response_body[:education_level][:id]).to eq test_education_level_id
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translation" do
get :show, params: {id: test_education_level_id}
expect(response_body[:education_level][:name]).to eq test_education_level_name_en
end
end
context "with invalid education_level id" do
let(:invalid_education_level_id) { "blah" }
it "returns 400 (Bad Request)" do
get :show, params: {id: invalid_education_level_id}
expect(response.status).to eq 400
end
end
end
end

View File

@@ -0,0 +1,43 @@
require "rails_helper"
RSpec.describe Api::V1::EthnicitiesController do
let(:test_ethnicity_id) { "south_asian" }
let(:test_ethnicity_name_en) { "South Asian" }
describe "index" do
let(:all_ethnicities_count) { Ethnicity.all.count }
it "returns all ethnicities" do
get :index
expect(response_body[:ethnicities].size).to eq all_ethnicities_count
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translations" do
get :index
test_ethnicity = response_body[:ethnicities].find { |c| c[:id].eql?(test_ethnicity_id) }
expect(test_ethnicity[:name]).to eq test_ethnicity_name_en
end
end
end
describe "show" do
it "returns test ethnicity" do
get :show, params: {id: test_ethnicity_id}
expect(response_body[:ethnicity][:id]).to eq test_ethnicity_id
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translation" do
get :show, params: {id: test_ethnicity_id}
expect(response_body[:ethnicity][:name]).to eq test_ethnicity_name_en
end
end
context "with invalid ethnicity id" do
let(:invalid_ethnicity_id) { "blah" }
it "returns 400 (Bad Request)" do
get :show, params: {id: invalid_ethnicity_id}
expect(response.status).to eq 400
end
end
end
end

View File

@@ -0,0 +1,96 @@
require "rails_helper"
RSpec.describe Api::V1::PasswordsController do
let(:user) { create(:user, password: "ValidPassword123", password_confirmation: "ValidPassword123") }
describe "create" do
context "when attempting to reset a password" do
let(:password_params) do
{
# Match the form posted by the front end
current_password: nil,
email: nil,
password: nil,
password_confirmation: nil,
reset_password_token: nil
}
end
context "for an email that exists in the database" do
it "returns a password reset object" do
expect_any_instance_of(User).to receive(:send_reset_password_instructions).and_return true
post :create, params: {password: password_params.merge(email: user.email)}
expect(response.status).to eq 200
expect(response_body[:password]).to include({"email" => user.email})
end
it "finds a user by case-insensitive email address" do
other_user = create :user, email: "arEALLycAMELcaSeemAIl@gmail.com"
expect_any_instance_of(User).to receive(:send_reset_password_instructions).and_return true
post :create, params: {password: password_params.merge(email: "AReallyCamelCaseEmail@GmAiL.CoM")}
expect(response.status).to eq 200
expect(response_body[:password]).to include({"email" => other_user.email})
end
end
context "for an email that does not exist in the database" do
it "returns a 404" do
expect_any_instance_of(User).to_not receive(:send_reset_password_instructions)
post :create, params: {password: password_params.merge(email: "Idonotexist@example.com")}
expect(response.status).to eq 404
end
end
end
end
describe "update" do
context "when no user logged-in" do
context "when missing token" do
it "returns 422 (Unprocessable Entity)" do
put :update, params: {id: 1}
expect(response.status).to eq 422
end
end
context "when provide token" do
it "returns password " do
put :update, params: {id: 1, token: "123"}
expect(response.status).to eq 422
end
end
end
context "when user logged-in" do
before { sign_in user }
context "when provide right params" do
it "update password" do
put(:update, params: {id: user.id, password: {
current_password: "ValidPassword123",
password: "password123",
password_confirmation: "password123"
}})
expect(response_body[:password][:email]).to eq user.email
end
end
context "when password confirmation is wrong" do
it "returns 422 (Unprocessable Entity)" do
put :update, params: {id: user.id, password: {password: "password123", password_confirmation: "password"}}
expect(response.status).to eq 422
end
end
context "when current password is wrong" do
it "returns 422 (Unprocessable Entity)" do
put(:update, params: {id: user.id, password: {
current_password: "InvalidPassword123",
password: "password123",
password_confirmation: "password123"
}})
expect(response.status).to eq 422
end
end
end
end
end

View File

@@ -0,0 +1,40 @@
require "rails_helper"
RSpec.describe Api::V1::PostsController do
let(:user) { create(:user) }
let(:other_user) { create(:user) }
before { sign_in user }
describe "index" do
it "returns a list of discussion posts" do
create(:post, user_id: user.id)
create(:post, user_id: other_user.id)
get :index
expect(response_body[:posts].size).to eq 2
end
it "returns a list of discussion posts filtered by post type" do
post = create(:post, user_id: user.id)
create(:post, user_id: other_user.id)
symptom = post.symptom_ids
get :index, params: {id: symptom[0], type: "symptom"}
expect(response_body[:posts].size).to eq 1
end
it "returns a list of discussion posts filtered by topic followings" do
post = create(:post, user_id: user.id)
create(:post, user_id: user.id)
create(:post, user_id: user.id)
topic_user_is_following = user.topic_following
topic_user_is_following.symptom_ids = post.symptom_ids
topic_user_is_following.save
get :index, params: {following: true}
expect(response_body[:posts].size).to eq 1
end
end
end

View File

@@ -0,0 +1,85 @@
require "rails_helper"
RSpec.describe Api::V1::ProfilesController do
let(:user) { create(:user) }
let(:profile) { user.profile }
let(:another_user) { create(:user) }
let(:another_profile) { another_user.profile }
describe "show" do
context "when no user logged-in" do
it "returns 302 (Permanent Redirect)" do
get :show, params: {id: profile.id}
expect(response.status).to eq 302
end
end
context "when different user logged-in" do
before { sign_in another_user }
it "returns 401 (unauthorized)" do
get :show, params: {id: profile.id}
expect(response.status).to eq 401
end
end
context "when user logged-in" do
before { sign_in user }
it "returns profile" do
get :show, params: {id: profile.id}
expect(response_body[:profile][:id]).to eq profile.id
end
context "with invalid profile id" do
it "returns 404 (RecordNotFound)" do
get :show, params: {id: "a123"}
expect(response.status).to eq 404
end
end
context "when different profile id is requested" do
it "returns 401 (unauthorized)" do
get :show, params: {id: another_profile.id}
expect(response.status).to eq 401
end
end
end
end
describe "update" do
context "when user logged-in" do
before { sign_in user }
let(:profile_attributes) { attributes_for(:profile) }
it "updates profile attributes" do
put :update, params: {id: profile.id, profile: profile_attributes}
updated_profile = response_body[:profile]
expect(updated_profile[:id]).to eq profile.id
expect(updated_profile[:country_id]).to eq profile_attributes[:country_id]
expect(updated_profile[:sex_id]).to eq profile_attributes[:sex_id]
expect(updated_profile[:birth_date]).to eq profile_attributes[:birth_date].to_date.to_s
end
context "with available locale for country" do
before { profile_attributes[:country_id] = "IT" }
it "sets the first country's language as locale" do
put :update, params: {id: profile.id, profile: profile_attributes}
expect(I18n.locale).to eq :it
end
after { I18n.locale = :en }
end
context "with unavailable locale for country" do
before { profile_attributes[:country_id] = "IN" }
it "sets locale to default" do
put :update, params: {id: profile.id, profile: profile_attributes}
expect(I18n.locale).to eq I18n.default_locale
end
end
context "when some attribute is invalid" do
before { profile_attributes[:sex_id] = "blah" }
it "returns 422 (unprocessable_entity)" do
put :update, params: {id: profile.id, profile: profile_attributes}
expect(response.status).to eq 422
end
end
end
end
end

View File

@@ -0,0 +1,56 @@
require "rails_helper"
RSpec.describe Api::V1::RegistrationsController do
let(:attributes) do
{
email: "user@example.com",
password: "secret123",
password_confirmation: "secret123",
screen_name: "user",
captcha_response: "dummy-captcha-response"
}
end
let(:user) { create(:user, attributes.slice(:email, :password, :password_confirmation)) }
describe "create" do
let(:registration) do
new_registration = Registration.new(
ActionController::Parameters.new(registration: attributes)
)
new_registration.user = user
new_registration
end
before { allow(Registration).to receive(:create!).and_return(registration) }
it "registers a new user" do
post :create, params: {registration: attributes}
expect(response.status).to eq 200
user = response_body[:users][0]
expect(user[:email]).to eq attributes[:email]
end
end
let(:attributes_for_destroy) do
{
delete_reason: "Reason",
email: user.email
}
end
describe "destroy" do
let!(:checkin_with_ref) do
create(:checkin, date: Date.parse("2016-01-06"), user_id: user.id, position_id: 1, postal_code: "123456789")
end
it "removes user and it's profile" do
delete :destroy, params: attributes_for_destroy
expect(response.status).to eq 200
expect(Feedback.last.delete_reason).to eq attributes_for_destroy[:delete_reason]
expect(checkin_with_ref.reload.postal_code).to be_nil
expect(checkin_with_ref.reload.position).to be_nil
expect(User.find_by(id: user.id)).to be_nil
expect(Profile.find_by(user_id: user.id)).to be_nil
end
end
end

View File

@@ -0,0 +1,40 @@
require "rails_helper"
RSpec.describe Api::V1::SearchesController do
before { I18n.default_locale = :en }
let!(:user) { create(:user) }
let!(:foods) { create_list(:food, 2) }
let!(:conditions) { create_list(:condition, 2) }
before { sign_in user }
describe "show" do
context "when searchable exists for the requested date" do
let!(:condition_to_find) { create(:condition, name: "ACL injury") }
it "returns correct searchables with first three letters" do
get :show, params: {resource: "condition", query: {name: "ACL"}}
expect_valid_responses(response_body)
end
def expect_valid_responses(response)
expect(response[:search][:searchables].count).to eq 1
expect(response[:search][:searchables][0][:type]).to eq "condition"
expect(response[:search][:searchables][0][:name]).to eq "ACL injury"
end
end
context "when food exists" do
let!(:food_to_find) { create(:food, long_desc: "Banana") }
before { get :show, params: {resource: "food", query: {name: "bana"}} }
it "returns correct searchable food" do
expect(response_body[:search][:searchables].count).to eq 1
expect(response_body[:search][:searchables][0][:type]).to eq "food"
expect(response_body[:search][:searchables][0][:name]).to eq "Banana"
end
end
end
end

View File

@@ -0,0 +1,61 @@
require "rails_helper"
RSpec.describe Api::V1::SexesController do
let(:test_sex_id) { "male" }
let(:test_sex_name_en) { "Male" }
let(:test_sex_name_it) { "Maschio" }
describe "index" do
let(:all_sexes_count) { Sex.all.count }
it "returns all sexes" do
get :index
expect(response_body[:sexes].size).to eq all_sexes_count
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translations" do
get :index
test_sex = response_body[:sexes].find { |c| c[:id].eql?(test_sex_id) }
expect(test_sex[:name]).to eq test_sex_name_en
end
end
context "with 'it' locale" do
before { I18n.default_locale = "it" }
it "returns 'it' translations" do
get :index
test_sex = response_body[:sexes].find { |c| c[:id].eql?(test_sex_id) }
expect(test_sex[:name]).to eq test_sex_name_it
end
after { I18n.default_locale = "en" }
end
end
describe "show" do
it "returns test sex" do
get :show, params: {id: test_sex_id}
expect(response_body[:sex][:id]).to eq test_sex_id
end
context "with 'en' locale" do
before { I18n.default_locale = "en" }
it "returns 'en' translation" do
get :show, params: {id: test_sex_id}
expect(response_body[:sex][:name]).to eq test_sex_name_en
end
end
context "with 'it' locale" do
before { I18n.default_locale = "it" }
it "returns 'it' translation" do
get :show, params: {id: test_sex_id}
expect(response_body[:sex][:name]).to eq test_sex_name_it
end
after { I18n.default_locale = "en" }
end
context "with invalid sex id" do
let(:invalid_sex_id) { "blah" }
it "returns 400 (Bad Request)" do
get :show, params: {id: invalid_sex_id}
expect(response.status).to eq 400
end
end
end
end

View File

@@ -0,0 +1,47 @@
require "rails_helper"
RSpec.describe Api::V1::SymptomsController do
let!(:user) { create(:user) }
let!(:global_symptom) { create(:symptom) }
let!(:personal_symptom) { create(:user_symptom, user: user).symptom }
let!(:another_user_symptom) { create(:user_symptom).symptom }
let(:user_abilities) { Ability.new(user) }
let(:accessible_symptoms) { Symptom.accessible_by(user_abilities) }
before { sign_in user }
describe "index" do
it "returns all accessible symptoms" do
get :index
returned_symptom_ids = response_body[:symptoms].map { |c| c[:id] }
accessible_symptom_ids = accessible_symptoms.map(&:id)
expect(returned_symptom_ids.to_set).to eq accessible_symptom_ids.to_set
end
end
describe "show" do
context "when symptom is accessible" do
it "return the requested symptom" do
get :show, params: {id: global_symptom.id}
expect(response_body[:symptom][:id]).to eq global_symptom.id
end
end
context "when local symptom is accessible" do
it "returns 200 (Authorized)" do
get :show, params: {id: another_user_symptom.id}
expect(response.status).to eq 200
end
end
end
describe "create" do
let(:symptom_attributes) { {name: "Headache"} }
it "creates the symptom as personal for the current user" do
post :create, params: {symptom: symptom_attributes}
created_symptom = response_body[:symptom]
expect(created_symptom[:name]).to eq symptom_attributes[:name]
expect(Symptom.find(created_symptom[:id]).global).to be false
end
end
end

View File

@@ -0,0 +1,45 @@
require "rails_helper"
RSpec.describe Api::V1::TagsController do
let!(:user) { create(:user) }
let!(:tag) { create(:tag) }
let(:user_abilities) { Ability.new(user) }
let(:accessible_tags) { Tag.accessible_by(user_abilities) }
before { sign_in user }
describe "index" do
it "returns all accessible tags" do
get :index
returned_tag_ids = response_body[:tags].map { |c| c[:id] }
accessible_tag_ids = accessible_tags.map(&:id)
expect(returned_tag_ids.to_set).to eq accessible_tag_ids.to_set
end
context "with ids param" do
let(:tag_ids) { create_list(:tag, 2).map(&:id) }
it "returns requested tags only" do
get :index, params: {ids: tag_ids}
returned_tag_ids = response_body[:tags].map { |c| c[:id] }
expect(returned_tag_ids.to_set).to eq tag_ids.to_set
end
end
end
describe "show" do
it "returns the requested tag" do
get :show, params: {id: tag.id}
expect(response_body[:tag][:id]).to eq tag.id
end
end
describe "create" do
let(:tag_attributes) { {name: "had sex"} }
it "creates the tag" do
post :create, params: {tag: tag_attributes}
created_tag = response_body[:tag]
expect(created_tag[:name]).to eq tag_attributes[:name]
expect(Tag.find(created_tag[:id]).global).to be false
end
end
end

View File

@@ -0,0 +1,88 @@
require "rails_helper"
RSpec.describe Api::V1::TrackingsController do
let!(:user) { create(:user) }
let!(:current_tracking) { create(:tracking, :active, :for_condition, user: user) }
let!(:old_tracking) { create(:tracking, :inactive, :for_symptom, user: user) }
let(:another_user_tracking) { create(:tracking, :active, :for_condition) }
before { sign_in user }
describe "index" do
context "at current time" do
let(:trackable_type) { current_tracking.trackable_type }
let(:at) { Time.zone.now }
it "returns current trackings only" do
get :index, params: {at: at, trackable_type: trackable_type}
returned_ids = response_body[:trackings].map { |t| t[:id] }
expect(returned_ids).to include current_tracking.id
expect(returned_ids).not_to include old_tracking.id
end
end
context "at past time" do
let(:trackable_type) { old_tracking.trackable_type }
let(:at) { 5.days.ago }
it "returns old trackings only" do
get :index, params: {at: at, trackable_type: trackable_type}
returned_ids = response_body[:trackings].map { |t| t[:id] }
expect(returned_ids).to include old_tracking.id
expect(returned_ids).not_to include current_tracking.id
end
end
end
describe "show" do
context "when a current user's tracking is requested" do
it "returns the requested tracking" do
get :show, params: {id: current_tracking.id}
expect(response_body[:tracking][:id]).to eq current_tracking.id
end
end
context "when another user's tracking is requested" do
it "returns 401 (Unauthorized)" do
get :show, params: {id: another_user_tracking.id}
expect(response.status).to eq 401
end
end
end
describe "create" do
let(:symptom) { create(:symptom) }
let(:tracking_attributes) { {trackable_id: symptom.id, trackable_type: symptom.class.name} }
it "saves a current tracking record" do
post :create, params: {tracking: tracking_attributes}
expect(response_body[:tracking][:id]).to be_present
expect(response_body[:tracking][:user_id]).to eq user.id
expect(response_body[:tracking][:trackable_id]).to eq symptom.id
expect(response_body[:tracking][:trackable_type]).to eq symptom.class.name
start_at = Date.parse(response_body[:tracking][:start_at])
expect(start_at.strftime("%F")).to eq Time.zone.today.strftime("%F")
end
end
describe "destroy" do
context "when destroying a current user's tracking" do
context "when tracking started in the past" do
before { current_tracking.update!(start_at: Time.zone.today - 2.days) }
it "sets end_date on that tracking" do
delete :destroy, params: {id: current_tracking.id}
end_at = current_tracking.reload.end_at
expect(end_at).to be_present
expect(end_at.strftime("%F")).to eq Time.zone.now.strftime("%F")
end
end
context "when tracking started today" do
it "destroys that tracking" do
delete :destroy, params: {id: current_tracking.id}
expect(Tracking.find_by(id: current_tracking.id)).to be_nil
end
end
end
context "when destroying another user's tracking" do
it "returns 401 (Unauthorized)" do
delete :destroy, params: {id: another_user_tracking.id}
expect(response.status).to eq 401
end
end
end
end

View File

@@ -0,0 +1,47 @@
require "rails_helper"
RSpec.describe Api::V1::TreatmentsController do
let!(:user) { create(:user) }
let!(:global_treatment) { create(:treatment) }
let!(:personal_treatment) { create(:user_treatment, user: user).treatment }
let!(:another_user_treatment) { create(:user_treatment).treatment }
let(:user_abilities) { Ability.new(user) }
let(:accessible_treatments) { Treatment.accessible_by(user_abilities) }
before { sign_in user }
describe "index" do
it "returns all accessible treatments" do
get :index
returned_treatment_ids = response_body[:treatments].map { |c| c[:id] }
accessible_treatment_ids = accessible_treatments.map(&:id)
expect(returned_treatment_ids.to_set).to eq accessible_treatment_ids.to_set
end
end
describe "show" do
context "when treatment is accessible" do
it "return the requested treatment" do
get :show, params: {id: global_treatment.id}
expect(response_body[:treatment][:id]).to eq global_treatment.id
end
end
context "when local treatment is accessible" do
it "returns 200 (Authorized)" do
get :show, params: {id: another_user_treatment.id}
expect(response.status).to eq 200
end
end
end
describe "create" do
let(:treatment_attributes) { {name: "Aspirin"} }
it "creates the treatment as personal for the current user" do
post :create, params: {treatment: treatment_attributes}
created_treatment = response_body[:treatment]
expect(created_treatment[:name]).to eq treatment_attributes[:name]
expect(Treatment.find(created_treatment[:id]).global).to be false
end
end
end

View File

@@ -0,0 +1,66 @@
require "rails_helper"
RSpec.describe Api::V1::UsersController do
let(:user) { create(:user) }
let(:another_user) { create(:user) }
describe "show" do
context "when no user logged-in" do
it "returns 302 (Permanent Redirect)" do
get :show, params: {id: user.id}
expect(response.status).to eq 302
end
end
context "when different user logged-in" do
before { sign_in another_user }
it "returns 401 (unauthorized)" do
get :show, params: {id: user.id}
expect(response.status).to eq 401
end
end
context "when user logged-in" do
before { sign_in user }
it "returns user" do
get :show, params: {id: user.id}
expect(response_body[:user][:id]).to eq user.id
end
context "with invalid user id" do
it "returns 404 (RecordNotFound)" do
get :show, params: {id: "a123"}
expect(response.status).to eq 404
end
end
context "when different user id is requested" do
it "returns 401 (unauthorized)" do
get :show, params: {id: another_user.id}
expect(response.status).to eq 401
end
end
end
end
describe "update" do
context "with valid email" do
before { sign_in user }
it "allow user ti change email" do
put :update, params: {id: user.id, user: {email: "some_email@ex.com"}}
expect(response.status).to eq 200
expect(user.reload.email).to eq "some_email@ex.com"
end
end
context "with invalid email" do
before { sign_in user }
it "returns an error" do
put :update, params: {id: user.id, user: {email: another_user.email}}
expect(response.status).to eq 422
end
end
end
end

View File

@@ -0,0 +1,44 @@
require "rails_helper"
describe Api::V1::WeathersController do
let(:user) { create(:user) }
let(:date) { "2016-01-06" }
let(:postal_code) { "55403" }
let(:index_action) { get :index, params: {date: date, postal_code: postal_code, format: :js} }
context "anonymous user" do
describe "index" do
it "should not hit weather API" do
expect(WeatherRetriever).not_to receive(:get)
index_action
end
it "should not authorize" do
index_action
expect(response).to have_http_status(:unauthorized)
end
end
end
context "user is present" do
before { sign_in user }
describe "index" do
let(:weather) { create :weather }
let(:json_response) { JSON.parse(response.body, symbolize_names: true) }
let(:expected_keys) { %i[id humidity icon precip_intensity pressure temperature_max temperature_min] }
let(:not_expected_keys) { %i[date postal_code] }
before { expect(WeatherRetriever).to receive(:get).with(Date.parse(date), postal_code).and_return(weather) }
before { index_action }
subject { json_response[:weather].keys }
it { is_expected.to include(*expected_keys) }
it { is_expected.not_to include(*not_expected_keys) }
it { expect(response).to have_http_status(:ok) }
end
end
end

View File

@@ -0,0 +1,9 @@
FactoryBot.define do
factory :checkin_condition, class: Checkin::Condition do
transient do
values { [(0..4).to_a + [nil]] }
end
condition_id { FactoryBot.create(:condition).id }
value { values.sample }
end
end

View File

@@ -0,0 +1,9 @@
FactoryBot.define do
factory :checkin_symptom, class: Checkin::Symptom do
transient do
values { [(0..4).to_a + [nil]] }
end
symptom_id { FactoryBot.create(:symptom).id }
value { values.sample }
end
end

View File

@@ -0,0 +1,10 @@
FactoryBot.define do
factory :checkin_treatment, class: Checkin::Treatment do
transient do
values { ["20 mg", "2 ml", "3 x 1 cap", "2 x 10 mg", nil, "3 x 4 ml", "1 cap", "5 ml", "2 x 2 cap"] }
end
treatment_id { FactoryBot.create(:treatment).id }
value { values.sample }
is_taken { value.present? ? true : [true, false].sample }
end
end

View File

@@ -0,0 +1,8 @@
FactoryBot.define do
factory :checkin do
user_id { FactoryBot.create(:user).id }
sequence(:date) { |n| Time.zone.now - n.days }
note { FFaker::Lorem.sentence }
tag_ids { FactoryBot.create_list(:tag, 2).map(&:id) }
end
end

View File

@@ -0,0 +1,7 @@
FactoryBot.define do
factory :comment do
body { "This is a comment." }
encrypted_user_id { create(:user).encrypted_id }
post_id { create(:post).id }
end
end

View File

@@ -0,0 +1,20 @@
# == Schema Information
#
# Table name: conditions
#
# id :integer not null, primary key
# global :boolean default(TRUE)
# created_at :datetime not null
# updated_at :datetime not null
# trackable_usages_count :integer default(0)
#
FactoryBot.define do
factory :condition do
sequence(:name) { |n| "Condition#{n}" }
trait :personal do
global { false }
end
end
end

View File

@@ -0,0 +1,14 @@
FactoryBot.define do
factory :food do
sequence(:ndb_no) { |n| "id#{n}" }
comname { FFaker::Lorem.sentence }
long_desc { FFaker::Lorem.sentence }
sciname { FFaker::Lorem.sentence }
shrt_desc { FFaker::Lorem.sentence }
trait :personal do
global { false }
end
end
end

View File

@@ -0,0 +1,11 @@
FactoryBot.define do
factory :notification do
kind { "reaction" }
notificateable { create(:post) }
encrypted_user_id { create(:user).encrypted_id }
encrypted_notify_user_id { create(:user).encrypted_id }
initialize_with { new(attributes) }
end
end

View File

@@ -0,0 +1,8 @@
FactoryBot.define do
factory :pattern do
encrypted_user_id { create(:user).encrypted_id }
start_at { Time.zone.now }
end_at { 2.days.from_now }
name { "Chuck Norris" }
end
end

View File

@@ -0,0 +1,8 @@
FactoryBot.define do
factory :post do
title { "Frustrating day" }
body { "Today was really hard with my symptoms" }
encrypted_user_id { "abcd1234" }
symptom_ids { [create(:symptom).id] }
end
end

View File

@@ -0,0 +1,30 @@
# == Schema Information
#
# Table name: profiles
#
# id :integer not null, primary key
# user_id :integer
# country_id :string
# birth_date :date
# sex_id :string
# onboarding_step_id :string
# created_at :datetime not null
# updated_at :datetime not null
# ethnicity_ids_string :string
# day_habit_id :string
# education_level_id :string
# day_walking_hours :integer
# most_recent_doses :hstore
# screen_name :string
# most_recent_conditions_positions :hstore
# most_recent_symptoms_positions :hstore
# most_recent_treatments_positions :hstore
#
FactoryBot.define do
factory :profile do
birth_date { (25..55).to_a.sample.years.ago }
country_id { FFaker::Address.country_code }
sex_id { Sex.all_ids.sample }
end
end

View File

@@ -0,0 +1,7 @@
FactoryBot.define do
factory :promotion_rate do
user_id { FactoryBot.create(:user).id }
sequence(:date) { |n| Time.zone.now - n.days }
score { rand(1..10) }
end
end

View File

@@ -0,0 +1,7 @@
FactoryBot.define do
factory :reaction do
value { ":smile:" }
encrypted_user_id { create(:user).encrypted_id }
reactable { create(:post) }
end
end

View File

@@ -0,0 +1,20 @@
# == Schema Information
#
# Table name: symptoms
#
# id :integer not null, primary key
# global :boolean default(TRUE)
# created_at :datetime not null
# updated_at :datetime not null
# trackable_usages_count :integer default(0)
#
FactoryBot.define do
factory :symptom do
sequence(:name) { |n| "Symptom#{n}" }
trait :personal do
global { false }
end
end
end

View File

@@ -0,0 +1,18 @@
# == Schema Information
#
# Table name: tags
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :tag do
sequence(:name) { |n| "Tag#{n}" }
trait :personal do
global { false }
end
end
end

View File

@@ -0,0 +1,4 @@
FactoryBot.define do
factory :topic_following do
end
end

View File

@@ -0,0 +1,19 @@
# == Schema Information
#
# Table name: trackable_usages
#
# id :integer not null, primary key
# user_id :integer
# trackable_id :integer
# trackable_type :string
# count :integer default(1)
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :trackable_usage do
user
association :trackable, factory: :condition
end
end

View File

@@ -0,0 +1,41 @@
# == Schema Information
#
# Table name: trackings
#
# id :integer not null, primary key
# user_id :integer
# trackable_id :integer
# trackable_type :string
# start_at :date
# end_at :date
# color_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :tracking do
user
trait :for_condition do
association :trackable, factory: :condition
end
trait :for_symptom do
association :trackable, factory: :symptom
end
trait :for_treatment do
association :trackable, factory: :treatment
end
trait :active do
start_at { Time.zone.today }
end
trait :inactive do
start_at { Time.zone.today - 7.days }
end_at { Date.yesterday }
end
end
end

View File

@@ -0,0 +1,20 @@
# == Schema Information
#
# Table name: treatments
#
# id :integer not null, primary key
# global :boolean default(TRUE)
# created_at :datetime not null
# updated_at :datetime not null
# trackable_usages_count :integer default(0)
#
FactoryBot.define do
factory :treatment do
sequence(:name) { |n| "Treatment#{n}" }
trait :personal do
global { false }
end
end
end

View File

@@ -0,0 +1,17 @@
# == Schema Information
#
# Table name: user_conditions
#
# id :integer not null, primary key
# user_id :integer
# condition_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :user_condition do
user
association :condition, :personal
end
end

View File

@@ -0,0 +1,6 @@
FactoryBot.define do
factory :user_food do
user
association :food, :personal
end
end

View File

@@ -0,0 +1,17 @@
# == Schema Information
#
# Table name: user_symptoms
#
# id :integer not null, primary key
# user_id :integer
# symptom_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :user_symptom do
user
association :symptom, :personal
end
end

View File

@@ -0,0 +1,6 @@
FactoryBot.define do
factory :user_tag do
user
association :tag, :personal
end
end

View File

@@ -0,0 +1,17 @@
# == Schema Information
#
# Table name: user_treatments
#
# id :integer not null, primary key
# user_id :integer
# treatment_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :user_treatment do
user
association :treatment, :personal
end
end

View File

@@ -0,0 +1,34 @@
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string default(""), not null
# encrypted_password :string default(""), not null
# reset_password_token :string
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string
# last_sign_in_ip :string
# authentication_token :string not null
# invitation_token :string
# invitation_created_at :datetime
# invitation_sent_at :datetime
# invitation_accepted_at :datetime
# invitation_limit :integer
# invited_by_id :integer
# invited_by_type :string
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :user do
sequence(:email) { |number| "user#{number}@example.com" }
password { "password123" }
password_confirmation { "password123" }
end
end

View File

@@ -0,0 +1,12 @@
FactoryBot.define do
factory :weather do
date { "MyString" }
postal_code { "MyString" }
icon { "MyString" }
temperature_min { 1.5 }
temperature_max { 1.5 }
precip_intensity { 1.5 }
pressure { 1.5 }
humidity { 1.5 }
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
---
http_interactions:
- request:
method: post
uri: https://www.google.com/recaptcha/api/siteverify
body:
encoding: UTF-8
string: remoteip&response=non-expired-recaptcha-response-dummy-string&secret=<RECAPTCHA_SECRET_KEY>
headers:
Accept:
- application/json
User-Agent:
- Faraday v0.9.2
Content-Type:
- application/x-www-form-urlencoded
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Content-Type:
- application/json; charset=utf-8
Date:
- Wed, 08 Jun 2016 08:49:46 GMT
Expires:
- Wed, 08 Jun 2016 08:49:46 GMT
Cache-Control:
- private, max-age=0
X-Content-Type-Options:
- nosniff
X-Xss-Protection:
- 1; mode=block
Server:
- GSE
Transfer-Encoding:
- chunked
body:
encoding: ASCII-8BIT
string: |-
{
"success": true,
"challenge_ts": "2016-06-08T07:54:17Z",
"hostname": "localhost"
}
http_version:
recorded_at: Wed, 08 Jun 2016 08:49:47 GMT
recorded_with: VCR 3.0.3

View File

@@ -0,0 +1,49 @@
---
http_interactions:
- request:
method: post
uri: https://www.google.com/recaptcha/api/siteverify
body:
encoding: UTF-8
string: remoteip&response=expired-recaptcha-response-dummy-string&secret=<RECAPTCHA_SECRET_KEY>
headers:
Accept:
- application/json
User-Agent:
- Faraday v0.9.2
Content-Type:
- application/x-www-form-urlencoded
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Content-Type:
- application/json; charset=utf-8
Date:
- Wed, 08 Jun 2016 08:35:05 GMT
Expires:
- Wed, 08 Jun 2016 08:35:05 GMT
Cache-Control:
- private, max-age=0
X-Content-Type-Options:
- nosniff
X-Xss-Protection:
- 1; mode=block
Server:
- GSE
Transfer-Encoding:
- chunked
body:
encoding: ASCII-8BIT
string: |-
{
"success": false,
"challenge_ts": "2016-06-08T07:54:17Z",
"hostname": "localhost"
}
http_version:
recorded_at: Wed, 08 Jun 2016 08:35:06 GMT
recorded_with: VCR 3.0.3

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,38 @@
---
http_interactions:
- request:
method: get
uri: https://nominatim.openstreetmap.org/search?accept-language=en&addressdetails=1&format=json&q=55403
body:
encoding: US-ASCII
string: ''
headers:
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
User-Agent:
- Ruby
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Tue, 05 Dec 2023 18:17:55 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '602'
Connection:
- keep-alive
Keep-Alive:
- timeout=20
body:
encoding: ASCII-8BIT
string: !binary |-
W3sicGxhY2VfaWQiOjMzMTA3NzYzNywibGljZW5jZSI6IkRhdGEgwqkgT3BlblN0cmVldE1hcCBjb250cmlidXRvcnMsIE9EYkwgMS4wLiBodHRwOi8vb3NtLm9yZy9jb3B5cmlnaHQiLCJsYXQiOiI0NC45Njc0ODU5OTU1MTUyNyIsImxvbiI6Ii05My4yODk3Njc4NDQ5NDI3NCIsImNsYXNzIjoicGxhY2UiLCJ0eXBlIjoicG9zdGNvZGUiLCJwbGFjZV9yYW5rIjoyMSwiaW1wb3J0YW5jZSI6MC4yMjUwMDAwOTk5OTk5OTk5MywiYWRkcmVzc3R5cGUiOiJwb3N0Y29kZSIsIm5hbWUiOiI1NTQwMyIsImRpc3BsYXlfbmFtZSI6Ik1pbm5lYXBvbGlzLCBIZW5uZXBpbiBDb3VudHksIDU1NDAzLCBNaW5uZXNvdGEsIFVuaXRlZCBTdGF0ZXMiLCJhZGRyZXNzIjp7ImNpdHkiOiJNaW5uZWFwb2xpcyIsImNvdW50eSI6Ikhlbm5lcGluIENvdW50eSIsInBvc3Rjb2RlIjoiNTU0MDMiLCJzdGF0ZSI6Ik1pbm5lc290YSIsIklTTzMxNjYtMi1sdmw0IjoiVVMtTU4iLCJjb3VudHJ5IjoiVW5pdGVkIFN0YXRlcyIsImNvdW50cnlfY29kZSI6InVzIn0sImJvdW5kaW5nYm94IjpbIjQ0LjgwNzQ4NjAiLCI0NS4xMjc0ODYwIiwiLTkzLjQ0OTc2NzgiLCItOTMuMTI5NzY3OCJdfV0=
recorded_at: Tue, 05 Dec 2023 18:17:55 GMT
recorded_with: VCR 6.2.0

View File

@@ -0,0 +1,38 @@
---
http_interactions:
- request:
method: get
uri: https://nominatim.openstreetmap.org/search?accept-language=en&addressdetails=1&format=json&q=55403
body:
encoding: US-ASCII
string: ''
headers:
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
User-Agent:
- Ruby
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Tue, 05 Dec 2023 18:17:56 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '602'
Connection:
- keep-alive
Keep-Alive:
- timeout=20
body:
encoding: ASCII-8BIT
string: !binary |-
W3sicGxhY2VfaWQiOjMzMTA3NzYzNywibGljZW5jZSI6IkRhdGEgwqkgT3BlblN0cmVldE1hcCBjb250cmlidXRvcnMsIE9EYkwgMS4wLiBodHRwOi8vb3NtLm9yZy9jb3B5cmlnaHQiLCJsYXQiOiI0NC45Njc0ODU5OTU1MTUyNyIsImxvbiI6Ii05My4yODk3Njc4NDQ5NDI3NCIsImNsYXNzIjoicGxhY2UiLCJ0eXBlIjoicG9zdGNvZGUiLCJwbGFjZV9yYW5rIjoyMSwiaW1wb3J0YW5jZSI6MC4yMjUwMDAwOTk5OTk5OTk5MywiYWRkcmVzc3R5cGUiOiJwb3N0Y29kZSIsIm5hbWUiOiI1NTQwMyIsImRpc3BsYXlfbmFtZSI6Ik1pbm5lYXBvbGlzLCBIZW5uZXBpbiBDb3VudHksIDU1NDAzLCBNaW5uZXNvdGEsIFVuaXRlZCBTdGF0ZXMiLCJhZGRyZXNzIjp7ImNpdHkiOiJNaW5uZWFwb2xpcyIsImNvdW50eSI6Ikhlbm5lcGluIENvdW50eSIsInBvc3Rjb2RlIjoiNTU0MDMiLCJzdGF0ZSI6Ik1pbm5lc290YSIsIklTTzMxNjYtMi1sdmw0IjoiVVMtTU4iLCJjb3VudHJ5IjoiVW5pdGVkIFN0YXRlcyIsImNvdW50cnlfY29kZSI6InVzIn0sImJvdW5kaW5nYm94IjpbIjQ0LjgwNzQ4NjAiLCI0NS4xMjc0ODYwIiwiLTkzLjQ0OTc2NzgiLCItOTMuMTI5NzY3OCJdfV0=
recorded_at: Tue, 05 Dec 2023 18:17:56 GMT
recorded_with: VCR 6.2.0

View File

@@ -0,0 +1,82 @@
require "rails_helper"
describe DataExportJob do
include ActiveJob::TestHelper
let(:tag) { create :tag }
let(:mail) { double }
let(:food) { create :food }
let(:user) { create :user }
let(:checkin) { create :checkin, user_id: user.id, tag_ids: [tag.id], food_ids: [food.id] }
let(:perform_now) { perform_enqueued_jobs { described_class.perform_later(user.id) } }
context "base functionality" do
let(:checkin_treatment) { create :checkin_treatment, checkin_id: checkin.id, value: "1mg", is_taken: true }
let(:expected_csv) do
csv = "Date,#{Treatment.find(checkin_treatment.treatment_id).name},Tags,Foods,Weather summary,Weather max temperature,Weather min temperature,Weather pressure,Weather precipitation intensity,Weather humidity\n"
csv << "#{checkin.date},#{checkin_treatment.value},#{tag.name},#{food.long_desc},,,,,,\n"
end
it "passes valid csv to mailer" do
expect(UserDataMailer).to receive(:trackings_csv).with(user.email, expected_csv).and_return(mail)
expect(mail).to receive(:deliver_later)
perform_now
end
end
context "creating CSV data" do
context "with treatments" do
let(:extra_headers) { "Tags,Foods,Weather summary,Weather max temperature,Weather min temperature,Weather pressure,Weather precipitation intensity,Weather humidity" }
it "reports treatments with dosages" do
ct = create :checkin_treatment, checkin_id: checkin.id, value: "1mg", is_taken: true
expect(subject.csv_data(user)).to eq <<~CSV
Date,#{Treatment.find(ct.treatment_id).name},#{extra_headers}
#{checkin.date},#{ct.value},#{tag.name},#{food.long_desc},,,,,,
CSV
end
it "reports treatments without dosages" do
ct = create :checkin_treatment, checkin_id: checkin.id, value: nil, is_taken: true
expect(subject.csv_data(user)).to eq <<~CSV
Date,#{Treatment.find(ct.treatment_id).name},#{extra_headers}
#{checkin.date},Taken,#{tag.name},#{food.long_desc},,,,,,
CSV
end
it "reports missed treatments" do
ct = create :checkin_treatment, checkin_id: checkin.id, value: nil, is_taken: false
expect(subject.csv_data(user)).to eq <<~CSV
Date,#{Treatment.find(ct.treatment_id).name},#{extra_headers}
#{checkin.date},Not Taken,#{tag.name},#{food.long_desc},,,,,,
CSV
end
it "reports sanely with unusual data" do
# The UI should not allow this, but the data model does not prevent it
ct = create :checkin_treatment, checkin_id: checkin.id, value: "1mg", is_taken: false
expect(subject.csv_data(user)).to eq <<~CSV
Date,#{Treatment.find(ct.treatment_id).name},#{extra_headers}
#{checkin.date},Not Taken,#{tag.name},#{food.long_desc},,,,,,
CSV
end
end
context "with weather" do
let(:extra_headers) { "Tags,Foods,Weather summary,Weather max temperature,Weather min temperature,Weather pressure,Weather precipitation intensity,Weather humidity" }
it "includes weather data" do
checkin.weather_id = FactoryBot.create(:weather).id
checkin.save
expect(subject.csv_data(user)).to eq <<~CSV
Date,#{extra_headers}
#{checkin.date},#{tag.name},#{food.long_desc},,1.5,1.5,1.5,1.5,1.5
CSV
end
end
end
end

View File

@@ -0,0 +1,24 @@
require "rails_helper"
describe SwitchTrackableVisibility do
include ActiveJob::TestHelper
before(:all) do
@condition = create(:condition, :personal)
create_list(:trackable_usage,
Flaredown.config.trackables_min_popularity - 1,
trackable_type: @condition.class.to_s,
trackable_id: @condition.id)
end
let!(:trackable_usage) { TrackableUsage.last }
context "for #{Flaredown.config.trackables_min_popularity} amount of tracks switch topic to global" do
before(:each) do
create(:trackable_usage, trackable_type: @condition.class.to_s, trackable_id: @condition.id)
SwitchTrackableVisibility.perform_now(trackable_usage.id)
end
it { expect(trackable_usage.trackable.reload.global?).to be true }
end
end

View File

@@ -0,0 +1,23 @@
require "rails_helper"
RSpec.describe CheckinReminderMailer, type: :mailer do
describe "checkin reminder email" do
let(:user_email) { create(:user, email: "test@flaredown.com").email }
let(:mail) { CheckinReminderMailer.remind(email: user_email) }
it "renders the headers" do
expect(mail.subject).to eq(I18n.t("checkin_reminder_mailer.subject"))
expect(mail.to).to eq([user_email])
expect(mail.from).to eq(["from@some.email"])
end
it "renders the body" do
body = I18n.t("checkin_reminder_mailer.body.text", base_url: Rails.application.secrets.base_url)
expect(mail.body.encoded.strip.tr('\"', "")).to match(body)
end
it "renders the attachment" do
expect(mail.attachments.count).to eq 1
end
end
end

View File

@@ -0,0 +1,6 @@
class CheckinReminderMailerPreview < ActionMailer::Preview
# Preview emails at http://localhost:3000/rails/mailers/checkin_reminder_mailer/remind
def remind
CheckinReminderMailer.remind(email: "test@flaredown.com")
end
end

View File

@@ -0,0 +1,11 @@
class TopPostsMailerPreview < ActionMailer::Preview
# Preview emails at http://localhost:3000/rails/mailers/top_posts_mailer/notify
def notify
TopPostsMailer.notify(email: "test@flaredown.com", top_posts_ids: top_posts_ids)
end
def top_posts_ids
posts = Post.pluck(:id).map(&:to_s)
posts.any? ? posts.first(5) : []
end
end

View File

@@ -0,0 +1,7 @@
# Preview all emails at http://localhost:3000/rails/mailers/user_data_mailer
class UserDataMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/user_data_mailer/trackings_csv
def trackings_csv
UserDataMailer.trackings_csv("some@email.yo", "header1,header2\nvalue1, value2\n")
end
end

View File

@@ -0,0 +1,23 @@
require "rails_helper"
describe UserDataMailer do
describe "trackings_csv" do
let(:mail) { UserDataMailer.trackings_csv(to_email, "header1,header2\nvalue1, value2\n") }
let(:to_email) { "some@email.yo" }
it "renders the headers" do
expect(mail.subject).to eq(I18n.t("user_data_mailer.trackings_csv.subject"))
expect(mail.to).to eq([to_email])
expect(mail.from).to eq(["from@some.email"])
end
it "renders the body" do
expect(mail.body.encoded).to match("- The Flaredown Team")
end
it "has attachment" do
expect(mail.attachments.count).to eq 1
expect(mail.attachments.first.content_type).to eq "text/csv; filename=data.csv"
end
end
end

View File

@@ -0,0 +1,72 @@
require "rails_helper"
require "cancan/matchers"
RSpec.describe Ability do
let!(:user) { create(:user) }
subject { Ability.new(user) }
context "for conditions" do
let!(:global_condition) { create(:condition) }
let!(:personal_condition) { create(:user_condition, user: user).condition }
let!(:another_user_condition) { create(:user_condition).condition }
let!(:popular_condition) { create(:condition, :personal) }
before { create_list(:user_condition, Flaredown.config.trackables_min_popularity, condition: popular_condition) }
context "index" do
it "allow to index personal condition" do
is_expected.to be_able_to(:index, personal_condition)
end
it "allow to index global conditions" do
is_expected.to be_able_to(:index, global_condition)
end
it "don't allow to index another user's personal condition" do
is_expected.not_to be_able_to(:index, another_user_condition)
end
end
context "show" do
it "allow to show global conditions" do
is_expected.to be_able_to(:show, global_condition)
end
it "allow to show personal conditions" do
is_expected.to be_able_to(:show, personal_condition)
end
it "allow to show popular conditions" do
is_expected.to be_able_to(:show, popular_condition)
end
it "allow to show another user's personal condition" do
is_expected.to be_able_to(:show, another_user_condition)
end
end
context "manage" do
it "allow to manage user's personal conditions" do
is_expected.to be_able_to(:manage, personal_condition)
end
it "don't allow to manage another user's personal conditions" do
is_expected.not_to be_able_to(:manage, another_user_condition)
end
end
context "create" do
let(:new_condition) { Condition.new(global: false) }
let(:new_global_condition) { Condition.new }
it "allow to create non-global conditions" do
is_expected.to be_able_to(:create, new_condition)
end
it "don't allow to create global conditions" do
is_expected.not_to be_able_to(:create, new_global_condition)
end
end
context "popular conditions" do
before { create_list(:user_condition, Flaredown.config.trackables_min_popularity, condition: popular_condition) }
let(:popular_condition_ids) { Ability.new(user).send(:popular_trackable_ids, "Condition") }
it { expect(popular_condition_ids).to eq([popular_condition.id]) }
end
end
end

View File

@@ -0,0 +1,61 @@
require "rails_helper"
require "cancan/matchers"
RSpec.describe Ability do
let!(:user) { create(:user) }
subject { Ability.new(user) }
context "for foods" do
let!(:global_food) { create(:food) }
let!(:personal_food) { create(:user_food, user: user).food }
let!(:another_user_food) { create(:user_food).food }
let!(:popular_food) { create(:food, :personal) }
before { create_list(:user_food, Flaredown.config.trackables_min_popularity, food: popular_food) }
context "index" do
it "allow to index personal food" do
is_expected.to be_able_to(:index, personal_food)
end
it "allow to index global food" do
is_expected.to be_able_to(:index, global_food)
end
it "don't allow to index another user's personal food" do
is_expected.not_to be_able_to(:index, another_user_food)
end
end
context "show" do
it "allow to show global food" do
is_expected.to be_able_to(:show, global_food)
end
it "allow to show personal food" do
is_expected.to be_able_to(:show, personal_food)
end
it "allow to show another user's personal food" do
is_expected.to be_able_to(:show, another_user_food)
end
end
context "manage" do
it "allow to manage user's personal food" do
is_expected.to be_able_to(:manage, personal_food)
end
it "don't allow to manage another user's personal food" do
is_expected.not_to be_able_to(:manage, another_user_food)
end
end
context "create" do
let(:new_food) { Food.new(global: false) }
let(:new_global_food) { Food.new }
it "allow to create non-global food" do
is_expected.to be_able_to(:create, new_food)
end
it "don't allow to create global food" do
is_expected.not_to be_able_to(:create, new_global_food)
end
end
end
end

View File

@@ -0,0 +1,72 @@
require "rails_helper"
require "cancan/matchers"
RSpec.describe Ability do
let!(:user) { create(:user) }
subject { Ability.new(user) }
context "for symptoms" do
let!(:global_symptom) { create(:symptom) }
let!(:personal_symptom) { create(:user_symptom, user: user).symptom }
let!(:another_user_symptom) { create(:user_symptom).symptom }
let!(:popular_symptom) { create(:symptom, :personal) }
before { create_list(:user_symptom, Flaredown.config.trackables_min_popularity, symptom: popular_symptom) }
context "index" do
it "allow to index personal symptom" do
is_expected.to be_able_to(:index, personal_symptom)
end
it "allow to index global symptoms" do
is_expected.to be_able_to(:index, global_symptom)
end
it "don't allow to index another user's personal symptom" do
is_expected.not_to be_able_to(:index, another_user_symptom)
end
end
context "show" do
it "allow to show global symptoms" do
is_expected.to be_able_to(:show, global_symptom)
end
it "allow to show personal symptoms" do
is_expected.to be_able_to(:show, personal_symptom)
end
it "allow to show popular symptoms" do
is_expected.to be_able_to(:show, popular_symptom)
end
it "allow to show another user's personal symptoms" do
is_expected.to be_able_to(:show, another_user_symptom)
end
end
context "manage" do
it "allow to manage user's personal symptoms" do
is_expected.to be_able_to(:manage, personal_symptom)
end
it "don't allow to manage another user's personal symptoms" do
is_expected.not_to be_able_to(:manage, another_user_symptom)
end
end
context "create" do
let(:new_symptom) { Symptom.new(global: false) }
let(:new_global_symptom) { Symptom.new }
it "allow to create non-global symptoms" do
is_expected.to be_able_to(:create, new_symptom)
end
it "don't allow to create global symptoms" do
is_expected.not_to be_able_to(:create, new_global_symptom)
end
end
context "popular symptoms" do
before { create_list(:user_symptom, Flaredown.config.trackables_min_popularity, symptom: popular_symptom) }
let(:popular_symptom_ids) { Ability.new(user).send(:popular_trackable_ids, "Symptom") }
it { expect(popular_symptom_ids).to eq([popular_symptom.id]) }
end
end
end

View File

@@ -0,0 +1,61 @@
require "rails_helper"
require "cancan/matchers"
RSpec.describe Ability do
let!(:user) { create(:user) }
subject { Ability.new(user) }
context "for tags" do
let!(:global_tag) { create(:tag) }
let!(:personal_tag) { create(:user_tag, user: user).tag }
let!(:another_user_tag) { create(:user_tag).tag }
let!(:popular_tag) { create(:tag, :personal) }
before { create_list(:user_tag, Flaredown.config.trackables_min_popularity, tag: popular_tag) }
context "index" do
it "allow to index personal tag" do
is_expected.to be_able_to(:index, personal_tag)
end
it "allow to index global tag" do
is_expected.to be_able_to(:index, global_tag)
end
it "don't allow to index another user's personal tag" do
is_expected.not_to be_able_to(:index, another_user_tag)
end
end
context "show" do
it "allow to show global tags" do
is_expected.to be_able_to(:show, global_tag)
end
it "allow to show personal tag" do
is_expected.to be_able_to(:show, personal_tag)
end
it "allow to show another user's personal tag" do
is_expected.to be_able_to(:show, another_user_tag)
end
end
context "manage" do
it "allow to manage user's personal tag" do
is_expected.to be_able_to(:manage, personal_tag)
end
it "don't allow to manage another user's personal tag" do
is_expected.not_to be_able_to(:manage, another_user_tag)
end
end
context "create" do
let(:new_tag) { Tag.new(global: false) }
let(:new_global_tag) { Tag.new }
it "allow to create non-global tag" do
is_expected.to be_able_to(:create, new_tag)
end
it "don't allow to create global tag" do
is_expected.not_to be_able_to(:create, new_global_tag)
end
end
end
end

View File

@@ -0,0 +1,72 @@
require "rails_helper"
require "cancan/matchers"
RSpec.describe Ability do
let!(:user) { create(:user) }
subject { Ability.new(user) }
context "for treatments" do
let!(:global_treatment) { create(:treatment) }
let!(:personal_treatment) { create(:user_treatment, user: user).treatment }
let!(:another_user_treatment) { create(:user_treatment).treatment }
let!(:popular_treatment) { create(:treatment, :personal) }
before { create_list(:user_treatment, Flaredown.config.trackables_min_popularity, treatment: popular_treatment) }
context "index" do
it "allow to index personal treatments" do
is_expected.to be_able_to(:index, personal_treatment)
end
it "allow to index global treatments" do
is_expected.to be_able_to(:index, global_treatment)
end
it "don't allow to index another user's personal treatment" do
is_expected.not_to be_able_to(:index, another_user_treatment)
end
end
context "show" do
it "allow to show global treatments" do
is_expected.to be_able_to(:show, global_treatment)
end
it "allow to show personal treatments" do
is_expected.to be_able_to(:show, personal_treatment)
end
it "allow to show popular treatments" do
is_expected.to be_able_to(:show, popular_treatment)
end
it "allow to show another user's personal treatments" do
is_expected.to be_able_to(:show, another_user_treatment)
end
end
context "manage" do
it "allow to manage user's personal treatments" do
is_expected.to be_able_to(:manage, personal_treatment)
end
it "don't allow to manage another user's personal treatments" do
is_expected.not_to be_able_to(:manage, another_user_treatment)
end
end
context "create" do
let(:new_treatment) { Treatment.new(global: false) }
let(:new_global_treatment) { Treatment.new }
it "allow to create non-global treatments" do
is_expected.to be_able_to(:create, new_treatment)
end
it "don't allow to create global treatments" do
is_expected.not_to be_able_to(:create, new_global_treatment)
end
end
context "popular treatmnets" do
before { create_list(:user_treatment, Flaredown.config.trackables_min_popularity, treatment: popular_treatment) }
let(:popular_treatment_ids) { Ability.new(user).send(:popular_trackable_ids, "Treatment") }
it { expect(popular_treatment_ids).to eq([popular_treatment.id]) }
end
end
end

View File

@@ -0,0 +1,11 @@
require "rails_helper"
RSpec.describe Checkin::Condition, type: :model do
include Mongoid::Matchers
it_behaves_like "fiveable"
describe "Relations" do
it { is_expected.to belong_to(:checkin) }
end
end

View File

@@ -0,0 +1,11 @@
require "rails_helper"
RSpec.describe Checkin::Symptom, type: :model do
include Mongoid::Matchers
it_behaves_like "fiveable"
describe "Relations" do
it { is_expected.to belong_to(:checkin) }
end
end

View File

@@ -0,0 +1,13 @@
require "rails_helper"
RSpec.describe Checkin::Treatment, type: :model do
include Mongoid::Matchers
describe "Relations" do
it { is_expected.to belong_to(:checkin) }
end
describe "Respond to" do
it { is_expected.to respond_to(:value) }
end
end

View File

@@ -0,0 +1,18 @@
require "rails_helper"
RSpec.describe Checkin, type: :model do
include Mongoid::Matchers
describe "Relations" do
it { is_expected.to have_many(:conditions) }
it { is_expected.to have_many(:symptoms) }
it { is_expected.to have_many(:treatments) }
it { is_expected.to have_one(:harvey_bradshaw_index) }
it { is_expected.to have_one(:promotion_rate) }
end
describe "Validations" do
it { is_expected.to validate_presence_of(:date) }
it { is_expected.to validate_presence_of(:encrypted_user_id) }
end
end

View File

@@ -0,0 +1,8 @@
require "rails_helper"
describe Comment do
describe "Validations" do
it { is_expected.to validate_presence_of(:body) }
it { is_expected.to validate_presence_of(:encrypted_user_id) }
end
end

View File

@@ -0,0 +1,43 @@
# == Schema Information
#
# Table name: conditions
#
# id :integer not null, primary key
# global :boolean default(TRUE)
# created_at :datetime not null
# updated_at :datetime not null
# trackable_usages_count :integer default(0)
#
require "rails_helper"
RSpec.describe Condition do
describe "Respond to" do
it { is_expected.to respond_to(:name) }
end
describe "Translations" do
before { I18n.locale = locale }
subject { create(:condition) }
context "with 'en' as current locale" do
let(:locale) { :en }
it "stores name with 'en' locale" do
t = subject.translations.to_a
expect(t.size).to eq 1
expect(t[0].locale).to eq locale
end
end
context "with 'it' as current locale" do
let(:locale) { :it }
it "stores name with 'it' locale" do
t = subject.translations.to_a
expect(t.size).to eq 1
expect(t[0].locale).to eq locale
end
end
after { I18n.locale = :en }
end
end

View File

@@ -0,0 +1,39 @@
require "rails_helper"
RSpec.describe Food do
describe "Respond to" do
it { is_expected.to respond_to(:long_desc) }
it { is_expected.to respond_to(:shrt_desc) }
it { is_expected.to respond_to(:comname) }
it { is_expected.to respond_to(:sciname) }
end
describe "class methods" do
let!(:global_food) { create(:food, long_desc: "TestFood") }
let!(:same_food_1) { create(:food, long_desc: "TestFood #{FFaker::Lorem.word}") }
let!(:same_food_2) { create(:food, long_desc: "TestFood #{FFaker::Lorem.word}") }
let!(:personal_food) { create(:food, :personal, long_desc: "TestFood") }
let!(:user_food) { create(:user_food, food: personal_food) }
let(:query) { {name: "TestFood"} }
MAX_ROWS = 2
describe "fts" do
it "return same global foods" do
another_user = create(:user)
result = Food.send(:fts, query[:name], MAX_ROWS, another_user.id)
expect(result).to eq [global_food, same_food_1]
expect(result.count).to eq MAX_ROWS
expect(result.count).to_not eq Food.where(global: true).count
expect(result.include?(personal_food)).to be false
end
it "retrun local and global foods for author" do
expect(Food.send(:fts, query[:name], MAX_ROWS, user_food.user_id)).to eq [global_food, personal_food]
end
end
end
end

View File

@@ -0,0 +1,20 @@
require "rails_helper"
describe HarveyBradshawIndex do
include Mongoid::Matchers
describe "Relations" do
it { is_expected.to belong_to(:checkin) }
end
describe "Validations" do
it { is_expected.to validate_presence_of(:checkin) }
it { is_expected.to validate_presence_of(:stools) }
it { is_expected.to validate_presence_of(:well_being) }
it { is_expected.to validate_presence_of(:abdominal_mass) }
it { is_expected.to validate_presence_of(:abdominal_pain) }
it { is_expected.to validate_uniqueness_of(:checkin_id) }
end
end

View File

@@ -0,0 +1,42 @@
require "rails_helper"
describe Notification do
let(:alice) { create(:user) }
let(:bob) { create(:user) }
let(:first_post) { create(:post) }
let(:second_post) { create(:post) }
let(:comment_for_first_post) { create(:comment, post: first_post) }
let(:comment_for_second_post) { create(:comment, post: second_post) }
context "#count_by_types" do
it "should count all by kind" do
# The following are valid possibilities for (kind, notificateable_type):
# - ("comment", "Comment"): commenting on a post
# - ("mention", "Comment"): users can only mention other users who have commented in a post
# - ("reaction", "Post")
# - ("reaction", "Comment")
alice_id = alice.encrypted_id
bob_id = bob.encrypted_id
create(:notification, kind: "comment", notificateable: comment_for_first_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
create(:notification, kind: "comment", notificateable: comment_for_second_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
create(:notification, kind: "mention", notificateable: comment_for_first_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
create(:notification, kind: "mention", notificateable: comment_for_second_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
create(:notification, kind: "reaction", notificateable: first_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
create(:notification, kind: "reaction", notificateable: second_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
create(:notification, kind: "reaction", notificateable: comment_for_first_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
create(:notification, kind: "reaction", notificateable: comment_for_second_post, encrypted_user_id: alice_id, encrypted_notify_user_id: bob_id)
expect(Notification.all.count_by_types).to eq({
"comment" => 2,
"mention" => 2,
"reaction" => 4
})
end
end
end

View File

@@ -0,0 +1,7 @@
require "rails_helper"
describe Position do
describe "Validations" do
it { is_expected.to validate_presence_of(:postal_code) }
end
end

View File

@@ -0,0 +1,9 @@
require "rails_helper"
describe Post do
describe "Validations" do
it { is_expected.to validate_presence_of(:body) }
it { is_expected.to validate_presence_of(:title) }
it { is_expected.to validate_presence_of(:encrypted_user_id) }
end
end

View File

@@ -0,0 +1,61 @@
# == Schema Information
#
# Table name: profiles
#
# id :integer not null, primary key
# user_id :integer
# country_id :string
# birth_date :date
# sex_id :string
# onboarding_step_id :string
# created_at :datetime not null
# updated_at :datetime not null
# ethnicity_ids_string :string
# day_habit_id :string
# education_level_id :string
# day_walking_hours :integer
# most_recent_doses :hstore
# screen_name :string
# most_recent_conditions_positions :hstore
# most_recent_symptoms_positions :hstore
# most_recent_treatments_positions :hstore
#
require "rails_helper"
RSpec.describe Profile do
describe "Associations" do
it { is_expected.to belong_to(:user) }
end
describe "Validations" do
it { is_expected.to validate_inclusion_of(:country_id).in_array(Country.codes) }
it { is_expected.to validate_inclusion_of(:sex_id).in_array(Sex.all_ids) }
end
describe "Respond to" do
it { is_expected.to respond_to(:birth_date) }
context "most recent trackables positions" do
it { is_expected.to respond_to(:set_most_recent_trackable_position).with(2).arguments }
it { is_expected.to respond_to(:most_recent_trackable_position_for).with(1).argument }
it { is_expected.to respond_to(:set_most_recent_condition_position).with(2).arguments }
it { is_expected.to respond_to(:most_recent_condition_position_for).with(1).argument }
it { is_expected.to respond_to(:set_most_recent_symptom_position).with(2).arguments }
it { is_expected.to respond_to(:most_recent_symptom_position_for).with(1).argument }
it { is_expected.to respond_to(:set_most_recent_treatment_position).with(2).arguments }
it { is_expected.to respond_to(:most_recent_treatment_position_for).with(1).argument }
end
end
describe "ethnicities" do
context "get" do
before { subject.ethnicity_ids_string = "latino,white" }
it "transforms to array" do
expect(subject.ethnicity_ids).to eq %w[latino white]
end
end
context "set" do
before { subject.ethnicity_ids = %w[latino white] }
it "transforms to string" do
expect(subject.ethnicity_ids_string).to eq "latino,white"
end
end
end
end

View File

@@ -0,0 +1,14 @@
require "rails_helper"
describe PromotionRate do
include Mongoid::Matchers
describe "Relations" do
it { is_expected.to belong_to(:checkin) }
end
describe "Validations" do
it { is_expected.to validate_presence_of(:checkin) }
it { is_expected.to validate_uniqueness_of(:checkin_id) }
end
end

View File

@@ -0,0 +1,50 @@
require "rails_helper"
class MockClassSkeleton < RankedEnum
end
class MockClassOverride < RankedEnum
class << self
def all_ids
%w[one two three]
end
end
end
RSpec.describe RankedEnum do
describe MockClassSkeleton do
it "yields all IDs associated with the class" do
all_ids = MockClassSkeleton.all_ids
expect(all_ids).to eq []
end
end
describe MockClassOverride do
it "yields all IDs associated with the class" do
all_ids = MockClassOverride.all_ids
expect(all_ids).to eq ["one", "two", "three"]
end
it "searches for a specific ID" do
searched_id = MockClassOverride.find("two")
expect(searched_id.id).to eq "two"
end
# TODO: Actually make this test grab the cache
it "prints out all IDs from cache" do
all_ids = MockClassOverride.all
expect(all_ids.size).to eq 3
expect(all_ids.last.id).to eq "three"
end
it "creates a translatable name (that does not exist in the code base) for a ranked enum model instance" do
mock = MockClassOverride.new("some-id", "some-rank")
expect(mock.name).to eq "Translation missing: en.mock_class_override.some-id"
end
end
end

View File

@@ -0,0 +1,52 @@
require "rails_helper"
describe Reaction do
describe "Validations" do
it { is_expected.to validate_presence_of(:value) }
it { is_expected.to validate_presence_of(:encrypted_user_id) }
end
let(:user) { create(:user) }
let(:other_user) { create(:user) }
context "#values_count_with_participated" do
it "should indicate counts and when the given user has already used the requested reaction" do
reaction = create(:reaction, encrypted_user_id: user.encrypted_id, value: ":smile:")
create(:reaction, encrypted_user_id: other_user.encrypted_id, value: ":smile:")
create(:reaction, encrypted_user_id: other_user.encrypted_id, value: ":smirk:")
expect(subject.class.values_count_with_participated(user.encrypted_id)).to match_array([
hash_including({
# A real reaction ID is only required/meaningful when the current user has reacted.
# Otherwise the value is meaningless.
id: reaction.id.to_s,
value: ":smile:",
count: 2,
participated: true
}),
hash_including({
# id is not relevant here because the user did not react
value: ":smirk:",
count: 1,
participated: false
})
])
end
it "should work with a filtered set" do
create(:reaction, encrypted_user_id: user.encrypted_id)
create(:reaction, encrypted_user_id: other_user.encrypted_id)
create(:reaction, encrypted_user_id: other_user.encrypted_id, value: ":smirk:")
filtered = Reaction.where(value: ":smirk:")
expect(filtered.values_count_with_participated(user.encrypted_id)).to match([
hash_including({
value: ":smirk:",
count: 1,
participated: false
})
])
end
end
end

View File

@@ -0,0 +1,78 @@
require "rails_helper"
RSpec.describe Registration do
subject { Registration.create!(params) }
let(:params) do
ActionController::Parameters.new(
registration: {
email: "user@example.com",
password: "secret123",
password_confirmation: "secret123",
screen_name: "user",
captcha_response: "dummy-captcha-response"
}
)
end
before { allow(Google::RecaptchaVerifier).to receive(:exec).and_return(true) }
context "with blank screen_name" do
before { params[:registration][:screen_name] = "" }
it "raises record invalid exception with proper error" do
expect { subject }.to raise_error do |e|
expect(e).to be_a(ActiveRecord::RecordInvalid)
expect(e.record.errors[:screen_name]).to eq ["can't be blank"]
end
end
end
context "with blank captcha_response" do
before { params[:registration][:captcha_response] = "" }
it "raises record invalid exception with proper error" do
expect { subject }.to raise_error do |e|
expect(e).to be_a(ActiveRecord::RecordInvalid)
expect(e.record.errors[:captcha_response]).to eq ["can't be blank"]
end
end
end
context "with invalid captcha_response" do
before { allow(Google::RecaptchaVerifier).to receive(:exec).and_return(false) }
it "raises record invalid exception with proper error" do
expect { subject }.to raise_error do |e|
expect(e).to be_a(ActiveRecord::RecordInvalid)
expect(e.record.errors[:captcha_response]).to eq ["verification failed or response expired"]
end
end
end
context "with blank email" do
before { params[:registration][:email] = "" }
it "raises record invalid exception with proper error" do
expect { subject }.to raise_error do |e|
expect(e).to be_a(ActiveRecord::RecordInvalid)
expect(e.record.errors[:email]).to eq ["can't be blank"]
end
end
end
context "with blank password" do
before { params[:registration][:password] = "" }
it "raises record invalid exception with proper error" do
expect { subject }.to raise_error do |e|
expect(e).to be_a(ActiveRecord::RecordInvalid)
expect(e.record.errors[:password]).to eq ["can't be blank"]
end
end
end
context "with all valid params" do
it "returns registration object wrapping new user created" do
user = subject.user
expect(user).to be_a User
expect(user.email).to eq params[:registration][:email]
expect(user.profile.screen_name).to eq params[:registration][:screen_name]
end
end
end

View File

@@ -0,0 +1,38 @@
require "rails_helper"
RSpec.describe Search::ForDose, type: :model do
let!(:checkins) { create_list(:checkin, 3) }
let!(:treatment) { create(:checkin_treatment, checkin: checkins[0], is_taken: true, value: "2 x 10 mg") }
let(:all_treatment_doses) { [treatment.value] + [other_dose_1.value, other_dose_2.value] }
let(:params) { {resource: "dose", query: {treatment_id: treatment.treatment_id, name: "2 x"}} }
let!(:other_dose_1) do
create(:checkin_treatment, checkin: checkins[1], is_taken: true, treatment_id: treatment.treatment_id)
end
let!(:other_dose_2) do
create(:checkin_treatment, checkin: checkins[2], is_taken: true, treatment_id: treatment.treatment_id)
end
subject { Search::ForDose.new(params) }
context "without treatment_id param" do
before { params[:query].delete(:treatment_id) }
it { is_expected.not_to be_valid }
end
context "without name param" do
before { params[:query].delete(:name) }
it "returns all doses for the requested treatment" do
returned_doses = subject.searchables.map(&:name)
expect(returned_doses.to_set).to eq all_treatment_doses.compact.to_set
end
end
context "with name param" do
it "returns matching doses for the requested treatment" do
returned_doses = subject.searchables.map(&:name)
expect(returned_doses).to include treatment.value
end
end
end

View File

@@ -0,0 +1,46 @@
require "rails_helper"
RSpec.describe Search, type: :model do
let(:user) { create(:user) }
let(:treatment) { create(:user_treatment, user: user).treatment }
let(:query) { {name: "terra"} }
before { treatment.update!(name: "Mediterranean Diet") }
subject { Search.new(resource: "treatment", query: query, user: user) }
context "success" do
context "when search text is more than 3 characters" do
it "returns string containing search text" do
returned_treatment_names = subject.searchables.map(&:name)
expect(returned_treatment_names).to include treatment.name
end
end
context "when search text is less than 3 characters" do
before { query[:name] = "me" }
it "returns string starting with search text" do
returned_treatment_names = subject.searchables.map(&:name)
expect(returned_treatment_names).to include treatment.name
end
end
end
context "failure" do
context "when search text is more than 3 characters" do
before { query[:name] = "teran" }
it "returns no results" do
expect(subject.searchables).to be_empty
end
end
context "when search text is less than 3 characters" do
before { query[:name] = "te" }
it "returns no results" do
expect(subject.searchables).to be_empty
end
end
end
end

View File

@@ -0,0 +1,18 @@
# == Schema Information
#
# Table name: symptoms
#
# id :integer not null, primary key
# global :boolean default(TRUE)
# created_at :datetime not null
# updated_at :datetime not null
# trackable_usages_count :integer default(0)
#
require "rails_helper"
RSpec.describe Symptom, type: :model do
describe "Respond to" do
it { is_expected.to respond_to(:name) }
end
end

View File

@@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: tags
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
require "rails_helper"
RSpec.describe Tag, type: :model do
describe "Respond to" do
it { is_expected.to respond_to(:name) }
end
end

View File

@@ -0,0 +1,7 @@
require "rails_helper"
describe TopicFollowing do
describe "Validations" do
it { is_expected.to validate_presence_of(:encrypted_user_id) }
end
end

View File

@@ -0,0 +1,47 @@
# == Schema Information
#
# Table name: trackable_usages
#
# id :integer not null, primary key
# user_id :integer
# trackable_id :integer
# trackable_type :string
# count :integer default(1)
# created_at :datetime not null
# updated_at :datetime not null
#
require "rails_helper"
RSpec.describe TrackableUsage, type: :model do
describe "Respond to" do
it { is_expected.to respond_to(:count) }
end
describe "Associations" do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:trackable) }
end
describe "Validations" do
it { is_expected.to validate_numericality_of(:count).is_greater_than(0) }
end
describe "Callbacks" do
before(:all) do
@condition = create(:condition, :personal)
create_list(:trackable_usage,
Flaredown.config.trackables_min_popularity - 1,
trackable_type: @condition.class.to_s,
trackable_id: @condition.id)
end
subject { TrackableUsage.last }
context "for small amount of tracks doesn't switch topic to global" do
before(:each) { subject.run_callbacks(:commit) }
it { expect(subject.trackable.reload.global?).to be false }
end
end
end

View File

@@ -0,0 +1,72 @@
# == Schema Information
#
# Table name: trackings
#
# id :integer not null, primary key
# user_id :integer
# trackable_id :integer
# trackable_type :string
# start_at :date
# end_at :date
# color_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
require "rails_helper"
RSpec.describe Tracking, type: :model do
describe "Associations" do
it { is_expected.to belong_to(:user) }
end
describe "Validations" do
it { is_expected.to validate_presence_of(:start_at) }
it { is_expected.to validate_presence_of(:user) }
it { is_expected.to validate_presence_of(:trackable) }
it { is_expected.to validate_inclusion_of(:trackable_type).in_array(%w[Condition Symptom Treatment]) }
context "without foreign key checks" do
subject { create :tracking, :for_condition, :active }
before { disable_foreign_key_checks("trackings") }
after { enable_foreign_key_checks("trackings") }
it do
is_expected.to(
validate_uniqueness_of(:user_id)
.scoped_to([:trackable_id, :trackable_type, :start_at])
.with_message("is already tracking this trackable")
)
end
end
end
describe "ensure_color_id" do
context "when have a parent" do
let(:parent) { create(:tracking, :for_condition, :inactive) }
subject { create(:tracking, :active, trackable: parent.trackable, user: parent.user) }
it "has the same color previous Tracking" do
expect(subject.color_id).to be_equal(parent.color_id)
end
end
context "when have a nil color" do
subject { create(:tracking, :active, :for_condition) }
it "has the random color" do
expect(subject.color_id).to be_present
end
end
context "when have a color" do
subject { create(:tracking, :active, :for_condition, color_id: 10) }
it "has the assigned color" do
expect(subject.color_id).to be_equal(10)
end
end
end
end

View File

@@ -0,0 +1,18 @@
# == Schema Information
#
# Table name: treatments
#
# id :integer not null, primary key
# global :boolean default(TRUE)
# created_at :datetime not null
# updated_at :datetime not null
# trackable_usages_count :integer default(0)
#
require "rails_helper"
RSpec.describe Treatment, type: :model do
describe "Respond to" do
it { is_expected.to respond_to(:name) }
end
end

View File

@@ -0,0 +1,19 @@
# == Schema Information
#
# Table name: user_conditions
#
# id :integer not null, primary key
# user_id :integer
# condition_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
require "rails_helper"
RSpec.describe UserCondition do
describe "Associations" do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:condition) }
end
end

View File

@@ -0,0 +1,71 @@
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string default(""), not null
# encrypted_password :string default(""), not null
# reset_password_token :string
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string
# last_sign_in_ip :string
# authentication_token :string not null
# invitation_token :string
# invitation_created_at :datetime
# invitation_sent_at :datetime
# invitation_accepted_at :datetime
# invitation_limit :integer
# invited_by_id :integer
# invited_by_type :string
# created_at :datetime not null
# updated_at :datetime not null
#
require "rails_helper"
RSpec.describe User do
describe "Associations" do
it { is_expected.to have_one(:profile) }
it { is_expected.to have_many(:conditions).through(:user_conditions) }
it { is_expected.to have_many(:symptoms).through(:user_symptoms) }
end
describe "Validations" do
it { is_expected.to validate_presence_of(:email) }
it { is_expected.to validate_presence_of(:password) }
end
describe "Callbacks" do
subject { create(:user) }
context "before_create" do
it "generates authentication token" do
expect(subject.reload.authentication_token).to be_present
end
end
context "after_create" do
it "creates profile" do
profile = subject.reload.profile
expect(profile).to be_present
expect(profile.id).to be_present
expect(profile.user.id).to eq subject.id
expect(profile.onboarding_step_id).to eq "onboarding-personal"
end
end
end
describe "#last_checkin" do
it "sees most recent checkin as more recent than less recent checkin when they are on the same day" do
date = "2020-01-02"
user = create(:user)
create(:checkin, date: Date.parse(date) - 5.days, user_id: user.id)
last = create(:checkin, date: Date.parse(date) + 2.hours, user_id: user.id)
create(:checkin, date: Date.parse(date), user_id: user.id)
create(:checkin, date: Date.parse(date) + 1.hour, user_id: user.id)
expect(user.last_checkin).to eq(last)
end
end
end

View File

@@ -0,0 +1,19 @@
# == Schema Information
#
# Table name: user_symptoms
#
# id :integer not null, primary key
# user_id :integer
# symptom_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
require "rails_helper"
RSpec.describe UserSymptom, type: :model do
describe "Associations" do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:symptom) }
end
end

View File

@@ -0,0 +1,19 @@
# == Schema Information
#
# Table name: user_treatments
#
# id :integer not null, primary key
# user_id :integer
# treatment_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
require "rails_helper"
RSpec.describe UserTreatment, type: :model do
describe "Associations" do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:treatment) }
end
end

View File

@@ -0,0 +1,7 @@
require "rails_helper"
describe Weather do
describe "Validations" do
it { is_expected.to validate_uniqueness_of(:date).scoped_to(:position_id) }
end
end

View File

@@ -0,0 +1,22 @@
require "spec_helper"
RSpec.configure do |config|
config.include Mongoid::Matchers, type: :mongoid_model
if Bullet.enable?
config.before(:each) do
Bullet.start_request
end
config.after(:each) do
Bullet.perform_out_of_channel_notifications if Bullet.notification?
Bullet.end_request
end
end
end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end

View File

@@ -0,0 +1,45 @@
require "rails_helper"
RSpec.describe ChartsPattern do
it "instantiates a ChartPattern instance" do
user = create(:user)
pattern = create(:pattern, encrypted_user_id: user.encrypted_id)
chart_pattern = ChartsPattern.new({start_at: pattern.start_at, end_at: pattern.end_at, pattern: pattern})
expect(chart_pattern.pattern.id).to eq pattern.id
end
it "generates chart data from a ChartPattern" do
user = create(:user)
pattern = create(:pattern, encrypted_user_id: user.encrypted_id)
chart_pattern = ChartsPattern.new({start_at: pattern.start_at, end_at: pattern.end_at, pattern: pattern})
chart_data = chart_pattern.chart_data
expect(chart_data[:pattern_name]).to eq pattern.name
expect(chart_data[:author_email]).to eq user.email
end
it "generates chart data from a ChartPattern with a valid category" do
user = create(:user)
pattern = create(:pattern, encrypted_user_id: user.encrypted_id, includes: [{category: "treatments"}])
chart_pattern = ChartsPattern.new({start_at: pattern.start_at, end_at: pattern.end_at, pattern: pattern})
chart_data = chart_pattern.chart_data
expect(chart_data[:pattern_name]).to eq pattern.name
expect(chart_data[:author_email]).to eq user.email
end
it "generates chart data from a ChartPattern with untracked category" do
user = create(:user)
pattern = create(:pattern, encrypted_user_id: user.encrypted_id, includes: [{category: "not-a-category"}])
chart_pattern = ChartsPattern.new({start_at: pattern.start_at, end_at: pattern.end_at, pattern: pattern})
chart_data = chart_pattern.chart_data
expect(chart_data[:pattern_name]).to eq pattern.name
expect(chart_data[:author_email]).to eq user.email
end
end

View File

@@ -0,0 +1,127 @@
require "rails_helper"
RSpec.describe Checkin::Creator do
let!(:user) { create(:user) }
let!(:condition_tracking) { create(:tracking, :active, :for_condition, user: user) }
let!(:condition) { condition_tracking.trackable }
let!(:symptom_tracking) { create(:tracking, :active, :for_symptom, user: user) }
let!(:symptom) { symptom_tracking.trackable }
let!(:treatment_tracking) { create(:tracking, :active, :for_treatment, user: user) }
let!(:treatment) { treatment_tracking.trackable }
let!(:date) { Time.zone.today }
subject { Checkin::Creator.new(user.id, date).create! }
describe "create" do
it "returns a new checkin prefilled with active trackables" do
expect(subject.id).to be_present
expect(subject.user_id).to eq user.id
expect(subject.date).to eq date
# Condition
checkin_condition = subject.conditions[0]
expect(checkin_condition.condition_id).to eq condition.id
expect(checkin_condition.color_id).to eq condition_tracking.color_id.to_s
expect(checkin_condition.position).to eq 0
# Symptom
checkin_symptom = subject.symptoms[0]
expect(checkin_symptom.symptom_id).to eq symptom.id
expect(checkin_symptom.color_id).to eq symptom_tracking.color_id.to_s
expect(checkin_symptom.position).to eq 0
# Treatment
checkin_treatment = subject.treatments[0]
expect(checkin_treatment.treatment_id).to eq treatment.id
expect(checkin_treatment.color_id).to eq treatment_tracking.color_id.to_s
expect(checkin_treatment.position).to eq 0
expect(checkin_treatment.is_taken).to be false
end
context "when recent dose exists for treatment in user's profile" do
before do
user.profile.set_most_recent_dose(treatment.id, "20 mg")
user.profile.save!
end
it "sets dose from profile on the new checkin" do
checkin_treatment = subject.treatments[0]
expect(checkin_treatment.treatment_id).to eq treatment.id
saved_dose = user.profile.most_recent_dose_for(treatment.id)
expect(checkin_treatment.value).to eq saved_dose
end
end
context "when recent position exists for a trackable in user's profile" do
before do
user.profile.set_most_recent_trackable_position(condition, 5)
user.profile.save!
end
it "sets trackable position from profile on the new checkin" do
checkin_condition = subject.conditions[0]
expect(checkin_condition.condition_id).to eq condition.id
saved_position = user.profile.most_recent_trackable_position_for(condition)
expect(checkin_condition.position).to eq saved_position
end
end
context "when no recent position exists for a trackable in user's profile" do
before { create(:tracking, :active, :for_condition, user: user) }
it "sets positions with auto-increment counter starting by 1" do
positions = subject.conditions.map(&:position)
expect(positions.to_set).to eq [0, 1].to_set
end
end
context "when trackables never used before" do
it "creates new usage records" do
# For Condition
expect(subject.conditions).to be_present
condition_usage = TrackableUsage.find_by(user: user, trackable: condition)
expect(condition_usage).to be_present
expect(condition_usage.count).to eq 1
# For Symptom
expect(subject.symptoms).to be_present
symptom_usage = TrackableUsage.find_by(user: user, trackable: symptom)
expect(symptom_usage).to be_present
expect(symptom_usage.count).to eq 1
# For Treatment
expect(subject.treatments).to be_present
treatment_usage = TrackableUsage.find_by(user: user, trackable: treatment)
expect(treatment_usage).to be_present
expect(treatment_usage.count).to eq 1
end
end
context "when trackables already used before" do
let!(:condition_usage) { TrackableUsage.create!(user: user, trackable: condition) }
let!(:condition_usage_count) { condition_usage.count }
let!(:symptom_usage) { TrackableUsage.create!(user: user, trackable: symptom) }
let!(:symptom_usage_count) { symptom_usage.count }
let!(:treatment_usage) { TrackableUsage.create!(user: user, trackable: treatment) }
let!(:treatment_usage_count) { treatment_usage.count }
it "increments count on usage records" do
# For Condition
expect(subject.conditions).to be_present
expect(condition_usage.reload.count).to eq(condition_usage_count + 1)
# For Symptom
expect(subject.symptoms).to be_present
expect(symptom_usage.reload.count).to eq(symptom_usage_count + 1)
# For Treatment
expect(subject.treatments).to be_present
expect(treatment_usage.reload.count).to eq(treatment_usage_count + 1)
end
end
context "when postal code is set on previous checkin" do
let(:weather) { create :weather }
let(:postal_code) { "55403" }
let(:position) { Position.create(postal_code: postal_code) }
let!(:previous_checkin) { create :checkin, user_id: user.id, position_id: position.id }
before { expect(WeatherRetriever).to receive(:get).and_return(weather) }
it "should ask for weather" do
expect(subject.position.postal_code).to eq(postal_code)
expect(subject.weather_id).to eq(weather.id)
end
end
end
end

View File

@@ -0,0 +1,207 @@
require "rails_helper"
RSpec.describe Checkin::Updater do
let(:user) { create(:user) }
let(:checkin) { create(:checkin, user_id: user.id, date: Time.zone.today) }
subject { Checkin::Updater.new(user, params).update! }
context "with permitted params" do
let(:params) { ActionController::Parameters.new(id: checkin.id.to_s, checkin: {note: "Blah"}) }
it "returns updated checkin" do
expect(subject.id).to eq checkin.id
expect(subject.note).to eq params[:checkin][:note]
end
end
context "with non-permitted params" do
let(:params) { ActionController::Parameters.new(id: checkin.id.to_s, checkin: {date: Date.yesterday}) }
it "returns checkin with no changes" do
expect(subject.id).to eq checkin.id
expect(subject.date).not_to eq params[:checkin][:date]
end
end
context "when recent dose exists for treatment in user's profile" do
let(:treatment) { create(:treatment) }
let(:params) do
ActionController::Parameters.new(
id: checkin.id.to_s,
checkin: {treatments_attributes: [{treatment_id: treatment.id}]}
)
end
before do
user.profile.set_most_recent_dose(treatment.id, "20 mg")
user.profile.save!
end
it "auto-sets the most recently used dose on added treatments" do
returned_treatment = subject.treatments[0]
expect(returned_treatment.treatment_id).to eq treatment.id
saved_dose = user.profile.most_recent_dose_for(treatment.id)
expect(returned_treatment.value).to eq saved_dose
end
end
context "trackable usages" do
context "when removing a trackable" do
let!(:checkin_condition) { create(:checkin_condition, checkin: checkin) }
let!(:condition) { Condition.find(checkin_condition.condition_id) }
let!(:usage) { create(:trackable_usage, user: user, trackable: condition) }
let(:params) do
ActionController::Parameters.new(
id: checkin.id.to_s,
checkin: {
conditions_attributes: [{
id: checkin_condition.id.to_s,
condition_id: checkin_condition.condition_id,
_destroy: "1"
}]
}
)
end
context "used once before" do
it "removes trackable and usage record" do
expect(subject.conditions.map(&:id)).not_to include checkin_condition.id
expect(TrackableUsage.find_by(user: user, trackable: condition)).to be_nil
end
end
context "used more than once before" do
let!(:previous_count) { usage.count }
before { usage.increment! :count }
it "removes trackable and decrements count on usage record" do
expect(subject.conditions.map(&:id)).not_to include checkin_condition.id
expect(usage.count).to eq(previous_count + 1)
end
end
end
context "when adding a trackable" do
let!(:condition) { create(:condition) }
let(:params) do
ActionController::Parameters.new(
id: checkin.id.to_s,
checkin: {
conditions_attributes: [{
condition_id: condition.id
}]
}
)
end
context "never used before" do
it "adds trackable and creates a new usage record" do
expect(subject.conditions.map(&:condition_id)).to include condition.id
expect(TrackableUsage.find_by(user: user, trackable: condition)).to be_present
end
end
context "already used before" do
let!(:usage) { TrackableUsage.find_or_create_by(user: user, trackable: condition) }
let!(:previous_count) { usage.count }
it "adds trackable and increments count on usage record" do
expect(subject.conditions.map(&:condition_id)).to include condition.id
expect(usage.reload.count).to eq(previous_count + 1)
end
end
end
end
context "trackables positions" do
let(:n) { 5 }
let(:trackables) do
result = []
n.times do |i|
result << create(:checkin_condition, checkin: checkin, position: i)
end
result
end
let(:trackables_attrs) do
trackables.map do |t|
{
id: t.id.to_s,
condition_id: t.condition_id,
position: t.position
}
end
end
context "when adding a trackable and client didn't pass position" do
let(:condition) { create(:condition) }
let(:params) do
ActionController::Parameters.new(
id: checkin.id.to_s,
checkin: {
conditions_attributes: trackables_attrs + [{condition_id: condition.id}]
}
)
end
it "auto-sets position to last" do
added_trackable = subject.conditions.find_by(condition_id: condition.id)
expect(added_trackable.position).to eq n
end
end
context "when removing a trackable" do
let(:params) do
ActionController::Parameters.new(
id: checkin.id.to_s,
checkin: {
conditions_attributes: trackables_attrs
}
)
end
let(:pos) { 1 }
before do
trackable_to_remove = params[:checkin][:conditions_attributes].find { |a| a[:position].eql? pos }
trackable_to_remove[:_destroy] = "1"
end
it "updates positions of removed trackable's successors" do
successors_attrs = params[:checkin][:conditions_attributes].select { |a| a[:position] > pos }
successors_attrs.each do |successor_attrs|
successor = subject.conditions.find(successor_attrs[:id])
expect(successor.position).to eq successor_attrs[:position] - 1
end
end
end
context "when reordering trackables" do
let(:params) do
ActionController::Parameters.new(
id: checkin.id.to_s,
checkin: {
conditions_attributes: trackables_attrs
}
)
end
before do
# swap first and last trackable's positions
attrs = params[:checkin][:conditions_attributes]
attrs[0][:position] = attrs[trackables_attrs.length - 1][:position]
end
context "on today's checkin" do
it "updates trackables positions in checkin and saves them in profile" do
params[:checkin][:conditions_attributes].each do |condition_attr|
checkin_condition = subject.conditions.find(condition_attr[:id])
expect(checkin_condition.position).to eq condition_attr[:position]
condition = Condition.find(condition_attr[:condition_id])
saved_position = user.profile.most_recent_trackable_position_for(condition)
expect(saved_position).to eq condition_attr[:position]
end
end
end
context "on a past checkin" do
let(:checkin) { create(:checkin, user_id: user.id, date: Time.zone.today - 1.day) }
it "updates trackables positions in checkin but doesn't save them in profile" do
params[:checkin][:conditions_attributes].each do |condition_attr|
checkin_condition = subject.conditions.find(condition_attr[:id])
expect(checkin_condition.position).to eq condition_attr[:position]
condition = Condition.find(condition_attr[:condition_id])
saved_position = user.profile.most_recent_trackable_position_for(condition)
expect(saved_position).to eq nil
end
end
end
end
end
end

View File

@@ -0,0 +1,91 @@
require "rails_helper"
MODELS = [Food, Tag].freeze
def occurrences_for(object_id, ids_key)
Checkin.where(ids_key => {"$elemMatch" => {"$eq" => object_id}}).count
end
describe CollectionRetriever do
let(:retrieved_objects) { subject.retrieve }
MODELS.each do |model|
model_name = model.name
model_slug = model_name.underscore
ids_key = "#{model_slug}_ids"
all_objects_are_model = "all objects are #{model_name}"
context model_name do
shared_examples all_objects_are_model do
it { expect(subject.retrieve.map(&:class).uniq.map(&:name)).to eq([model_name]) }
end
describe "most_popular" do
let(:objects) { create_list(model_slug, 20) }
let(:object_ids) { objects.map(&:id) }
before do
5.times do
create(:checkin, ids_key => object_ids.sample(5))
end
end
subject { described_class.new(model, :most_popular) }
it_behaves_like all_objects_are_model
it "retrieves the most popular" do
popular_object_ids = retrieved_objects.map(&:id)
non_popular_object_ids = object_ids - popular_object_ids
min_occurrence = subject.occurrences.to_a.last["count"]
non_popular_object_ids.each do |object_id|
expect(occurrences_for(object_id, ids_key)).to be <= min_occurrence
end
end
it "limits results to 10" do
expect(retrieved_objects.count).to eq 10
end
it "makes occurrences counts available after retrieve" do
subject.retrieve
max_occurrence = subject.occurrences.to_a.first["count"]
min_occurrence = subject.occurrences.to_a.last["count"]
expect(min_occurrence).to be < max_occurrence
subject.occurrences.each do |o|
expected_count = occurrences_for(o["_id"], ids_key)
expect(o["count"]).to eq expected_count
end
end
end
describe "most_recent" do
let(:user) { create(:user) }
let(:objects) { create_list(model_slug, 20) }
let(:object_ids) { objects.map(&:id) }
before do
today = Time.zone.today
5.times do |i|
create(
:checkin,
:user_id => user.id,
:date => today + i.days,
ids_key => [object_ids[i], object_ids[i + 5]]
)
end
end
subject { described_class.new(model, :most_recent, user) }
it_behaves_like all_objects_are_model
it "retrieves the most recent objects for the given user" do
retrieved_object_ids = retrieved_objects.map(&:id)
expect(retrieved_object_ids.to_set).to eq object_ids.slice(0..9).to_set
expect(retrieved_object_ids).not_to include object_ids.slice(10..19)
end
end
end
end
end

View File

@@ -0,0 +1,19 @@
require "rails_helper"
RSpec.describe Google::RecaptchaVerifier, :vcr do
subject { Google::RecaptchaVerifier.exec(recaptcha_response) }
context "given a non-expired ReCaptcha response" do
let(:recaptcha_response) { "non-expired-recaptcha-response-dummy-string" }
it "returns true" do
is_expected.to be true
end
end
context "given an expired ReCaptcha response" do
let(:recaptcha_response) { "expired-recaptcha-response-dummy-string" }
it "returns false" do
is_expected.to be false
end
end
end

View File

@@ -0,0 +1,32 @@
require "rails_helper"
RSpec.describe TrackableCreator do
context "for Condition" do
let!(:user) { create(:user) }
let!(:condition_name) { "coding addiction" }
let!(:trackable) { Condition.new(name: condition_name, global: false) }
subject { TrackableCreator.new(trackable, user).create! }
context "when no same condition exists" do
it "creates new non-global condition and associates to user" do
expect(subject.global?).to be false
expect(UserCondition.find_by(user_id: user.id, condition_id: subject.id)).to be_present
end
end
context "when global same condition exists" do
let!(:same_condition) { create(:condition, name: condition_name.titleize) }
it "returns existing condition" do
expect(subject.id).to eq same_condition.id
end
end
context "when non-global same condition exists" do
let!(:same_condition) { create(:user_condition).condition }
before { same_condition.update!(name: condition_name.titleize) }
it "returns existing condition and associates it to user" do
expect(subject.id).to eq same_condition.id
expect(UserCondition.find_by(user_id: user.id, condition_id: same_condition.id)).to be_present
end
end
end
end

View File

@@ -0,0 +1,30 @@
require "rails_helper"
describe WeatherRetriever, :vcr do
let(:date) { Date.parse "2016-01-06" }
let(:cassete) { "#{described_class.name}/#{postal_code}" }
let(:postal_code) { "55403" }
let(:perform) do
VCR.use_cassette cassete do
described_class.get(date, postal_code)
end
end
context "no weather cached" do
it { expect(perform).to be_a(Weather) }
it { expect { perform }.to change { Weather.count }.by(1) }
end
context "the weather is already cached" do
let(:position) { Position.create(postal_code: postal_code) }
let!(:weather) { create :weather, date: date, position_id: position.id }
before { expect(Weather).not_to receive(:create) }
before { expect(Geocoder).not_to receive(:search) }
before { expect(Tomorrowiorb).not_to receive(:forecast) }
it { expect(perform).to eq(weather) }
it { expect { perform }.not_to change { Weather.count } }
end
end

View File

@@ -0,0 +1,43 @@
require "simplecov"
SimpleCov.start
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= "test"
require File.expand_path("../../config/environment", __FILE__)
require "rspec/rails"
require "webmock/rspec"
WebMock.disable_net_connect!(allow_localhost: true)
Geocoder.configure(lookup: :test, ip_lookup: :test)
minneapolis_geo = {
# match the WeatherRetriever vcr stub
"coordinates" => [44.967486, -93.2897678],
"address" => "Minneapolis, Minnesota, USA",
"state" => "Minnesota",
"state_code" => "MN",
"country" => "United States",
"country_code" => "US",
"postal_code" => "55403"
}
Geocoder::Lookup::Test.set_default_stub([minneapolis_geo])
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.expect_with :rspec
config.mock_with :rspec
config.include Devise::Test::ControllerHelpers, type: :controller
config.infer_spec_type_from_file_location!
config.before(:suite) do
# TestEnv.init
end
end
ActiveRecord::Migration.maintain_test_schema!

Some files were not shown because too many files have changed in this diff Show More