Files
grecia/spec/system/proposal_notifications_spec.rb
Javi Martín d8f1c462de Try to avoid PG::ProtocolViolation error in tests
While running our test suite, we were getting an exception sometimes:

```
Proposal Notifications In-app notifications from the proposal's author Followers should receive a notification
   Failure/Error: notification_for_user2 = Notification.find_by(user: user2)
      ActiveRecord::StatementInvalid:
        PG::ProtocolViolation: ERROR:  bind message supplies 0 parameters, but prepared statement "" requires 2
        : SELECT  "notifications".* FROM "notifications" WHERE "notifications"."user_id" = $1 LIMIT $2
   # ./spec/system/proposal_notifications_spec.rb:268
```

Sometimes we were getting a similar exception in a different test:

```
Commenting legislation questions Merged comment threads Reply on a multiple annotation thread and display it in the single annotation thread
And sometimes we were getting a different one:
   Failure/Error: annotation.comments.roots.sort_by_most_voted.limit(Legislation::Annotation::COMMENTS_PAGE_SIZE).each do |comment|
     ActionView::Template::Error:
       PG::ProtocolViolation: ERROR:  bind message supplies 0 parameters, but prepared statement "" requires 3
```

My best (wild) guess is these exceptions might take place because the
test is accessing the database and at the same time the browser
(chromedriver) process is accessing the database, with code like:

```
 find(".icon-notification").click
 notification_for_user2 = Notification.find_by(user: user2)
```

Or:

```
first(:css, ".annotator-hl").click
(...)
comment = annotation1.comments.first
click_link "Reply"
```

This behavior happened sometimes while using transactional fixtures and
a shared database connection with feature specs (before system specs
were introduced in Rails 5.1) when some queries were triggered from the
test after the browser process was started.

So we're avoiding the situation by writing the tests from the user's
point of view. This is just an attempt at fixing the issue; I don't know
whether these changes will fix it since I've only seen this exception on
Github Actions (never on my machine). Worst case scenario, we're still
improving the tests legibililty.
2021-01-22 12:31:48 +01:00

418 lines
13 KiB
Ruby

