More frontend test cleanup (#8919)

This commit is contained in:
Nick Taylor 2020-06-25 18:04:01 -04:00 committed by GitHub
parent e49999ded0
commit 63b4d9fdc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 523 additions and 341 deletions

View file

@ -46,14 +46,14 @@ describe('<ArticleCoverImage />', () => {
});
it('shows the change and remove buttons', () => {
const { getByText } = render(
const { queryByText } = render(
<ArticleCoverImage
mainImage={'/some-fake-image.jpg'}
onMainImageUrlChange={jest.fn()}
/>,
);
getByText('Change');
getByText('Remove');
expect(queryByText('Change')).toBeDefined();
expect(queryByText('Remove')).toBeDefined();
});
it('allows trigger the correct function for removal', async () => {

View file

@ -1,8 +1,8 @@
import { h } from 'preact';
import { render, fireEvent, waitForElement } from '@testing-library/preact';
import { axe } from 'jest-axe';
import { ImageUploader } from '../ImageUploader';
import fetch from 'jest-fetch-mock';
import { ImageUploader } from '../ImageUploader';
import '@testing-library/jest-dom';
global.fetch = fetch;

View file

@ -127,7 +127,7 @@ describe('<Article /> component', () => {
});
it('should render with an organization', () => {
const { getByAltText } = render(
const { queryByAltText } = render(
<Article
{...commonProps}
isBookmarked={false}
@ -136,20 +136,20 @@ describe('<Article /> component', () => {
/>,
);
getByAltText('Web info-mediaries logo');
getByAltText('Emil99 profile');
expect(queryByAltText('Web info-mediaries logo')).toBeDefined();
expect(queryByAltText('Emil99 profile')).toBeDefined();
});
it('should render with a flare tag', () => {
const { getByText } = render(
const { queryByText } = render(
<Article {...commonProps} isBookmarked={false} article={article} />,
);
getByText('#javascript', { selector: 'span' });
expect(queryByText('#javascript', { selector: 'span' })).toBeDefined();
});
it('should render with a snippet result', () => {
const { getByText } = render(
const { queryByText } = render(
<Article
{...commonProps}
isBookmarked={false}
@ -157,9 +157,11 @@ describe('<Article /> component', () => {
/>,
);
getByText(
'…copying Rest withdrawal Handcrafted multi-state Pre-emptive e-markets feed...overriding RSS Fantastic Plastic Gloves invoice productize systemic Monaco…',
);
expect(
queryByText(
'…copying Rest withdrawal Handcrafted multi-state Pre-emptive e-markets feed...overriding RSS Fantastic Plastic Gloves invoice productize systemic Monaco…',
),
).toBeDefined();
});
it('should render with reactions', () => {

View file

@ -214,7 +214,7 @@ describe('<Chat />', () => {
it('should collapse and expand chat channels properly', async () => {
fetch.mockResponse(getMockResponse());
const { getByText, getByLabelText, getByTitle } = render(
const { queryByText, queryByLabelText, getByTitle, queryByTitle } = render(
<Chat {...getRootData()} />,
);
@ -229,16 +229,22 @@ describe('<Chat />', () => {
fireEvent.click(openToggleButton);
// // chat channels
getByTitle('Collapse channels');
getByLabelText('Toggle channel search');
getByText('all', {
selector: 'button',
});
getByText('direct', {
selector: 'button',
});
getByText('group', {
selector: 'button',
});
expect(queryByTitle('Collapse channels')).toBeDefined();
expect(queryByLabelText('Toggle channel search')).toBeDefined();
expect(
queryByText('all', {
selector: 'button',
}),
).toBeDefined();
expect(
queryByText('direct', {
selector: 'button',
}),
).toBeDefined();
expect(
queryByText('group', {
selector: 'button',
}),
).toBeDefined();
});
});

View file

@ -46,19 +46,21 @@ describe('<Content />', () => {
it('should render', () => {
const channelRequestResource = getChannelRequestData();
const { getByText, getByTitle } = render(
const { queryByText, queryByTitle } = render(
<Content resource={channelRequestResource} />,
);
// Ensure the two buttons render
getByTitle('exit');
getByTitle('fullscreen');
expect(queryByTitle('exit')).toBeDefined();
expect(queryByTitle('fullscreen')).toBeDefined();
// Simple check if the component to request joining a channel appears.
// The component itself is tested it in it's own test suite.
getByText(
'You are not a member of this group yet. Send a request to join.',
);
expect(
queryByText(
'You are not a member of this group yet. Send a request to join.',
),
).toBeDefined();
});
});
@ -73,12 +75,14 @@ describe('<Content />', () => {
it('should render', () => {
const loadinUserResource = getLoadingUserData();
const { getByTitle } = render(<Content resource={loadinUserResource} />);
const { queryByTitle } = render(
<Content resource={loadinUserResource} />,
);
// Ensure the two buttons render
getByTitle('exit');
getByTitle('fullscreen');
getByTitle('Loading user');
expect(queryByTitle('exit')).toBeDefined();
expect(queryByTitle('fullscreen')).toBeDefined();
expect(queryByTitle('Loading user')).toBeDefined();
});
});
/*

View file

@ -12,12 +12,12 @@ describe('<InviteForm />', () => {
});
it('should render with no usernames', () => {
const { getByLabelText, getByText } = render(
const { queryByLabelText, queryByText } = render(
<InviteForm invitationUsernames="" />,
);
getByLabelText('Usernames to invite');
getByText('Submit');
expect(queryByLabelText('Usernames to invite')).toBeDefined();
expect(queryByText('Submit')).toBeDefined();
});
it('should render with usernames to invite', () => {

View file

@ -12,9 +12,10 @@ describe('<LeaveMembershipSection />', () => {
});
it('should render', () => {
const { getByText } = render(<LeaveMembershipSection />);
getByText('Danger Zone');
getByText('Leave Channel');
const { queryByText } = render(<LeaveMembershipSection />);
expect(queryByText('Danger Zone')).toBeDefined();
expect(queryByText('Leave Channel')).toBeDefined();
});
it('should have user leave channel when leave button is clicked', () => {

View file

@ -146,18 +146,22 @@ describe('<Membership />', () => {
membershipType,
currentMembershipRole,
} = getMemberUser();
const { getByText } = render(
const { queryByText } = render(
<Membership
membership={membership}
membershipType={membershipType}
currentMembershipRole={currentMembershipRole}
/>,
);
getByText('+', {
selector: 'button',
});
getByText('x', {
selector: 'button',
});
expect(
queryByText('+', {
selector: 'button',
}),
).toBeDefined();
expect(
queryByText('x', {
selector: 'button',
}),
).toBeDefined();
});
});

View file

@ -12,9 +12,11 @@ describe('<ChannelDescriptionSection />', () => {
});
it('should render', () => {
const { getByText } = render(<ModFaqSection email="jane@doe.com" />);
const { queryByText } = render(<ModFaqSection email="jane@doe.com" />);
getByText(/^Questions about Connect Channel moderation\? Contact/);
getByText('jane@doe.com');
expect(
queryByText(/^Questions about Connect Channel moderation\? Contact/),
).toBeDefined();
expect(queryByText('jane@doe.com')).toBeDefined();
});
});

View file

@ -12,10 +12,12 @@ describe('<ModSection />', () => {
});
it('should render if the membership role is a moderator', () => {
const { getByTestId } = render(<ModSection currentMembershipRole="mod" />);
const { queryByTestId } = render(
<ModSection currentMembershipRole="mod" />,
);
// the <InviteForm /> and <SettingsForm /> have their own tests.
getByTestId('invite-form');
getByTestId('settings-form');
expect(queryByTestId('invite-form')).toBeDefined();
expect(queryByTestId('settings-form')).toBeDefined();
});
});

View file

@ -14,18 +14,20 @@ describe('<PersonalSettng />', () => {
});
it('should render the the component', () => {
const { getByText, getByLabelText } = render(
const { queryByText, queryByLabelText } = render(
<PersonalSettng showGlobalBadgeNotification />,
);
// get the section header
getByText('Personal Settings');
expect(queryByText('Personal Settings')).toBeDefined();
// get the subsection header
getByText('Notifications');
expect(queryByText('Notifications')).toBeDefined();
// form fields
getByLabelText('Receive Notifications for New Messages');
getByText('Submit', { selector: 'button' });
expect(
queryByLabelText('Receive Notifications for New Messages'),
).toBeDefined();
expect(queryByText('Submit', { selector: 'button' })).toBeDefined();
});
});

View file

@ -1,7 +1,7 @@
import { h } from 'preact';
import { render, waitForElement } from '@testing-library/preact';
import { axe } from 'jest-axe';
import RequestManager from '../requestManager';
import RequestManager from '../requestManager';
const data = [
{
@ -13,16 +13,23 @@ const data = [
describe('<RequestManager />', () => {
it('should have no a11y violations', async () => {
const { container } = render(
<RequestManager resource={data} handleRequestRejection={jest.fn()} handleRequestApproval={jest.fn()} />
<RequestManager
resource={data}
handleRequestRejection={jest.fn()}
handleRequestApproval={jest.fn()}
/>,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should have the proper elements', () => {
const { getByTestId, debug, getByText } = render(
<RequestManager resource={data} handleRequestRejection={jest.fn()} handleRequestApproval={jest.fn()} />
const { getByTestId, getByText } = render(
<RequestManager
resource={data}
handleRequestRejection={jest.fn()}
handleRequestApproval={jest.fn()}
/>,
);
getByText(/Joining Request/i);
@ -32,20 +39,28 @@ describe('<RequestManager />', () => {
expect(request.textContent).toContain('Accept');
});
xit('should call the relavant handlers when the buttons are clicked', async ()=> {
it.skip('should call the relavant handlers when the buttons are clicked', async () => {
const handleRequestRejection = jest.fn();
const handleRequestApproval = jest.fn();
const { getByText } = render(
<RequestManager resource={data} handleRequestRejection={jest.fn()} handleRequestApproval={jest.fn()} />
<RequestManager
resource={data}
handleRequestRejection={jest.fn()}
handleRequestApproval={jest.fn()}
/>,
);
const rejectButton = getByText(/Reject/i);
const acceptButton = getByText(/Accept/i);
rejectButton.click();
await waitForElement(() => expect(handleRequestRejection).toHaveBeenCalledTimes(1))
await waitForElement(() =>
expect(handleRequestRejection).toHaveBeenCalledTimes(1),
);
acceptButton.click();
await waitForElement(() => expect(handleRequestApproval).toHaveBeenCalledTimes(1))
})
await waitForElement(() =>
expect(handleRequestApproval).toHaveBeenCalledTimes(1),
);
});
});

View file

@ -79,14 +79,16 @@ describe('<RequestedMembershipSection />', () => {
it('should render the membership list', () => {
const { requestedMemberships, currentMembershipRole } = getMembershipData();
const { getByText } = render(
const { queryByText } = render(
<RequestedMembershipSection
requestedMemberships={requestedMemberships}
currentMembershipRole={currentMembershipRole}
/>,
);
getByText('Joining Request');
getByText('+', { selector: 'button[data-membership-id]' });
expect(queryByText('Joining Request')).toBeDefined();
expect(
queryByText('+', { selector: 'button[data-membership-id]' }),
).toBeDefined();
});
});

View file

@ -25,18 +25,18 @@ describe('<SettingsForm />', () => {
});
it('should render the the component', () => {
const { getByText, getByLabelText } = render(getSettingsForm(data));
const { queryByText, queryByLabelText } = render(getSettingsForm(data));
// title
getByText('Channel Settings');
expect(queryByText('Channel Settings')).toBeDefined();
// description of channel
getByLabelText('Description');
expect(queryByLabelText('Description')).toBeDefined();
// whether or not the channel is discoverable
getByLabelText('Channel Discoverable');
expect(queryByLabelText('Channel Discoverable')).toBeDefined();
// submit buttton
getByText('Submit');
expect(queryByText('Submit')).toBeDefined();
});
});

View file

@ -223,17 +223,20 @@ describe('<GithubRepos />', () => {
getByTitle('Loading GitHub repositories');
await waitForElement(() => getByTestId('github-repos-list'));
const repoList = await waitForElement(() =>
getByTestId('github-repos-list'),
);
// No need to test it's contents as this is the <SingleRepo /> component
// which has it's own tests.
expect(repoList).toBeDefined();
});
it('should render with no repositories', () => {
fetch.mockResponse('[]');
const { getByTitle } = render(<GithubRepos />);
const { queryByTitle } = render(<GithubRepos />);
getByTitle('Loading GitHub repositories');
expect(queryByTitle('Loading GitHub repositories')).toBeDefined();
});
it('should render error message when repositories cannot be loaded', async () => {

View file

@ -46,10 +46,10 @@ describe('<TagsFollowed />', () => {
});
it('should render the tags followed when tags are passed in', () => {
const { getByTitle } = render(<TagsFollowed tags={getTags()} />);
const { queryByTitle } = render(<TagsFollowed tags={getTags()} />);
getByTitle('javascript tag');
getByTitle('webdev tag');
getByTitle('react tag');
expect(queryByTitle('javascript tag')).toBeDefined();
expect(queryByTitle('webdev tag')).toBeDefined();
expect(queryByTitle('react tag')).toBeDefined();
});
});

View file

@ -16,11 +16,15 @@ describe('<ContactViaConnect />', () => {
it('should render a checked check box opting in to open DMs', () => {
const onChange = jest.fn();
const { getByLabelText } = render(
const { queryByLabelText } = render(
<ContactViaConnect onChange={onChange} checked />,
);
getByLabelText('Allow Users to Message Me Via In-App Chat (DEV Connect)');
expect(
queryByLabelText(
'Allow Users to Message Me Via In-App Chat (DEV Connect)',
),
).toBeDefined();
});
it('should fire a change event when clicking the checkbox', () => {

View file

@ -27,42 +27,45 @@ describe('<ListingFilterTags />', () => {
describe('should render a search field', () => {
it('should have "search" as placeholder', () => {
const { getByPlaceholderText } = renderListingFilterTags();
getByPlaceholderText(/search/i);
const { queryByPlaceholderText } = renderListingFilterTags();
expect(queryByPlaceholderText(/search/i)).toBeDefined();
});
it(`should have "${getProps().message}" as default value`, () => {
const { getByDisplayValue } = renderListingFilterTags();
getByDisplayValue(getProps().message);
const { queryByDisplayValue } = renderListingFilterTags();
expect(queryByDisplayValue(getProps().message)).toBeDefined();
});
it('should have auto-complete as off', () => {
const { getByPlaceholderText } = renderListingFilterTags();
const input = getByPlaceholderText(/search/i);
expect(input.getAttribute('autoComplete')).toBe('off');
});
});
describe('<ClearQueryButton />', () => {
it('should render the clear query button', () => {
const { getByTestId } = renderListingFilterTags();
getByTestId('clear-query-button');
const { queryByTestId } = renderListingFilterTags();
expect(queryByTestId('clear-query-button')).toBeDefined();
});
it('should not render the clear query button', () => {
const propsWithoutQuery = { ...getProps(), query: '' };
const { queryByTestId } = renderListingFilterTags(
propsWithoutQuery,
);
const { queryByTestId } = renderListingFilterTags(propsWithoutQuery);
expect(queryByTestId('clear-query-button')).toBeNull();
});
});
describe('<SelectedTags />', () => {
it('should render the selected Tags', () => {
const { getByText } = renderListingFilterTags();
const { queryByText } = renderListingFilterTags();
getTags().forEach((tag) => {
getByText(`${tag}`);
expect(queryByText(`${tag}`)).toBeDefined();
});
});
});

View file

@ -46,10 +46,11 @@ describe('<ListingFiltersCategories />', () => {
it('should be "selected" when there is no category selected', () => {
const propsWithoutCategory = { ...getProps(), category: '' };
const { getByTestId } = renderListingFilterCategories(
const { queryByTestId } = renderListingFilterCategories(
propsWithoutCategory,
);
getByTestId('selected');
expect(queryByTestId('selected')).toBeDefined();
});
it('should render a create listing link', () => {
@ -61,7 +62,9 @@ describe('<ListingFiltersCategories />', () => {
it('should render a manage listings link', () => {
const { getByText } = renderListingFilterCategories();
const manageListing = getByText(/manage listings/i);
expect(manageListing.getAttribute('href')).toContain('/listings/dashboard');
expect(manageListing.getAttribute('href')).toContain(
'/listings/dashboard',
);
});
});
@ -70,7 +73,9 @@ describe('<ListingFiltersCategories />', () => {
const { getByText } = renderListingFilterCategories();
categories.forEach((category) => {
const categoryLink = getByText(`${category.name}`);
expect(categoryLink.getAttribute('href')).toEqual(`/listings/${category.slug}`);
expect(categoryLink.getAttribute('href')).toEqual(
`/listings/${category.slug}`,
);
expect(categoryLink.textContent).toEqual(category.name);
});
});

View file

@ -25,17 +25,24 @@ const getProps = () => ({
currentUserId: 1,
message: 'Something',
onChangeDraftingMessage: jest.fn(),
onSubmit: jest.fn()
onSubmit: jest.fn(),
});
const renderMessageModal = (listing) => render(
<MessageModal {...getProps()} listing={listing} />
);
const renderMessageModal = (listing) =>
render(<MessageModal {...getProps()} listing={listing} />);
describe('<MessageModal />', () => {
it('should have no a11y violations', async () => {
const { container } = render(renderMessageModal(getDefaultListing()));
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should render a text-area', () => {
const { getByTestId } = renderMessageModal(getDefaultListing());
getByTestId('listing-new-message');
const { queryByTestId } = renderMessageModal(getDefaultListing());
expect(queryByTestId('listing-new-message')).toBeDefined();
});
describe('When the current user is the author', () => {
@ -45,13 +52,20 @@ describe('<MessageModal />', () => {
};
it('should show the information about contact with the current user', () => {
const { getByText } = renderMessageModal(listingWithCurrentUserId);
getByText('This is your active listing. Any member can contact you via this form.')
const { queryByText } = renderMessageModal(listingWithCurrentUserId);
expect(
queryByText(
'This is your active listing. Any member can contact you via this form.',
),
).toBeDefined();
});
it('should show the personalized message about the interactions', () => {
const { getByTestId } = renderMessageModal(listingWithCurrentUserId);
expect(getByTestId('personal-message-about-interactions').textContent).toEqual('All private interactions must abide by the code of conduct')
expect(
getByTestId('personal-message-about-interactions').textContent,
).toEqual('All private interactions must abide by the code of conduct');
});
});
@ -62,15 +76,25 @@ describe('<MessageModal />', () => {
};
it('should show the message to contact the author', () => {
const { getByText } = renderMessageModal(listingWithDifferentCurrentUserId);
const { queryByText } = renderMessageModal(
listingWithDifferentCurrentUserId,
);
getByText(`Contact ${listingWithDifferentCurrentUserId.author.name} via DEV Connect`);
expect(
queryByText(
`Contact ${listingWithDifferentCurrentUserId.author.name} via DEV Connect`,
),
).toBeDefined();
});
it('should show a generic message about the interactions', () => {
const { getByTestId } = renderMessageModal(listingWithDifferentCurrentUserId);
expect(getByTestId('generic-message-about-interactions').textContent).toEqual(
'Message must be relevant and on-topic with the listing. All private interactions must abide by the code of conduct'
const { getByTestId } = renderMessageModal(
listingWithDifferentCurrentUserId,
);
expect(
getByTestId('generic-message-about-interactions').textContent,
).toEqual(
'Message must be relevant and on-topic with the listing. All private interactions must abide by the code of conduct',
);
});
});

View file

@ -59,8 +59,9 @@ describe('<Modal />', () => {
...getDefaultListing(),
contact_via_connect: true,
};
const { getByTestId } = renderModal(listingWithContactViaConnectTrue);
getByTestId('listings-message-modal');
const { queryByTestId } = renderModal(listingWithContactViaConnectTrue);
expect(queryByTestId('listings-message-modal')).toBeDefined();
});
it('should not render the MessageModal when the listing.contact_via_connect is false', () => {

View file

@ -17,8 +17,9 @@ describe('<ModalBackground />', () => {
});
it('should render', () => {
const { getByTestId } = render(<ModalBackground {...defaultProps} />);
getByTestId('listings-modal-background');
const { queryByTestId } = render(<ModalBackground {...defaultProps} />);
expect(queryByTestId('listings-modal-background')).toBeDefined();
});
it('should call the onClick handler', () => {

View file

@ -18,13 +18,14 @@ describe('<NextPageButton />', () => {
});
it('should show a button', () => {
const {getByText} = render(<NextPageButton {...defaultProps} />);
getByText(/load more listings/i);
const { queryByText } = render(<NextPageButton {...defaultProps} />);
expect(queryByText(/load more listings/i)).toBeDefined();
});
it('should call the onclick handler', () => {
const onClick = jest.fn();
const {getByText} = render(<NextPageButton onClick={onClick} />);
const { getByText } = render(<NextPageButton onClick={onClick} />);
const button = getByText(/load more listings/i);
button.click();

View file

@ -20,15 +20,16 @@ describe('<SelectedTags />', () => {
});
it('should render all the selected tags', () => {
const { getByText } = renderSelectedTags();
tags.forEach(tag => {
getByText(tag);
const { queryByText } = renderSelectedTags();
tags.forEach((tag) => {
expect(queryByText(tag)).toBeDefined();
});
});
it('should show the relevant links for each tag', () => {
const { getByText } = renderSelectedTags();
tags.forEach(tag => {
tags.forEach((tag) => {
expect(getByText(tag).closest('a').href).toContain(`/listings?t=${tag}`);
});
});
@ -36,10 +37,17 @@ describe('<SelectedTags />', () => {
it('should remove a tag', async () => {
const onRemoveTag = jest.fn();
const onKeyPress = jest.fn();
const { getAllByText, queryByText, debug } = render(<SelectedTags tags={tags} onKeyPress={onKeyPress} onRemoveTag={onRemoveTag} />);
const { getAllByText } = render(
<SelectedTags
tags={tags}
onKeyPress={onKeyPress}
onRemoveTag={onRemoveTag}
/>,
);
const firstTagX = getAllByText('×')[0];
firstTagX.click();
expect(onRemoveTag).toHaveBeenCalledTimes(1);
});
});

View file

@ -24,22 +24,23 @@ const listing = {
};
describe('<SingleListing />', () => {
const renderSingleListing = () => render(
<SingleListing
onAddTag={() => {
return 'onAddTag';
}}
onChangeCategory={() => {
return 'onChangeCategory';
}}
listing={listing}
currentUserId={1}
onOpenModal={() => {
return 'onOpenModal';
}}
isOpen={false}
/>
);
const renderSingleListing = () =>
render(
<SingleListing
onAddTag={() => {
return 'onAddTag';
}}
onChangeCategory={() => {
return 'onChangeCategory';
}}
listing={listing}
currentUserId={1}
onOpenModal={() => {
return 'onOpenModal';
}}
isOpen={false}
/>,
);
it('should have no a11y violations', async () => {
const { container } = renderSingleListing();
@ -48,14 +49,15 @@ describe('<SingleListing />', () => {
});
it('shows a listing title', () => {
const { getByText } = renderSingleListing();
getByText('Illo iure quos perspiciatis.');
const { queryByText } = renderSingleListing();
expect(queryByText('Illo iure quos perspiciatis.')).toBeDefined();
});
it('shows a dropdown', () => {
const { getByLabelText, getByText } = renderSingleListing();
const dropdownButton = getByLabelText(/toggle dropdown menu/i);
getByText(/report abuse/i);
const { queryByLabelText, queryByText } = renderSingleListing();
expect(queryByLabelText(/toggle dropdown menu/i)).toBeDefined();
expect(queryByText(/report abuse/i)).toBeDefined();
});
it('shows a listing tags', () => {
@ -73,11 +75,15 @@ describe('<SingleListing />', () => {
it('shows a listing author', () => {
const { getByText } = renderSingleListing();
expect(getByText('Mrs. Yoko Christiansen').href).toContain(`/mrschristiansenyoko`);
expect(getByText('Mrs. Yoko Christiansen').href).toContain(
`/mrschristiansenyoko`,
);
});
it('shows a listing location', () => {
const { getByTestId } = renderSingleListing();
expect(getByTestId('single-listing-location').href).toContain(`/listings/?q=West%20Refugio`);
expect(getByTestId('single-listing-location').href).toContain(
`/listings/?q=West%20Refugio`,
);
});
});

View file

@ -36,38 +36,48 @@ describe('<SingleArticle />', () => {
});
it('renders the article title', () => {
const { getByText } = renderSingleArticle();
getByText(testArticle.title);
const { queryByText } = renderSingleArticle();
expect(queryByText(testArticle.title)).toBeDefined();
});
it('renders the tags', () => {
const { getByText } = renderSingleArticle();
getByText('discuss');
getByText('javascript');
getByText('beginners');
const { queryByText } = renderSingleArticle();
expect(queryByText('discuss')).toBeDefined();
expect(queryByText('javascript')).toBeDefined();
expect(queryByText('beginners')).toBeDefined();
});
it('renders the author name', () => {
const { container } = renderSingleArticle();
const text = getNodeText(container.querySelector('.article-author'));
expect(text).toContain(testArticle.user.name);
});
it('renders the hand wave emoji if the author has less than 3 articles ', () => {
const { container } = renderSingleArticle();
const text = getNodeText(container.querySelector('.article-author'));
expect(text).toContain('👋');
});
it('renders the correct formatted published date', () => {
const { getByText } = renderSingleArticle();
getByText('Jun 22');
const { queryByText } = renderSingleArticle();
expect(queryByText('Jun 22')).toBeDefined();
});
it('renders the correct formatted published date as a time if the date is the same day', () => {
const today = new Date();
today.setSeconds('00');
testArticle.publishedAt = today.toISOString();
const { getByText } = renderSingleArticle(testArticle);
const { queryByText } = renderSingleArticle(testArticle);
const readableTime = today.toLocaleTimeString().replace(':00 ', ' '); // looks like 8:05 PM
getByText(readableTime);
expect(queryByText(readableTime)).toBeDefined();
});
it('renders the iframes on click', () => {
const { container } = renderSingleArticle();
container.querySelector('button.moderation-single-article').click();
@ -80,6 +90,7 @@ describe('<SingleArticle />', () => {
`${testArticle.path}/actions_panel`,
);
});
it('adds the opened class when opening an article', () => {
const toggleArticle = jest.fn();
const { container } = render(
@ -96,6 +107,7 @@ describe('<SingleArticle />', () => {
fireEvent.click(
container.querySelector('button.moderation-single-article'),
);
expect(
container.querySelector('.article-iframes-container').classList,
).toContain('opened');

View file

@ -10,17 +10,17 @@ global.fetch = fetch;
// NOTE: the navigation and behaviour per component is tested in each components unit test. This file simply tests the ability to move forward and backward in a modal, and can probably be replaced by an end to end test at some point.
describe('<Onboarding />', () => {
const renderOnboarding = () => render(
<Onboarding
communityConfig={{
communityName: 'Community Name',
communityLogo: '/x.png',
communityBackground: '/y.jpg',
communityDescription: "Some community description",
}}
/>,
)
const renderOnboarding = () =>
render(
<Onboarding
communityConfig={{
communityName: 'Community Name',
communityLogo: '/x.png',
communityBackground: '/y.jpg',
communityDescription: 'Some community description',
}}
/>,
);
const getUserData = () =>
JSON.stringify({
followed_tag_names: ['javascript'],
@ -29,10 +29,10 @@ describe('<Onboarding />', () => {
username: 'username',
});
const fakeEmptyResponse = JSON.stringify([]);
const { location } = window;
beforeAll(() => {
document.head.innerHTML = '<meta name="csrf-token" content="some-csrf-token" />';
document.head.innerHTML =
'<meta name="csrf-token" content="some-csrf-token" />';
document.body.setAttribute('data-user', getUserData());
});
@ -43,13 +43,15 @@ describe('<Onboarding />', () => {
});
it('should render the IntroSlide first', () => {
const { getByTestId } = renderOnboarding();
getByTestId('onboarding-intro-slide');
const { queryByTestId } = renderOnboarding();
expect(queryByTestId('onboarding-intro-slide')).toBeDefined();
});
it('should allow the modal to move forward and backward a step where relevant', async () => {
// combined back and forward into one test to avoid a long test running time
const { getByTestId, getByText } = renderOnboarding();
getByTestId('onboarding-intro-slide');
fetch.mockResponseOnce({});
@ -59,26 +61,24 @@ describe('<Onboarding />', () => {
termsCheckbox.click();
// click to next step
const nextButton = await waitForElement(() =>
getByText(/continue/i),
);
const nextButton = await waitForElement(() => getByText(/continue/i));
fetch.mockResponse(fakeEmptyResponse);
nextButton.click();
// we should be on the Follow tags step
await waitForElement(() =>
getByTestId('onboarding-follow-tags'),
);
await waitForElement(() => getByTestId('onboarding-follow-tags'));
// click a step back
const backButton = getByTestId('back-button')
const backButton = getByTestId('back-button');
backButton.click();
// we should be on the Intro Slide step
await waitForElement(() =>
const introSlide = await waitForElement(() =>
getByTestId('onboarding-intro-slide'),
);
expect(introSlide).toBeDefined();
});
it("should skip the step when 'Skip for now' is clicked", async () => {
@ -92,30 +92,32 @@ describe('<Onboarding />', () => {
termsCheckbox.click();
// click to next step
const nextButton = await waitForElement(() =>
getByText(/continue/i),
);
const nextButton = await waitForElement(() => getByText(/continue/i));
fetch.mockResponse(fakeEmptyResponse);
nextButton.click();
// we should be on the Follow tags step
await waitForElement(() =>
const followTagsStep = await waitForElement(() =>
getByTestId('onboarding-follow-tags'),
);
expect(followTagsStep).toBeDefined();
// click on skip for now
const skipButton = getByText(/Skip for now/i);
skipButton.click();
// we should be on the Profile Form step
await waitForElement(() =>
const profileStep = await waitForElement(() =>
getByTestId('onboarding-profile-form'),
);
})
it("should redirect the users to the correct steps every time", async () => {
const { getByTestId, getByText, debug } = renderOnboarding();
expect(profileStep).toBeDefined();
});
it('should redirect the users to the correct steps every time', async () => {
const { getByTestId, getByText } = renderOnboarding();
getByTestId('onboarding-intro-slide');
fetch.mockResponseOnce({});
@ -125,26 +127,20 @@ describe('<Onboarding />', () => {
termsCheckbox.click();
// click to next step
const nextButton = await waitForElement(() =>
getByText(/continue/i),
);
const nextButton = await waitForElement(() => getByText(/continue/i));
fetch.mockResponse(fakeEmptyResponse);
nextButton.click();
// we should be on the Follow tags step
await waitForElement(() =>
getByTestId('onboarding-follow-tags'),
);
await waitForElement(() => getByTestId('onboarding-follow-tags'));
// click on skip for now
let skipButton = getByText(/Skip for now/i);
skipButton.click();
// we should be on the Profile Form step
await waitForElement(() =>
getByTestId('onboarding-profile-form'),
);
await waitForElement(() => getByTestId('onboarding-profile-form'));
// click on skip for now
skipButton = getByText(/Skip for now/i);
@ -152,9 +148,7 @@ describe('<Onboarding />', () => {
skipButton.click();
// we should be on the Follow Users step
await waitForElement(() =>
getByTestId('onboarding-follow-users'),
);
await waitForElement(() => getByTestId('onboarding-follow-users'));
// click on skip for now
skipButton = getByText(/Skip for now/i);
@ -177,10 +171,8 @@ describe('<Onboarding />', () => {
const finishButton = getByText(/Finish/i);
finishButton.click();
const href = window.location.href
expect(href).toEqual(url);
const { href } = window.location;
// TODO: we should be redirected to '/'
// await waitForElement(() => expect(href).toEqual('/'));
expect(href).toEqual(url);
});
});

View file

@ -47,31 +47,37 @@ describe('EmailPreferencesForm', () => {
});
it('should load the appropriate text', () => {
const { getByText } = renderEmailPreferencesForm();
const { queryByText } = renderEmailPreferencesForm();
getByText(/almost there!/i);
getByText(/review your email preferences before we continue./i);
getByText('Email preferences');
expect(queryByText(/almost there!/i)).toBeDefined();
expect(
queryByText(/review your email preferences before we continue./i),
).toBeDefined();
expect(queryByText('Email preferences')).toBeDefined();
});
it('should show the two checkboxes', () => {
const { getByLabelText } = renderEmailPreferencesForm();
getByLabelText(/receive weekly newsletter/i);
getByLabelText(/receive a periodic digest/i);
const { queryByLabelText } = renderEmailPreferencesForm();
expect(queryByLabelText(/receive weekly newsletter/i)).toBeDefined();
expect(queryByLabelText(/receive a periodic digest/i)).toBeDefined();
});
it('should render a stepper', () => {
const { queryByTestId } = renderEmailPreferencesForm();
queryByTestId('stepper');
expect(queryByTestId('stepper')).toBeDefined();
});
it('should render a back button', () => {
const { getByTestId } = renderEmailPreferencesForm();
getByTestId('back-button');
const { queryByTestId } = renderEmailPreferencesForm();
expect(queryByTestId('back-button')).toBeDefined();
});
it('should render a button that says Finish', () => {
const { getByText } = renderEmailPreferencesForm();
getByText('Finish');
const { queryByText } = renderEmailPreferencesForm();
expect(queryByText('Finish')).toBeDefined();
});
});

View file

@ -8,21 +8,22 @@ import FollowTags from '../FollowTags';
global.fetch = fetch;
describe('FollowTags', () => {
const renderFollowTags = () => render(
<FollowTags
next={jest.fn()}
prev={jest.fn()}
currentSlideIndex={1}
slidesCount={5}
communityConfig={{
communityName: 'Community Name',
communityLogo: '/x.png',
communityBackground: '/y.jpg',
communityDescription: "Some community description",
}}
previousLocation={null}
/>
);
const renderFollowTags = () =>
render(
<FollowTags
next={jest.fn()}
prev={jest.fn()}
currentSlideIndex={1}
slidesCount={5}
communityConfig={{
communityName: 'Community Name',
communityLogo: '/x.png',
communityBackground: '/y.jpg',
communityDescription: 'Some community description',
}}
previousLocation={null}
/>,
);
const getUserData = () =>
JSON.stringify({
@ -54,7 +55,8 @@ describe('FollowTags', () => {
]);
beforeAll(() => {
document.head.innerHTML = '<meta name="csrf-token" content="some-csrf-token" />';
document.head.innerHTML =
'<meta name="csrf-token" content="some-csrf-token" />';
document.body.setAttribute('data-user', getUserData());
});
@ -72,17 +74,17 @@ describe('FollowTags', () => {
it('should render the correct navigation button on first load', () => {
fetch.mockResponseOnce(fakeTagsResponse);
const { getByText } = renderFollowTags();
getByText(/skip for now/i);
const { queryByText } = renderFollowTags();
expect(queryByText(/skip for now/i)).toBeDefined();
});
it('should update the navigation button text, follow status and count when you follow a tag', async () => {
fetch.mockResponse(fakeTagsResponse);
const { getByText, findByText, findAllByText, getByTestId } = renderFollowTags();
const followButtons = await waitForElement(() =>
findAllByText('Follow'),
);
const { queryByText, findByText, findAllByText } = renderFollowTags();
const followButtons = await waitForElement(() => findAllByText('Follow'));
findByText(/skip for now/);
// click on the first follow button
@ -90,20 +92,21 @@ describe('FollowTags', () => {
button.click();
// it should change to Following and update the count
await waitForElement(() =>
findByText(/Following/i),
);
getByText(/1 tag selected/i);
getByText(/continue/i);
await waitForElement(() => findByText(/Following/i));
expect(queryByText(/1 tag selected/i)).toBeDefined();
expect(queryByText(/continue/i)).toBeDefined();
});
it('should render a stepper', () => {
const { getByTestId } = renderFollowTags();
getByTestId('stepper');
const { queryByTestId } = renderFollowTags();
expect(queryByTestId('stepper')).toBeDefined();
});
it('should render a back button', () => {
const { getByTestId } = renderFollowTags();
getByTestId('back-button');
const { queryByTestId } = renderFollowTags();
expect(queryByTestId('back-button')).toBeDefined();
});
});

View file

@ -3,8 +3,8 @@ import { render, waitForElement } from '@testing-library/preact';
import fetch from 'jest-fetch-mock';
import '@testing-library/jest-dom';
import FollowUsers from '../FollowUsers';
import { axe } from 'jest-axe';
import FollowUsers from '../FollowUsers';
global.fetch = fetch;
@ -81,20 +81,22 @@ describe('FollowUsers', () => {
});
it('should render the correct navigation button on first load', () => {
const { getByText } = renderFollowUsers();
getByText(/skip for now/i);
const { queryByText } = renderFollowUsers();
expect(queryByText(/skip for now/i)).toBeDefined();
});
it('should update the navigation button text and follow status when you follow users', async () => {
fetch.mockResponse(fakeUsersResponse);
const { getByText, findByText, findAllByTestId } = renderFollowUsers();
const { queryByText, findByText, findAllByTestId } = renderFollowUsers();
const userButtons = await waitForElement(() =>
findAllByTestId('onboarding-user-button'),
);
getByText(/skip for now/i);
getByText("You're not following anyone");
expect(queryByText(/skip for now/i)).toBeDefined();
expect(queryByText("You're not following anyone")).toBeDefined();
// follow the first user
const firstUser = userButtons[0];
@ -102,8 +104,8 @@ describe('FollowUsers', () => {
await waitForElement(() => findByText('Following'));
getByText("You're following 1 person");
getByText(/continue/i);
expect(queryByText("You're following 1 person")).toBeDefined();
expect(queryByText(/continue/i)).toBeDefined();
// follow the second user
const secondUser = userButtons[1];
@ -111,8 +113,8 @@ describe('FollowUsers', () => {
await waitForElement(() => findByText('Following'));
getByText("You're following 2 people");
getByText(/continue/i);
expect(queryByText("You're following 2 people")).toBeDefined();
expect(queryByText(/continue/i)).toBeDefined();
});
it('should have a functioning de/select all toggle', async () => {
@ -144,12 +146,14 @@ describe('FollowUsers', () => {
});
it('should render a stepper', () => {
const { getByTestId } = renderFollowUsers();
getByTestId('stepper');
const { queryByTestId } = renderFollowUsers();
expect(queryByTestId('stepper')).toBeDefined();
});
it('should render a back button', () => {
const { getByTestId } = renderFollowUsers();
getByTestId('back-button');
const { queryByTestId } = renderFollowUsers();
expect(queryByTestId('back-button')).toBeDefined();
});
});

View file

@ -57,9 +57,10 @@ describe('ProfileForm', () => {
});
it('should show the correct name and username', () => {
const { getByText } = renderProfileForm();
getByText('username');
getByText('firstname lastname');
const { queryByText } = renderProfileForm();
expect(queryByText('username')).toBeDefined();
expect(queryByText('firstname lastname')).toBeDefined();
});
it('should show the correct profile picture', () => {
@ -100,13 +101,15 @@ describe('ProfileForm', () => {
});
it('should render a stepper', () => {
const { getByTestId } = renderProfileForm();
getByTestId('stepper');
const { queryByTestId } = renderProfileForm();
expect(queryByTestId('stepper')).toBeDefined();
});
it('should show the back button', () => {
const { getByTestId } = renderProfileForm();
getByTestId('back-button');
const { queryByTestId } = renderProfileForm();
expect(queryByTestId('back-button')).toBeDefined();
});
it('should update the text on the forward button', async () => {

View file

@ -58,7 +58,7 @@ describe('<OrganizationPicker />', () => {
});
it('renders an organization list with only "None" as an option when no organizations are passed in.', () => {
const { getByText } = render(
const { queryByText } = render(
<OrganizationPicker
{...commonProps}
organizationId={undefined}
@ -66,6 +66,6 @@ describe('<OrganizationPicker />', () => {
/>,
);
getByText('None');
expect(queryByText('None')).toBeDefined();
});
});

View file

@ -67,14 +67,14 @@ describe('<ReadingList />', () => {
});
it('renders all the elements', () => {
const { getByPlaceholderText, getByText } = render(
const { queryByPlaceholderText, queryByText } = render(
<ReadingList availableTags={['discuss']} />,
);
getByPlaceholderText('search your list');
getByText('#discuss');
getByText('View Archive');
getByText('Your Archive List is Lonely');
getByText('Reading List (empty)');
expect(queryByPlaceholderText('search your list')).toBeDefined();
expect(queryByText('#discuss')).toBeDefined();
expect(queryByText('View Archive')).toBeDefined();
expect(queryByText('Your Archive List is Lonely')).toBeDefined();
expect(queryByText('Reading List (empty)')).toBeDefined();
});
});

View file

@ -4,89 +4,113 @@ import { axe } from 'jest-axe';
import { ItemListItem } from '../ItemListItem';
import '../../../../assets/javascripts/lib/xss';
const item = {
reactable: {
path: '/article',
title: 'Title',
published_date_string: 'Jun 29',
reading_time: 1,
user: {
username: 'bob',
profile_image_90: 'https://dummyimage.com/90x90',
name: 'Bob',
function getItem() {
return {
reactable: {
path: '/article',
title: 'Title',
published_date_string: 'Jun 29',
reading_time: 1,
user: {
username: 'bob',
profile_image_90: 'https://dummyimage.com/90x90',
name: 'Bob',
},
tags: [{ name: 'discuss' }],
},
tags: [{ name: 'discuss' }],
},
};
};
}
describe('<ItemListItem />', () => {
it('should have no a11y violations', async () => {
const { container } = render(<ItemListItem item={item} />);
const { container } = render(<ItemListItem item={getItem()} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('renders the title', () => {
const { getByText } = render(<ItemListItem item={item} />);
getByText(/Title/i);
const { queryByText } = render(<ItemListItem item={getItem()} />);
expect(queryByText(/Title/i)).toBeDefined();
});
it('renders the path', () => {
const { getByText } = render(<ItemListItem item={item} />);
const { getByText } = render(<ItemListItem item={getItem()} />);
expect(getByText(/Title/i).closest('a').getAttribute('href')).toBe(
'/article',
);
});
it('renders a published date', () => {
const { getByText } = render(<ItemListItem item={item} />);
getByText(/Jun 29/i);
const { queryByText } = render(<ItemListItem item={getItem()} />);
expect(queryByText(/Jun 29/i)).toBeDefined();
});
it('renders a profile_image', () => {
const { getByAltText } = render(<ItemListItem item={item} />);
const { getByAltText } = render(<ItemListItem item={getItem()} />);
expect(getByAltText(/Profile Pic/i).getAttribute('src')).toBe(
'https://dummyimage.com/90x90',
);
});
it('renders with readingtime of 1 min if reading time is less than 1 min.', () => {
const item = getItem();
item.reactable.reading_time = 0.5;
const { getByText } = render(<ItemListItem item={item} />);
getByText(/1 min read/i);
const { queryByText } = render(<ItemListItem item={item} />);
expect(queryByText(/1 min read/i)).toBeDefined();
});
it('renders with readingtime of 1 min if reading time is null.', () => {
const item = getItem();
item.reactable.reading_time = null;
const { getByText } = render(<ItemListItem item={item} />);
getByText(/1 min read/i);
const { queryByText } = render(<ItemListItem item={item} />);
expect(queryByText(/1 min read/i)).toBeDefined();
});
it('renders correct readingtime.', () => {
const item = getItem();
item.reactable.reading_time = 10;
const { getByText } = render(<ItemListItem item={item} />);
getByText(/10 min read/i);
const { queryByText } = render(<ItemListItem item={item} />);
expect(queryByText(/10 min read/i)).toBeDefined();
});
it('renders without any tags if the tags array is empty.', () => {
const item = getItem();
item.reactable.tags = [];
const { queryByTestId } = render(<ItemListItem item={item} />);
expect(queryByTestId('item-tags')).toBeNull();
});
it('renders tags with links if present.', () => {
const item = getItem();
item.reactable.tags = [{ name: 'discuss' }];
const { getByText } = render(<ItemListItem item={item} />);
getByText('#discuss');
expect(getByText('#discuss').closest('a').getAttribute('href')).toBe(
'/t/discuss',
);
});
it('renders user information', () => {
const { getByText } = render(<ItemListItem item={item} />);
const { getByText } = render(<ItemListItem item={getItem()} />);
getByText(/Bob/i);
expect(getByText(/Bob/i).closest('a').getAttribute('href')).toBe('/bob');
});
});

View file

@ -12,8 +12,11 @@ describe('<ItemListItemArchiveButton />', () => {
});
it('renders the Archive button', () => {
const { getByText } = render(<ItemListItemArchiveButton text="archive" />);
getByText(/archive/i);
const { queryByText } = render(
<ItemListItemArchiveButton text="archive" />,
);
expect(queryByText(/archive/i)).toBeDefined();
});
it('triggers the onClick if the Enter key is pressed', () => {

View file

@ -24,7 +24,8 @@ describe('<ItemListLoadMoreButton />', () => {
});
it('renders a button when required', () => {
const { getByText } = render(<ItemListLoadMoreButton show={true} />);
getByText(/load more/i);
const { queryByText } = render(<ItemListLoadMoreButton show={true} />);
expect(queryByText(/load more/i)).toBeDefined();
});
});

View file

@ -41,15 +41,15 @@ describe('<ItemListTags />', () => {
});
it('renders properly with some shared tags', () => {
const { getByText } = render(
const { queryByText } = render(
<ItemListTags
availableTags={['discuss', 'javascript']}
selectedTags={['javascript']}
/>,
);
getByText('#discuss');
getByText('#javascript');
expect(queryByText('#discuss')).toBeDefined();
expect(queryByText('#javascript')).toBeDefined();
});
it('triggers the onClick', () => {

View file

@ -3,36 +3,42 @@ import { render } from '@testing-library/preact';
import { axe } from 'jest-axe';
import SidebarUser from '../sidebarUser';
const user = {
id: 1234,
username: 'john_doe',
name: 'Jon Doe',
profile_image_url: 'www.profile.com',
};
const followUser = jest.fn();
const renderedSideBar = (props) =>
render(
<SidebarUser
key={user.id}
user={user}
followUser={followUser}
index={0}
{...props}
/>,
);
function getUser() {
return {
id: 1234,
username: 'john_doe',
name: 'Jon Doe',
profile_image_url: 'www.profile.com',
};
}
describe('<SidebarUser />', () => {
it('should have no a11y violations', async () => {
const { container } = render(renderedSideBar());
const user = getUser();
const { container } = render(
<SidebarUser
key={user.id}
user={user}
followUser={jest.fn()}
index={0}
/>,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('renders properly', () => {
const { getByTestId, getByText, getByAltText } = renderedSideBar();
const user = getUser();
const { getByTestId, getByText, getByAltText } = render(
<SidebarUser
key={user.id}
user={user}
followUser={jest.fn()}
index={0}
/>,
);
expect(getByTestId('widget-avatar').getAttribute('href')).toEqual(
'/john_doe',
@ -47,7 +53,17 @@ describe('<SidebarUser />', () => {
});
it('triggers the onClick', () => {
const { getByTestId } = renderedSideBar();
const user = getUser();
const followUser = jest.fn();
const { getByTestId } = render(
<SidebarUser
key={user.id}
user={user}
followUser={followUser}
index={0}
/>,
);
getByTestId('widget-follow-button').click();
expect(followUser).toHaveBeenCalled();
@ -55,13 +71,35 @@ describe('<SidebarUser />', () => {
describe('following', () => {
it('shows if the user is followed', () => {
const { getByText } = renderedSideBar({ user: { following: true } });
getByText(/Following/i);
const user = getUser();
user.following = true;
const { queryByText } = render(
<SidebarUser
key={user.id}
user={user}
followUser={jest.fn()}
index={0}
/>,
);
expect(queryByText(/Following/i)).toBeDefined();
});
it('shows if the user can be followed', () => {
const { getByText } = renderedSideBar({ user: { following: false } });
getByText(/follow/i);
const user = getUser();
user.following = false;
const { queryByText } = render(
<SidebarUser
key={user.id}
user={user}
followUser={jest.fn()}
index={0}
/>,
);
expect(queryByText(/follow/i)).toBeDefined();
});
});
});

View file

@ -18,10 +18,10 @@ module.exports = {
],
coverageThreshold: {
global: {
statements: 40,
statements: 41,
branches: 35,
functions: 39,
lines: 41,
lines: 42,
},
},
moduleNameMapper: {