-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Factory girl #25
base: main
Are you sure you want to change the base?
Factory girl #25
Changes from 4 commits
38f895e
7343b58
37d6b10
c3e0095
847f5b3
4117ffb
0bf74f6
4bd48ab
4019c6e
4a0efab
a2f7881
cfcc469
5c23318
e989528
47f0343
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,4 +39,5 @@ group :development, :test do | |
gem 'capybara' | ||
gem 'launchy' | ||
gem 'rspec-rails' | ||
gem 'factory_girl_rails' | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
FactoryGirl.define do | ||
factory :user do | ||
provider "google_oauth2" | ||
sequence :uid do |n| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you write this using a more compact single-line block instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
n | ||
end | ||
sequence :name do |n| | ||
"Fake User#{n}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please indent with two spaces. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
end | ||
approval_at "2017-02-25 23:28:13" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From my experience with Factory Girl, the less you do in the main factory, the better. My rule of thumb is to only define attributes that are required (by a validation, for example). So if needed, we could add an approved_user factory, but I would take this line out here. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes perfect sense! Default approval status removed 😄 |
||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,72 @@ | ||
feature "User management" do | ||
feature "user management" do | ||
let(:users_index_path) { polymorphic_path([:users]) } | ||
|
||
context "when an admin user visits the users index" do | ||
let!(:admin_user) { login_new_admin_user } | ||
subject { admin_user } | ||
context "when an admin visits the users index" do | ||
let!(:admin) { login_new_admin_user } | ||
let!(:users) { create_list(:user, 2) } | ||
let!(:unapproved_user) { create(:user, approval_at: nil)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a space after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
before { visit users_index_path } | ||
|
||
it "displays a table of users" do | ||
expect(page).to have_table("users_table") | ||
end | ||
|
||
it "fills the table with the right headers and rows" do | ||
check_headers_and_values_on_generic_index_page( | ||
"users_table", { | ||
"Name" => "Example User", | ||
"Created At" => subject.created_at_string, | ||
"Approval At" => subject.approval_at_string, | ||
"Admin" => "true", | ||
"Actions" => "Remove Approval Delete", | ||
} | ||
) | ||
it "sees a table with proper headers and rows" do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we are describing a feature here ("user management"), I would make sure "it" refers to the feature and not to the user. So instead of "it (the user) sees a table..." I would say "it (the feature) displays/renders/produces/shows a table..." What do you think? I'm open to your way but in either case think we should be consistent throughout the specs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with consistency. I was reading the "it" as referring to the subject of the context block, but I'm happy to have it refer to the feature. I appreciate you pointing out all of these stylistic things. I need to pickier with my code, for sure! |
||
expect(page).to have_css("#user_#{admin.id}", :text => "#{admin.name}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use newer hash syntax instead of hash rockets: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
expect(page).to have_css("#user_#{admin.id}", :text => "#{admin.created_at_string}") | ||
expect(page).to have_css("#user_#{admin.id}", :text => "#{admin.approval_at_string}") | ||
expect(page).to have_css("#user_#{admin.id}", :text => "Delete") | ||
expect(page).to have_css("#user_#{admin.id}", :text => "Yes") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah... that check_headers_and_values_on_generic_index_page method was a bit of a mouthful, thanks for taking it on! 😆 I still think this would be more readable and precise if we could write something like "expect the row for X to have the value Y in the column for Z". Checking the contents of tables is something we're likely to do quite often. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I think I found a simple solution to this issue. It's not as robust as your original solution, but I could not get your solution to work despite my best efforts. My new solution checks the order of the data in the table, as you requested. The only downside is that the test would break if the order of the table is ever changed. This may be worth further investigation depending on the likelihood of table columns being changed in the future. |
||
expect(page).to_not have_css("#user_#{admin.id}", :text => "No") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find this brittle because it could fail in November if we start displaying the dates differently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you decide to change the format of the dates, then that'll probably take place inside of the model methods, as it is right now (e.g. User.approval_at_string). The test is matching what's on the DOM with the logic in the model. I think it's sound unless you're manipulating the date format somewhere else. |
||
end | ||
|
||
context "and a new non-admin user is added" do | ||
subject! { User.create!(name: "Joe") } | ||
|
||
before { visit users_index_path } | ||
it "sees a table with proper headers and rows" do | ||
expect(page).to have_css("#user_#{users.first.id}", :text => "#{users.first.name}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no reason to use interpolation when you want to use the whole string ("#{x}" == x) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, you're absolutely right. |
||
expect(page).to have_css("#user_#{users.first.id}", :text => "#{users.first.created_at_string}") | ||
expect(page).to have_css("#user_#{users.first.id}", :text => "#{users.first.approval_at_string}") | ||
expect(page).to have_link('Yes', :href => remove_approval_user_path(users.first.id)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm hoping we can be consistent with our choice of single quotes vs. double quotes. I'm thinking of establishing a project convention of double quotes by default. Do you have an argument for one way or the other? https://github.com/bbatsov/ruby-style-guide#consistent-string-literals There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with double by default due to the somewhat frequent need for string interpolation. I fixed this random use of single quote. Good catch! |
||
expect(page).to_not have_link('No', :href => approve_user_path(users.first.id)) | ||
expect(page).to have_link('No', :href => toggle_admin_user_path(users.first.id)) | ||
expect(page).to_not have_link('Yes', :href => toggle_admin_user_path(users.first.id)) | ||
end | ||
|
||
it "fills the table with that user\"s information too" do | ||
check_headers_and_values_on_generic_index_page( | ||
"users_table", { | ||
"Name" => "Joe", | ||
"Created At" => subject.created_at_string, | ||
"Approval At" => "", | ||
"Admin" => "", | ||
"Actions" => "Approve Delete", | ||
} | ||
) | ||
context "the admin clicks Yes for user approval" do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By convention, begin context descriptions with "when" (https://github.com/reachlocal/rspec-style-guide#context-descriptions). I also use "with" in certain cases, as encouraged by betterspecs and I use "and" for nested contexts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool. Thanks for pointing that out! |
||
before do | ||
find(:xpath, "//a[@href='/users/#{unapproved_user.id}/approve']").click | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer to avoid using xpaths, because I find them brittle and not very readable. At the very least I would use a url helper here instead of interpolating the user id into a hardcoded path (check out how the link is produced in the view code). What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. Since you already had a dynamic button class for the admin approval button, I went ahead and did the exact same thing for the user approval button. This allows me to find by the button class rather than using XPath. |
||
end | ||
|
||
context "and the current user clicks the approve link for that user" do | ||
before do | ||
within(:row_for, subject) do | ||
click_link "Approve" | ||
end | ||
end | ||
it "approves the user" do | ||
expect(unapproved_user.reload).to be_approved | ||
end | ||
|
||
it "approves the user" do | ||
expect(subject.reload).to be_approved | ||
end | ||
it "displays an approval time" do | ||
expect(page).to have_content(unapproved_user.approval_at_string) | ||
end | ||
|
||
it "displays an approval time" do | ||
within(:row_for, subject) do | ||
expect(find(:value_under_header, "Approval At").text).to_not be_blank | ||
end | ||
end | ||
it "no longer shows the approve link" do | ||
expect(page).to have_link('Yes', :href => remove_approval_user_path(unapproved_user)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not testing what the description says it is. Could you either update the description or change the test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. I think I was slightly confused by clicking 'No' to approve a user. |
||
end | ||
|
||
it "no longer shows the approve link" do | ||
within(:row_for, subject) do | ||
expect(find(:value_under_header, "Actions").text).to eq "Remove Approval Delete" | ||
end | ||
context "and the admin clicks No for user approval for same user" do | ||
before do | ||
find(:xpath, "//a[@href='/users/#{unapproved_user.id}/remove_approval']").click | ||
end | ||
|
||
context "and the current user clicks the Remove Approval link for that user" do | ||
before do | ||
within(:row_for, subject) do | ||
click_link "Remove Approval" | ||
end | ||
end | ||
|
||
it "removes the user's approval" do | ||
expect(subject.reload).to_not be_approved | ||
end | ||
it "removes the user's approval" do | ||
expect(unapproved_user.reload).to_not be_approved | ||
end | ||
end | ||
|
||
context "and the current user clicks the delete link for that user" do | ||
context "and the admin clicks the delete link for same user" do | ||
before do | ||
within(:row_for, subject) do | ||
within(:css, "#user_#{unapproved_user.id}") do | ||
click_link "Delete" | ||
end | ||
end | ||
|
||
it "deletes the user" do | ||
expect(User.find_by_id(subject.id)).to be_nil | ||
expect(User.find_by_id(unapproved_user.id)).to be_nil | ||
end | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FactoryGirl.define do | ||
# <factories for each model go here> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can get rid of this file since we are creating separate files for each model, don't you? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, good call! |
||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
RSpec.configure do |config| | ||
config.include FactoryGirl::Syntax::Methods | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
module FeatureHelpers | ||
def login_new_user(options = {}) | ||
visit "/" | ||
click_link "Sign in" | ||
within(:css, ".super-button") do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for fixing the specs: I really shouldn't have pushed my last update without running them. Do you practice TDD? I'd like to make it the convention for this project. CSS is the default selector for Capybara, so you can leave it out in cases like this: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No problem! It was a good way to get familiar with the code base! I do practice TDD, so I'll certainly use it if I add any new features. Good catch. I'm not sure why I put that in there 😕 |
||
click_link "Sign in or sign up" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please indent with two spaces There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
end | ||
user = User.last | ||
user.admin = options[:admin] || false | ||
user.approval_at = options[:approval_at] || Time.now | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💃 👍