require "rails_helper"
describe "Proposal Notifications" do
scenario "Send a notification" do
author = create(:user, :with_proposal)
login_as(author)
visit root_path
click_link "My content"
click_link "Dashboard"
within("#side_menu") do
click_link "Message to users"
end
click_link "Send message to proposal followers"
fill_in "proposal_notification_title", with: "Thank you for supporting my proposal"
fill_in "proposal_notification_body", with: "Please share it with "\
"others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
expect(page).to have_content "Thank you for supporting my proposal"
expect(page).to have_content "Please share it with others so we can make it happen!"
end
scenario "Send a notification (Active voter)" do
proposal = create(:proposal)
create(:user, :level_two, votables: [proposal], followables: [proposal])
create_proposal_notification(proposal)
expect(Notification.count).to eq(1)
end
scenario "Send a notification (Follower)" do
proposal = create(:proposal)
create(:user, :level_two, followables: [proposal])
create_proposal_notification(proposal)
expect(Notification.count).to eq(1)
end
scenario "Send a notification (Follower and Voter)" do
proposal = create(:proposal)
create(:user, followables: [proposal], votables: [proposal])
create(:user, followables: [proposal])
create_proposal_notification(proposal)
expect(Notification.count).to eq(2)
end
scenario "Send a notification (Blocked voter)" do
proposal = create(:proposal)
voter = create(:user, :level_two, votables: [proposal])
voter.block
create_proposal_notification(proposal)
expect(Notification.count).to eq(0)
end
scenario "Send a notification (Erased voter)" do
proposal = create(:proposal)
voter = create(:user, :level_two, votables: [proposal])
voter.erase
create_proposal_notification(proposal)
expect(Notification.count).to eq(0)
end
scenario "Show notifications" do
proposal = create(:proposal)
_notification1 = create(:proposal_notification,
proposal: proposal, title: "Hey guys",
body: "Just wanted to let you know that...")
_notification2 = create(:proposal_notification,
proposal: proposal, title: "Another update",
body: "We are almost there please share with your peoples!")
visit proposal_path(proposal)
expect(page).to have_content "Hey guys"
expect(page).to have_content "Just wanted to let you know that..."
expect(page).to have_content "Another update"
expect(page).to have_content "We are almost there please share with your peoples!"
end
scenario "Message about receivers (Followers)" do
author = create(:user)
proposal = create(:proposal, author: author)
7.times { create(:follow, :followed_proposal, followable: proposal) }
login_as(author)
visit new_proposal_notification_path(proposal_id: proposal.id)
expect(page).to have_content "This message will be sent to 7 people and it will "\
"be visible in the proposal's page"
expect(page).to have_link("the proposal's page", href: proposal_path(proposal,
anchor: "comments"))
end
scenario "Message about receivers (Disctinct Followers and Voters)" do
author = create(:user)
proposal = create(:proposal, author: author)
7.times { create(:follow, :followed_proposal, followable: proposal) }
7.times { create(:vote, votable: proposal, vote_flag: true) }
login_as(author)
visit new_proposal_notification_path(proposal_id: proposal.id)
expect(page).to have_content "This message will be sent to 7 people and it will "\
"be visible in the proposal's page"
expect(page).to have_link("the proposal's page", href: proposal_path(proposal,
anchor: "comments"))
end
scenario "Message about receivers (Same Followers and Voters)" do
author = create(:user)
voter_follower = create(:user)
proposal = create(:proposal, author: author, voters: [voter_follower], followers: [voter_follower])
login_as(author)
visit new_proposal_notification_path(proposal_id: proposal.id)
expect(page).to have_content "This message will be sent to 1 people and it will "\
"be visible in the proposal's page"
expect(page).to have_link("the proposal's page", href: proposal_path(proposal,
anchor: "comments"))
end
context "Permissions" do
scenario "Link to send the message" do
author = create(:user)
proposal = create(:proposal, author: author)
login_as(author)
visit root_path
click_link "My content"
within("#proposal_#{proposal.id}") do
click_link "Dashboard"
end
within("#side_menu") do
click_link "Message to users"
end
expect(page).to have_link "Send message to proposal followers"
end
scenario "Accessing form directly" do
user = create(:user)
author = create(:user)
proposal = create(:proposal, author: author)
login_as(user)
visit new_proposal_notification_path(proposal_id: proposal.id)
expect(page).to have_current_path(root_path)
expect(page).to have_content("You do not have permission to carry out the action")
end
end
context "In-app notifications from the proposal's author" do
scenario "Voters who are followed should receive a notification", :js do
author = create(:user)
proposal = create(:proposal, author: author)
user1 = create(:user, votables: [proposal], followables: [proposal])
user2 = create(:user, votables: [proposal], followables: [proposal])
user3 = create(:user, votables: [proposal])
login_as(author)
visit root_path
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "proposal_notification_title", with: "Thank you for supporting my proposal"
fill_in "proposal_notification_body", with: "Please share it with "\
"others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
logout
login_as user1
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
click_link text: "There is one new notification on #{proposal.title}"
expect(page).to have_current_path(proposal_path(proposal))
logout
login_as user2
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
click_link text: "There is one new notification on #{proposal.title}"
expect(page).to have_current_path(proposal_path(proposal))
logout
login_as user3
visit root_path
find(".icon-no-notification").click
expect(page).to have_css ".notification", count: 0
end
scenario "Followers should receive a notification", :js do
author = create(:user)
proposal = create(:proposal, author: author)
user1 = create(:user, followables: [proposal])
user2 = create(:user, followables: [proposal])
user3 = create(:user)
login_as author.reload
visit root_path
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "proposal_notification_title", with: "Thank you for supporting my proposal"
fill_in "proposal_notification_body", with: "Please share it with "\
"others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
logout
login_as user1.reload
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
click_link text: "There is one new notification on #{proposal.title}"
expect(page).to have_current_path(proposal_path(proposal))
logout
login_as user2.reload
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
click_link text: "There is one new notification on #{proposal.title}"
expect(page).to have_current_path(proposal_path(proposal))
logout
login_as user3.reload
visit root_path
find(".icon-no-notification").click
expect(page).to have_css ".notification", count: 0
end
scenario "Proposal hidden", :js do
author = create(:user)
user = create(:user)
proposal = create(:proposal, author: author, voters: [user], followers: [user])
login_as(author)
visit root_path
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "proposal_notification_title", with: "Thank you for supporting my proposal"
fill_in "proposal_notification_body", with: "Please share it with "\
"others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
proposal.hide
logout
login_as user
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
expect(page).to have_content "This resource is not available anymore"
end
scenario "Proposal retired by author", :js do
author = create(:user)
user = create(:user)
proposal = create(:proposal, author: author, voters: [user])
login_as(author)
visit root_path
visit new_proposal_notification_path(proposal_id: proposal.id)
end
context "Group notifications" do
before do
Setting[:proposal_notification_minimum_interval_in_days] = 0
end
scenario "for the same proposal", :js do
author = create(:user)
proposal = create(:proposal, author: author)
user = create(:user, followables: [proposal])
login_as author.reload
3.times do
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "Title", with: "Thank you for supporting my proposal"
fill_in "Message", with: "Please share it with others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
end
logout
login_as user.reload
visit root_path
within("#notifications") { expect(page).to have_content :all, "You have 3 new notifications" }
find(".icon-notification").click
expect(page).to have_css ".notification", count: 3
expect(page).to have_content "There is one new notification on #{proposal.title}", count: 3
end
end
end
scenario "Error messages" do
author = create(:user)
proposal = create(:proposal, author: author)
login_as(author)
visit new_proposal_notification_path(proposal_id: proposal.id)
click_button "Send message"
expect(page).to have_content error_message
end
context "Limits" do
scenario "Cannot send more than one notification within established interval" do
author = create(:user)
proposal = create(:proposal, author: author)
login_as author.reload
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "Title", with: "Thank you for supporting my proposal"
fill_in "Message", with: "Please share it with others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "Title", with: "Thank you again for supporting my proposal"
fill_in "Message", with: "Please share it again with others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "You have to wait a minimum of 3 days between notifications"
expect(page).not_to have_content "Your message has been sent correctly."
end
scenario "Use time traveling to make sure notifications can be sent after time interval" do
author = create(:user)
proposal = create(:proposal, author: author)
login_as author.reload
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "Title", with: "Thank you for supporting my proposal"
fill_in "Message", with: "Please share it with others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
travel_to(3.days.from_now + 1.second) do
visit new_proposal_notification_path(proposal_id: proposal.id)
fill_in "Title", with: "Thank you again for supporting my proposal"
fill_in "Message", with: "Please share it again with others so we can make it happen!"
click_button "Send message"
expect(page).to have_content "Your message has been sent correctly."
expect(page).not_to have_content "You have to wait a minimum of 3 days between notifications"
end
end
end
end