Accessible names for follow buttons (#14389)

* added follow hidden tags for accessibility

* fixed failing tests

* replaced hidden span with screen-reader-only with aria-label

* add aria-label dynamically to follow buttons

* fixed followButtons

* fixed cypress tests and updated addAriaLabelToButton helper

* Fixed failing tests

* fixed failing tests

* Update cypress/integration/seededFlows/notificationsFlows/followUserFromNotifications.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>
This commit is contained in:
Keshav Biswa 2021-09-07 20:39:06 +05:30 committed by GitHub
parent 5fc3f52299
commit 42c9a10f57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 231 additions and 87 deletions

View file

@ -187,7 +187,7 @@ function buildArticleHTML(article) {
</a>
</div>
<div class="print-hidden">
<button class="crayons-btn follow-action-button whitespace-nowrap follow-user w-100" data-info='{"id": ${article.user_id}, "className": "User", "style": "full"}'>Follow</button>
<button class="crayons-btn follow-action-button whitespace-nowrap follow-user w-100" data-info='{"id": ${article.user_id}, "className": "User", "style": "full", "name": "${article.user.name}"}'>Follow</button>
</div>
<div class="author-preview-metadata-container" data-author-id="${article.user_id}"></div>
</div>
@ -196,7 +196,7 @@ function buildArticleHTML(article) {
var meta = `
<div class="crayons-story__meta">
<div class="crayons-story__author-pic">
<div class="crayons-story__author-pic">
${organizationLogo}
<a href="/${profileUsername}" class="crayons-avatar ${organizationClasses}">
<img src="${picUrl}" alt="${profileUsername} profile" class="crayons-avatar__image" loading="lazy" />
@ -262,13 +262,13 @@ function buildArticleHTML(article) {
<span class="bm-success">Saved</span>\
</button>';
} else if (article.class_name === 'User') {
saveButton =
'<button type="button" class="crayons-btn crayons-btn--secondary crayons-btn--icon-left fs-s bookmark-button article-engagement-count engage-button follow-action-button follow-user"\
data-info=\'{"id":' +
article.id +
',"className":"User"}\' data-follow-action-button>\
&nbsp;\
</button>';
saveButton = `
<button type="button"
class="crayons-btn crayons-btn--secondary crayons-btn--icon-left fs-s bookmark-button article-engagement-count engage-button follow-action-button follow-user"
data-info='{"id": ${article.id},"className":"User", "name": "${article.user.name}"}'
data-follow-action-button>
&nbsp;
</button>`;
}
var videoHTML = '';

View file

@ -123,6 +123,13 @@ module ApplicationHelper
return if followable == DELETED_USER
user_follow = followable.instance_of?(User) ? "follow-user" : ""
followable_type = if followable.respond_to?(:decorated?) && followable.decorated?
followable.object.class.name.downcase
else
followable.class.name.downcase
end
followable_name = followable.name
tag.button(
"Follow",
@ -131,11 +138,13 @@ module ApplicationHelper
data: {
info: {
id: followable.id,
className: followable.class.name,
className: followable_type,
name: followable_name,
style: style
}
},
class: "crayons-btn follow-action-button whitespace-nowrap #{classes} #{user_follow}",
aria: { label: "Follow #{followable_type}: #{followable_name}" },
)
end

View file

@ -114,7 +114,7 @@ Object {
>
<button
class="crayons-btn follow-action-button whitespace-nowrap follow-user w-100"
data-info="{\\"id\\":23289,\\"className\\":\\"User\\",\\"style\\":\\"full\\"}"
data-info="{\\"id\\":23289,\\"className\\":\\"User\\",\\"name\\":\\"Stella Macejkovic\\",\\"style\\":\\"full\\"}"
>
Follow
</button>
@ -362,7 +362,7 @@ Object {
>
<button
class="crayons-btn follow-action-button whitespace-nowrap follow-user w-100"
data-info="{\\"id\\":23289,\\"className\\":\\"User\\",\\"style\\":\\"full\\"}"
data-info="{\\"id\\":23289,\\"className\\":\\"User\\",\\"name\\":\\"Stella Macejkovic\\",\\"style\\":\\"full\\"}"
>
Follow
</button>

View file

@ -9,18 +9,67 @@ import { getInstantClick } from '../topNavigation/utilities';
* @param {string} style The style of the button from its "info" data attribute
*/
function addButtonFollowText(button, style) {
const { name, className } = JSON.parse(button.dataset.info);
switch (style) {
case 'small':
addAriaLabelToButton({
button,
followName: name,
followType: className,
style: 'follow',
});
button.textContent = '+';
break;
case 'follow-back':
addAriaLabelToButton({
button,
followName: name,
followType: className,
style: 'follow-back',
});
button.textContent = 'Follow back';
break;
default:
addAriaLabelToButton({
button,
followName: name,
followType: className,
style: 'follow',
});
button.textContent = 'Follow';
}
}
/**
* Sets the aria-label of the button
*
* @param {HTMLElement} button The Follow button to update.
* @param {string} followType The followableType of the button.
* @param {string} followName The name of the followable to be followed.
* @param {string} style The style of the button from its "info" data attribute
*/
function addAriaLabelToButton({ button, followType, followName, style = '' }) {
let label = '';
switch (style) {
case 'follow':
label = `Follow ${followType.toLowerCase()}: ${followName}`;
break;
case 'follow-back':
label = `Follow ${followType.toLowerCase()} back: ${followName}`;
break;
case 'following':
label = `Unfollow ${followType.toLowerCase()}: ${followName}`;
break;
case 'self':
label = `Edit profile`;
break;
default:
label = `Follow ${followType.toLowerCase()}: ${followName}`;
}
button.setAttribute('aria-label', label);
}
/**
* Sets the text content of the button to the correct 'Following' state
*
@ -81,11 +130,18 @@ function optimisticallyUpdateButtonUI(button) {
* @param {string} style Style of the follow button (e.g. 'small')
*/
function updateFollowingButton(button, style) {
const { name, className } = JSON.parse(button.dataset.info);
button.dataset.verb = 'follow';
addButtonFollowingText(button, style);
button.classList.remove('crayons-btn--primary');
button.classList.remove('crayons-btn--secondary');
button.classList.add('crayons-btn--outlined');
addAriaLabelToButton({
button,
followName: name,
followType: className,
style: 'following',
});
}
/**
@ -96,6 +152,12 @@ function updateFollowingButton(button, style) {
function updateUserOwnFollowButton(button) {
button.dataset.verb = 'self';
button.textContent = 'Edit profile';
addAriaLabelToButton({
button,
followName: '',
followType: '',
style: 'self',
});
}
/**
@ -251,11 +313,14 @@ function initializeAllUserFollowButtons() {
Array.from(buttons, (button) => {
button.dataset.fetched = 'fetched';
const { userStatus } = document.body.dataset;
const buttonInfo = JSON.parse(button.dataset.info);
const { name, className } = buttonInfo;
if (userStatus === 'logged-out') {
const { style } = JSON.parse(button.dataset.info);
addButtonFollowText(button, style);
} else {
addAriaLabelToButton({ button, followType: className, followName: name });
const { id: userId } = JSON.parse(button.dataset.info);
if (userIds[userId]) {
userIds[userId].push(button);
@ -317,7 +382,9 @@ function initializeNonUserFollowButtons() {
nonUserFollowButtons.forEach((button) => {
const { info } = button.dataset;
const buttonInfo = JSON.parse(info);
if (buttonInfo.className === 'Tag' && user) {
const { className, name } = buttonInfo;
addAriaLabelToButton({ button, followType: className, followName: name });
if (className === 'Tag' && user) {
// We don't need to make a network request to 'fetch' the status of tag buttons
button.dataset.fetched = true;
const initialButtonFollowState = followedTagIds.has(buttonInfo.id)

View file

@ -45,6 +45,7 @@ export const MinimalProfilePreviewCard = ({
data-info={JSON.stringify({
id: userId,
className: 'User',
name,
style: 'full',
})}
>

View file

@ -64,7 +64,7 @@
<div class="print-hidden">
<button
class="crayons-btn follow-action-button whitespace-nowrap follow-user w-100"
data-info='{"id": <%= story.user_id %>, "className": "User", "style": "full"}'>
data-info='{"id": <%= story.user_id %>, "className": "User", "style": "full", "name": "<%= story.cached_user.name %>"}'>
Follow
</button>
</div>

View file

@ -17,7 +17,7 @@
</a>
<a class="follow-action-button sidebar-nav-link-follow crayons-btn crayons-btn--s"
href="#" id="sidebar-nav-link-follow-<%= tag_array.second %>"
data-info='{"id":<%= tag_array.first %>,"className":"Tag"}'>
data-info='{"id":<%= tag_array.first %>,"className":"Tag", "name": "<%= tag_array.second %>"}'>
Follow
</a>
</div>

View file

@ -17,7 +17,12 @@
</span>
<div class="profile-header__actions">
<button id="user-follow-butt" class="crayons-btn whitespace-nowrap follow-action-button user-profile-follow-button" data-info='{"id":<%= @user.id %>,"className":"<%= @user.class.name %>"}'>Follow</button>
<button
id="user-follow-butt"
class="crayons-btn whitespace-nowrap follow-action-button user-profile-follow-button"
data-info='{"id":<%= @user.id %>,"className":"<%= @user.class.name %>", "name": "<%= @user.name %>"}'>
Follow
</button>
</div>
</div>

View file

@ -12,7 +12,10 @@
</div>
</a>
<div class="ltag__user__content">
<h2><a href="/<%= organization.slug %>" class="ltag__user__link"><%= organization.name %></a><%= follow_button %></h2>
<h2>
<a href="/<%= organization.slug %>" class="ltag__user__link"><%= organization.name %></a>
<%= follow_button(organization) %>
</h2>
<div class="ltag__user__summary">
<a href="/<%= organization.slug %>" class="ltag__user__link">
<%= organization.summary %>

View file

@ -7,7 +7,7 @@
</a>
<a href="/<%= podcast.slug %>" style="display:block">
<h2 class="podcastliquidtag__info__podcasttitle">
<%= podcast.title %> <button class="crayons-btn follow-action-button" data-info='{"id":<%= podcast.id %>,"className":"<%= podcast.class.name %>"}'>&nbsp;</button>
<%= podcast.title %> <button class="crayons-btn follow-action-button" data-info='{"id":<%= podcast.id %>,"className":"<%= podcast.class.name %>", "name": <%= podcast.name %>}'>&nbsp;</button>
</h2>
</a>

View file

@ -7,7 +7,12 @@
<div class="tag-or-query-header-container">
<h1><img class="record main-image" src="<%= Images::Optimizer.call(@podcast.image_url, crop: "fill", width: 420, height: 420) %>"
alt="<%= @podcast.title %>" /> <%= @podcast.title %>
<button id="user-follow-butt" class="crayons-btn follow-action-button user-profile-follow-button" data-info='{"id":<%= @podcast.id %>,"className":"<%= @podcast.class.name %>"}'>&nbsp;</button>
<button
id="user-follow-butt"
class="crayons-btn follow-action-button user-profile-follow-button"
data-info='{"id":<%= @podcast.id %>,"className":"<%= @podcast.class.name %>", "name": "<%= @podcast.name %>"}'>
&nbsp;
</button>
</h1>
</div>
</div>

View file

@ -36,7 +36,12 @@
<a href="/<%= @podcast.slug %>">
<img aria-hidden="true" alt="<%= @podcast.title %>" src="<%= optimized_image_url(@podcast.image_url, width: 60, quality: 80) %>" /><%= @podcast.title %>
</a>
<button id="user-follow-butt" class="crayons-btn follow-action-button" data-info='{"id":<%= @podcast.id %>,"className":"<%= @podcast.class.name %>"}'>&nbsp;</button>
<button
id="user-follow-butt"
class="crayons-btn follow-action-button"
data-info='{"id":<%= @podcast.id %>,"className":"<%= @podcast.class.name %>", "name": "<%= @podcast.name %>"}'>
&nbsp;
</button>
</h2>
<% if @episode.title.size > 60 %>
<h1 class="smaller"><%= @episode.title %></h1>

View file

@ -21,7 +21,12 @@
<% end %>
</h1>
<% if @tag_model %>
<button id="user-follow-butt" class="crayons-btn follow-action-button" data-info='{"id":<%= @tag_model.id %>,"className":"Tag"}'>Follow</button>
<button
id="user-follow-butt"
class="crayons-btn follow-action-button"
data-info='{"id":<%= @tag_model.id %>,"className":"Tag", "name": "<%= @tag_model.pretty_name || @tag %>"}'>
Follow
</button>
<% end %>
</div>
<% if @tag_model && @tag_model.short_summary.present? %>

View file

@ -47,7 +47,7 @@
<div class="mt-auto">
<button
class="crayons-btn crayons-btn--secondary follow-action-button"
data-info='{"id":<%= tag.id %>,"className":"Tag", "followStyle":"secondary"}'>
data-info='{"id":<%= tag.id %>,"className":"Tag", "followStyle":"secondary", "name": "<%= tag.name %>"}'>
Follow
</button>
</div>

View file

@ -18,7 +18,7 @@
</div>
<% end %>
<div class="ltag__user__content">
<h2><%= link_to_if user_path.present?, user.name, user_path, class: "ltag__user__link" %><%= follow_button %></h2>
<h2><%= link_to_if user_path.present?, user.name, user_path, class: "ltag__user__link" %><%= follow_button(user) %></h2>
<div class="ltag__user__summary">
<%= link_to_if user_path.present?, user.tag_line, user_path, class: "ltag__user__link" %>
</div>

View file

@ -33,7 +33,7 @@
<button class="chat-action-button crayons-btn crayons-btn--outlined hidden" id="modal-opener">Chat</button>
</a>
<% end %>
<button id="user-follow-butt" class="crayons-btn whitespace-nowrap follow-action-button user-profile-follow-button follow-user" data-info='{"id":<%= @user.id %>,"className":"<%= @user.class.name %>"}'>Follow</button>
<button id="user-follow-butt" class="crayons-btn whitespace-nowrap follow-action-button user-profile-follow-button follow-user" data-info='{"id":<%= @user.id %>,"className":"<%= @user.class.name %>", "name": "<%= @user.name %>"}'>Follow</button>
<div class="profile-dropdown ml-2 relative hidden" data-username="<%= @user.username %>">
<button id="user-profile-dropdown" aria-expanded="false" aria-controls="user-profile-dropdownmenu" aria-haspopup="true" class="crayons-btn crayons-btn--ghost-dimmed crayons-btn--icon">
<%= inline_svg_tag("overflow-horizontal.svg", class: "dropdown-icon crayons-icon", aria: true, title: "User actions") %>

View file

@ -16,10 +16,11 @@ describe('Follow author from article sidebar', () => {
cy.intercept('/follows').as('followRequest');
cy.findByRole('complementary', { name: 'Author details' }).within(() => {
cy.findByRole('button', { name: 'Follow' }).as('followButton');
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).as(
'followButton',
);
cy.get('@followButton').click();
cy.wait('@followRequest');
cy.get('@followButton').should('have.text', 'Following');
cy.get('@followButton').click();

View file

@ -27,9 +27,9 @@ describe('Follow from article liquid tag', () => {
it('Follows a user from an article liquid tag', () => {
cy.findByRole('main').within(() => {
cy.findAllByRole('button', { name: 'Follow' })
.first()
.as('followUserButton');
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).as(
'followUserButton',
);
cy.get('@followUserButton').should('have.text', 'Follow');
cy.get('@followUserButton').click();
cy.get('@followUserButton').should('have.text', 'Following');
@ -66,10 +66,10 @@ describe('Follow from article liquid tag', () => {
it('Follows a user from an article liquid tag', () => {
cy.findByRole('main').within(() => {
cy.findAllByRole('button', { name: 'Follow back' })
.first()
.as('followUserButton');
cy.get('@followUserButton').should('have.text', 'Follow back');
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).as(
'followUserButton',
);
cy.get('@followUserButton').should('have.text', 'Follow');
cy.get('@followUserButton').click();
cy.get('@followUserButton').should('have.text', 'Following');
cy.get('@followUserButton').click();
@ -104,9 +104,9 @@ describe('Follow from article liquid tag', () => {
it('Follows a tag from an article liquid tag', () => {
cy.findByRole('main').within(() => {
cy.findAllByRole('button', { name: 'Follow' })
.last()
.as('followTagButton');
cy.findByRole('button', { name: 'Follow tag: tag1' }).as(
'followTagButton',
);
cy.get('@followTagButton').should('have.text', 'Follow');
cy.get('@followTagButton').click();
cy.get('@followTagButton').should('have.text', 'Following');

View file

@ -78,11 +78,15 @@ describe('Preview user profile from article page', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', {
name: 'Follow user: Admin McAdmin',
}).click();
// Wait for Follow button to disappear and Following button to be initialized
cy.findByRole('button', { name: 'Follow' }).should('not.exist');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', {
name: 'Follow user: Admin McAdmin',
}).should('not.exist');
cy.findByRole('button', { name: 'Unfollow user: Admin McAdmin' });
});
// Check we can close the preview dropdown
@ -117,11 +121,15 @@ describe('Preview user profile from article page', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', {
name: 'Follow user: Admin McAdmin',
}).click();
// Wait for Follow button to disappear and Following button to be initialized
cy.findByRole('button', { name: 'Follow' }).should('not.exist');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', {
name: 'Follow user: Admin McAdmin',
}).should('not.exist');
cy.findByRole('button', { name: 'Unfollow user: Admin McAdmin' });
});
});
});
@ -137,10 +145,14 @@ describe('Preview user profile from article page', () => {
cy.findAllByTestId('profile-preview-card')
.first()
.within(() => {
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', {
name: 'Follow user: Admin McAdmin',
}).click();
// Confirm the follow button has been updated
cy.findByRole('button', { name: 'Follow' }).should('not.exist');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', {
name: 'Follow user: Admin McAdmin',
}).should('not.exist');
cy.findByRole('button', { name: 'Unfollow user: Admin McAdmin' });
});
// Close the preview card so the next preview button can be clicked
@ -153,7 +165,7 @@ describe('Preview user profile from article page', () => {
cy.findAllByTestId('profile-preview-card')
.last()
.findByRole('button', { name: 'Following' });
.findByRole('button', { name: 'Unfollow user: Admin McAdmin' });
});
it('should detach listeners on preview card close', () => {
@ -280,7 +292,7 @@ describe('Preview user profile from article page', () => {
name: 'Admin McAdmin',
}).should('have.focus');
cy.findByRole('button', { name: 'Follow' });
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' });
cy.findByText('Admin user summary');
cy.findByText('Software developer at Company');
cy.findByText('Edinburgh');

View file

@ -32,11 +32,13 @@ describe('Preview profile from series', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', { name: 'Follow user: Series User' }).click();
// Check that the follow button has updated as expected
cy.findByRole('button', { name: 'Follow' }).should('not.exist');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', { name: 'Follow user: Series User' }).should(
'not.exist',
);
cy.findByRole('button', { name: 'Unfollow user: Series User' });
});
});
});

View file

@ -16,7 +16,9 @@ describe('View article discussion', () => {
cy.findByRole('button', { name: 'Admin McAdmin profile details' }).click();
cy.findByTestId('profile-preview-card').within(() => {
cy.findByRole('button', { name: 'Follow' }).as('userFollowButton');
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).as(
'userFollowButton',
);
cy.get('@userFollowButton').click();
// Confirm the follow button has been updated

View file

@ -27,11 +27,13 @@ describe('Home feed profile preview cards', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).click();
// Check that following status has been updated
cy.findByRole('button', { name: 'Follow' }).should('not.exist');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).should(
'not.exist',
);
cy.findByRole('button', { name: 'Unfollow user: Admin McAdmin' });
});
});
});

View file

@ -24,7 +24,7 @@ describe('Logged out Home feed', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).click();
});
// Clicking a follow button while logged out should always trigger the log in to continue modal

View file

@ -62,7 +62,7 @@ describe('Show log in modal', () => {
verifyLoginModalBehavior(() =>
cy
.findByRole('complementary', { name: 'Author details' })
.findByRole('button', { name: 'Follow' }),
.findByRole('button', { name: 'Follow user: Admin McAdmin' }),
);
});
@ -72,13 +72,15 @@ describe('Show log in modal', () => {
cy.get('[data-follow-clicks-initialized]');
verifyLoginModalBehavior(() =>
cy.findAllByRole('button', { name: 'Follow' }).first(),
cy.findByRole('button', { name: 'Follow tag: tag1' }),
);
cy.visit('/t/tag1');
cy.findByRole('heading', { name: '# tag1' });
verifyLoginModalBehavior(() => cy.findByRole('button', { name: 'Follow' }));
verifyLoginModalBehavior(() =>
cy.findByRole('button', { name: 'Follow tag: tag1' }),
);
});
it('should show login modal for user profile follow button click', () => {
@ -86,7 +88,9 @@ describe('Show log in modal', () => {
cy.get('[data-follow-clicks-initialized]');
cy.findByRole('heading', { name: 'Admin McAdmin' });
verifyLoginModalBehavior(() => cy.findByRole('button', { name: 'Follow' }));
verifyLoginModalBehavior(() =>
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }),
);
});
it('should show login modal for podcast follow button click', () => {
@ -97,6 +101,8 @@ describe('Show log in modal', () => {
name: 'Developer on Fire Developer on Fire Follow',
});
verifyLoginModalBehavior(() => cy.findByRole('button', { name: 'Follow' }));
verifyLoginModalBehavior(() =>
cy.findByRole('button', { name: 'Follow podcast: Developer on Fire' }),
);
});
});

View file

@ -25,7 +25,7 @@ describe('Logged out - tag index page', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).click();
});
// Clicking a follow button while logged out should always trigger the log in to continue modal

View file

@ -10,16 +10,15 @@ describe('Follow user from notifications', () => {
it('Follows and unfollows a user from a follow notification', () => {
cy.findByRole('heading', { name: 'Notifications' });
cy.intercept('/follows').as('followsRequest');
cy.findByRole('button', { name: 'Follow back' }).as('followButton');
cy.findByRole('button', { name: 'Follow user back: User' }).as(
'followButton',
);
cy.get('@followButton').click();
cy.wait('@followsRequest');
cy.get('@followButton').should('have.text', 'Following');
cy.get('@followButton').click();
cy.wait('@followsRequest');
cy.get('@followButton').should('have.text', 'Follow back');
});
});

View file

@ -13,7 +13,9 @@ describe('Follow podcast', () => {
cy.findByRole('heading', {
name: 'Developer on Fire Developer on Fire Follow',
});
cy.findByRole('button', { name: 'Follow' }).as('followButton');
cy.findByRole('button', { name: 'Follow podcast: Developer on Fire' }).as(
'followButton',
);
cy.get('@followButton').click();
// Inner text should now be following
@ -21,7 +23,9 @@ describe('Follow podcast', () => {
// Check that state is persisted on refresh
cy.visitAndWaitForUserSideEffects('/developeronfire');
cy.findByRole('button', { name: 'Following' }).as('followButton');
cy.findByRole('button', { name: 'Unfollow podcast: Developer on Fire' }).as(
'followButton',
);
// Check it reverts back to Follow on click
cy.get('@followButton').click();
@ -29,6 +33,8 @@ describe('Follow podcast', () => {
// Check that state is persisted on refresh
cy.visitAndWaitForUserSideEffects('/developeronfire');
cy.findByRole('button', { name: 'Follow' }).as('followButton');
cy.findByRole('button', { name: 'Follow podcast: Developer on Fire' }).as(
'followButton',
);
});
});

View file

@ -12,20 +12,24 @@ describe('Follow user from profile page', () => {
it('follows and unfollows an organisation', () => {
cy.intercept('/follows').as('followsRequest');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', {
name: 'Follow organization: Bachmanity',
}).click();
cy.wait('@followsRequest');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', { name: 'Unfollow organization: Bachmanity' });
// Check that the update persists after reload
cy.visitAndWaitForUserSideEffects('/bachmanity');
cy.findByRole('button', { name: 'Following' }).click();
cy.findByRole('button', {
name: 'Unfollow organization: Bachmanity',
}).click();
cy.wait('@followsRequest');
cy.findByRole('button', { name: 'Follow' });
cy.findByRole('button', { name: 'Follow organization: Bachmanity' });
// Check that the update persists after reload
cy.visitAndWaitForUserSideEffects('/bachmanity');
cy.findByRole('button', { name: 'Follow' });
cy.findByRole('button', { name: 'Follow organization: Bachmanity' });
});
});

View file

@ -12,20 +12,24 @@ describe('Follow user from profile page', () => {
it('follows and unfollows a user', () => {
cy.intercept('/follows').as('followsRequest');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', {
name: 'Follow user: Article Editor v1 User',
}).click();
cy.wait('@followsRequest');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', { name: 'Unfollow user: Article Editor v1 User' });
// Check that the update persists after reload
cy.visitAndWaitForUserSideEffects('/article_editor_v1_user');
cy.findByRole('button', { name: 'Following' }).click();
cy.findByRole('button', {
name: 'Unfollow user: Article Editor v1 User',
}).click();
cy.wait('@followsRequest');
cy.findByRole('button', { name: 'Follow' });
cy.findByRole('button', { name: 'Follow user: Article Editor v1 User' });
// Check that the update persists after reload
cy.visitAndWaitForUserSideEffects('/article_editor_v1_user');
cy.findByRole('button', { name: 'Follow' });
cy.findByRole('button', { name: 'Follow user: Article Editor v1 User' });
});
});

View file

@ -24,7 +24,9 @@ describe('Follow user from search results', () => {
cy.intercept('/follows').as('followsRequest');
cy.findAllByRole('button', { name: 'Follow' }).first().as('followButton');
cy.findByRole('button', { name: 'Follow user: article_editor_v1_user' }).as(
'followButton',
);
cy.get('@followButton').click();
cy.wait('@followsRequest');

View file

@ -28,11 +28,13 @@ describe('Preview profile from post search results', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).click();
// Check that following status has been updated
cy.findByRole('button', { name: 'Follow' }).should('not.exist');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).should(
'not.exist',
);
cy.findByRole('button', { name: 'Unfollow user: Admin McAdmin' });
});
});
});

View file

@ -14,7 +14,7 @@ describe('Follow tag', () => {
it('Follows and unfollows a tag from the tag index page', () => {
cy.intercept('/follows').as('followsRequest');
cy.findAllByRole('button', { name: 'Follow' }).first().as('followButton');
cy.findByRole('button', { name: 'Follow tag: tag1' }).as('followButton');
cy.get('@followButton').click();
cy.wait('@followsRequest');
@ -43,7 +43,7 @@ describe('Follow tag', () => {
it('Follows and unfollows a tag from the tag feed page', () => {
cy.intercept('/follows').as('followsRequest');
cy.findByRole('button', { name: 'Follow' }).as('followButton');
cy.findByRole('button', { name: 'Follow tag: tag1' }).as('followButton');
cy.get('@followButton').click();
cy.wait('@followsRequest');

View file

@ -28,11 +28,13 @@ describe('Preview profile from the tag index page', () => {
cy.findByText('Edinburgh');
cy.findByText('University of Life');
cy.findByRole('button', { name: 'Follow' }).click();
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).click();
// Check that following status has been updated
cy.findByRole('button', { name: 'Follow' }).should('not.exist');
cy.findByRole('button', { name: 'Following' });
cy.findByRole('button', { name: 'Follow user: Admin McAdmin' }).should(
'not.exist',
);
cy.findByRole('button', { name: 'Unfollow user: Admin McAdmin' });
});
});
});