Add comment notification test to Cypress, including a11y improvements to notification page (#15842)

* changes to accessible names on notification comment box, cypress specs

* add reply to comment test, delete old specs

* tweak to seeds
This commit is contained in:
Suzanne Aitchison 2021-12-21 15:42:13 +00:00 committed by GitHub
parent c2659d38df
commit 5fd1f94e85
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 106 additions and 37 deletions

View file

@ -70,6 +70,8 @@ function initReactions() {
for (var i = 0; i < butts.length; i++) {
var butt = butts[i];
butt.setAttribute('aria-pressed', butt.classList.contains('reacted'));
butt.onclick = function (event) {
event.preventDefault();
sendHapticMessage('medium');
@ -79,8 +81,10 @@ function initReactions() {
function successCb(response) {
if (response.result === 'create') {
thisButt.classList.add('reacted');
thisButt.setAttribute('aria-pressed', true);
} else {
thisButt.classList.remove('reacted');
thisButt.setAttribute('aria-pressed', false);
}
}

View file

@ -68,6 +68,9 @@
<%= render "articles/fitvids" %>
</main>
<%= javascript_packs_with_chunks_tag "followButtons", defer: true %>
<script>
<%== RunkitTag.script %>
</script>
<% else %>
<%= render "devise/registrations/registration_form" %>
<% end %>

View file

@ -40,23 +40,24 @@
data-reactable-id="<%= json_data["comment"]["id"] %>"
data-category="like"
data-reactable-type="Comment"
aria-label="<%= t("views.reactions.like.aria_label") %>"
title="heart">
<%= inline_svg_tag("small-heart.svg", aria: true, class: "crayons-icon reaction-icon not-reacted", title: t("views.comments.footer.heart.icon")) %>
<%= inline_svg_tag("small-heart-filled.svg", aria: true, class: "crayons-icon reaction-icon--like reaction-icon reacted", title: t("views.comments.footer.heart.icon")) %>
<%= inline_svg_tag("small-heart.svg", aria_hidden: true, class: "crayons-icon reaction-icon not-reacted", title: t("views.comments.footer.heart.icon")) %>
<%= inline_svg_tag("small-heart-filled.svg", aria_hidden: true, class: "crayons-icon reaction-icon--like reaction-icon reacted", title: t("views.comments.footer.heart.icon")) %>
<span class="hidden m:inline-block"><%= t("views.comments.footer.heart.text") %></span>
</button>
<% cache "comment-box-comment-reply-#{@last_user_comment}-#{json_data['comment']['updated_at']}-#{json_data['comment']['id']}" do %>
<% reply = Comment.select(:id, :user_id, :ancestry).find_by(id: json_data["comment"]["id"])&.children&.find_by(user_id: current_user.id) %>
<% if reply %>
<a class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left mr-1 inline-flex reaction-comment reacted" href="<%= reply.path %>">
<%= inline_svg_tag("small-comment-filled.svg", aria: true, class: "crayons-icon reaction-icon--comment reaction-icon reacted", title: t("views.comments.footer.reply.icon")) %>
<a class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left mr-1 inline-flex reaction-comment reacted" href="<%= reply.path %>" aria-label="<%= t("views.comments.footer.reply.done") %>">
<%= inline_svg_tag("small-comment-filled.svg", aria_hidden: true, class: "crayons-icon reaction-icon--comment reaction-icon reacted", title: t("views.comments.footer.reply.icon")) %>
<span class="hidden m:inline-block"><%= t("views.comments.footer.reply.done") %></span>
</a>
<% else %>
<a class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left toggle-reply-form mr-1 inline-flex" data-reactable-id="<%= json_data["comment"]["id"] %>" href="#<%= json_data["comment"]["path"] %>">
<%= inline_svg_tag("small-comment.svg", aria: true, class: "crayons-icon reaction-icon not-reacted", title: t("views.comments.footer.reply.icon")) %>
<%= inline_svg_tag("small-comment-filled.svg", aria: true, class: "crayons-icon reaction-icon--comment reaction-icon reacted", title: t("views.comments.footer.reply.icon")) %>
<a class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left toggle-reply-form mr-1 inline-flex" data-reactable-id="<%= json_data["comment"]["id"] %>" href="#<%= json_data["comment"]["path"] %>" aria-label="<%= t("views.comments.footer.reply.text") %>">
<%= inline_svg_tag("small-comment.svg", aria_hidden: true, class: "crayons-icon reaction-icon not-reacted", title: t("views.comments.footer.reply.icon")) %>
<%= inline_svg_tag("small-comment-filled.svg", aria_hidden: true, class: "crayons-icon reaction-icon--comment reaction-icon reacted", title: t("views.comments.footer.reply.icon")) %>
<span class="hidden m:inline-block"><%= t("views.comments.footer.reply.text") %></span>
</a>
<% end %>
@ -74,7 +75,8 @@
<%= f.hidden_field :commentable_type, value: json_data["comment"]["commentable"]["class"]["name"] %>
<%= f.hidden_field :parent_id, value: json_data["comment"]["id"] %>
<%= f.text_area :body_markdown, id: "comment-textarea-for-#{json_data['comment']['id']}", class: "crayons-textfield mb-2 resize-y", placeholder: t("views.comments.footer.reply.placeholder"), "aria-label": t("views.comments.footer.reply.aria_label"), onfocus: "handleFocus(event)" %>
<%= f.text_area :body_markdown, id: "comment-textarea-for-#{json_data['comment']['id']}", class: "comment-textarea crayons-textfield mb-2 resize-y", placeholder: t("views.comments.footer.reply.placeholder"), "aria-label": t("views.comments.footer.reply.aria_label"),
onfocus: "handleFocus(event)" %>
<div class="actions">
<button type="submit" class="crayons-btn comment-action-button" onclick="validateField(event)"><%= t("views.comments.write.submit") %></button>
</div>

View file

@ -0,0 +1,45 @@
describe('Comment notifications', () => {
beforeEach(() => {
cy.testSetup();
cy.fixture('users/notificationsUser.json').as('user');
cy.get('@user').then((user) => {
cy.loginAndVisit(user, '/notifications');
cy.findByRole('heading', { name: 'Notifications', level: 1 });
});
});
it('Likes and unlikes a comment', () => {
cy.get('main').within(() => {
cy.findByRole('button', { name: 'Like' }).as('like');
// User can like a comment
cy.get('@like')
.should('have.attr', 'aria-pressed', 'false')
.click()
.should('have.attr', 'aria-pressed', 'true');
// User can unlike a comment
cy.get('@like').click().should('have.attr', 'aria-pressed', 'false');
});
});
it('Replies to a comment', () => {
cy.get('main').within(() => {
// Check that comment form is initially hidden
cy.findByRole('textbox', { name: 'Reply to a comment...' }).should(
'not.exist',
);
// Check the textbox appears and received immediate focus
cy.findByRole('link', { name: 'Reply' }).click();
cy.findByRole('textbox', { name: 'Reply to a comment...' })
.should('have.focus')
.type('Example reply text');
cy.findByRole('button', { name: 'Submit' }).click();
// Check the confirmation is displayed on the page
cy.findByRole('link', { name: 'Check it out' });
});
});
});

View file

@ -199,6 +199,7 @@ seeder.create_if_doesnt_exist(User, "email", "notifications-user@forem.local") d
checked_code_of_conduct: true,
checked_terms_and_conditions: true,
)
user.notification_setting.update(
email_comment_notifications: false,
email_follower_notifications: false,
@ -208,8 +209,51 @@ seeder.create_if_doesnt_exist(User, "email", "notifications-user@forem.local") d
website_url: Faker::Internet.url,
)
# Create a follow notification to test against
follow = admin_user.follows.create!(followable: user)
Notification.send_new_follower_notification_without_delay(follow)
# Create an article comment notification to test against
seeder.create_if_doesnt_exist(Article, "slug", "notification-article-slug") do
markdown = <<~MARKDOWN
---
title: Notification article
published: true
---
#{Faker::Hipster.paragraph(sentence_count: 2)}
#{Faker::Markdown.random}
#{Faker::Hipster.paragraph(sentence_count: 2)}
MARKDOWN
article = Article.create!(
body_markdown: markdown,
featured: true,
show_comments: true,
user_id: user.id,
slug: "notification-article-slug",
)
parent_comment_attributes = {
body_markdown: Faker::Hipster.paragraph(sentence_count: 1),
user_id: user.id,
commentable_id: article.id,
commentable_type: "Article"
}
parent_comment = Comment.create!(parent_comment_attributes)
Notification.send_new_comment_notifications_without_delay(parent_comment)
reply_comment_attributes = {
body_markdown: Faker::Hipster.paragraph(sentence_count: 1),
user_id: admin_user.id,
commentable_id: article.id,
commentable_type: "Article",
parent: parent_comment
}
reply = Comment.create!(reply_comment_attributes)
Notification.send_new_comment_notifications_without_delay(reply)
end
end
##############################################################################

View file

@ -25,35 +25,6 @@ RSpec.describe "Notifications page", type: :system, js: true do
expect(page).not_to have_css("span#notifications-number", text: "1")
end
xit "allows user to interact with replies" do
sidekiq_perform_enqueued_jobs do
article = create(:article, user: alex)
comment = create(:comment, commentable: article, user: alex)
reply = create(:comment, commentable: article, user: leslie, parent: comment)
Notification.send_new_comment_notifications_without_delay(reply)
end
visit "/notifications"
expect(page).to have_css("div.spec-notification")
click_button("heart")
expect(page).to have_css(".reacted")
click_link("Reply")
validate_reply(leslie.comments.first.id)
end
it "allows user to follow other users back" do
follow = leslie.follow(alex)
Notification.send_new_follower_notification_without_delay(follow, is_read: true)
visit "/notifications"
expect(page).to have_css("div.spec-notification")
click_button(I18n.t("core.follow_back"))
expect(page).to have_text(I18n.t("core.following"))
end
xcontext "when user is trusted" do
before do
dev_user = create(:user)