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.
418 lines
13 KiB
Ruby
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
|