chore(eslint): enables recommended eslint rules for testing-library and jest-dom (#42817)

This commit is contained in:
Anirudh Modi
2021-07-20 19:51:16 +05:30
committed by GitHub
parent a368e7f277
commit ef3b7ec955
20 changed files with 184 additions and 163 deletions

View File

@ -57,7 +57,7 @@
"plugins": ["@typescript-eslint"] "plugins": ["@typescript-eslint"]
}, },
{ {
"files": ["./tools/ui-components/**/*.test.[jt]s?(x)"], "files": ["./tools/ui-components/**/*.test.[jt]s?(x)", "./client/**/*.test.[jt]s?(x)"],
"extends": ["plugin:testing-library/react", "plugin:jest-dom/recommended"] "extends": ["plugin:testing-library/react", "plugin:jest-dom/recommended"]
} }
] ]

View File

@ -25,8 +25,8 @@ describe('<UniversalNav />', () => {
it('renders to the DOM', () => { it('renders to the DOM', () => {
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<UniversalNav {...UniversalNavProps} />); shallow.render(<UniversalNav {...UniversalNavProps} />);
const result = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect(result).toBeTruthy(); expect(view).toBeTruthy();
}); });
}); });
@ -48,14 +48,14 @@ describe('<NavLinks />', () => {
}; };
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<NavLinks {...landingPageProps} />); shallow.render(<NavLinks {...landingPageProps} />);
const result = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect( expect(
hasDonateNavItem(result) && hasDonateNavItem(view) &&
hasSignInNavItem(result) && hasSignInNavItem(view) &&
hasCurriculumNavItem(result) && hasCurriculumNavItem(view) &&
hasForumNavItem(result) && hasForumNavItem(view) &&
hasNewsNavItem(result) && hasNewsNavItem(view) &&
hasRadioNavItem(result) hasRadioNavItem(view)
).toBeTruthy(); ).toBeTruthy();
}); });
@ -76,15 +76,15 @@ describe('<NavLinks />', () => {
}; };
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<NavLinks {...landingPageProps} />); shallow.render(<NavLinks {...landingPageProps} />);
const result = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect( expect(
hasDonateNavItem(result) && hasDonateNavItem(view) &&
hasCurriculumNavItem(result) && hasCurriculumNavItem(view) &&
hasProfileAndSettingsNavItems(result, landingPageProps.user.username) && hasProfileAndSettingsNavItems(view, landingPageProps.user.username) &&
hasForumNavItem(result) && hasForumNavItem(view) &&
hasNewsNavItem(result) && hasNewsNavItem(view) &&
hasRadioNavItem(result) && hasRadioNavItem(view) &&
hasSignOutNavItem(result) hasSignOutNavItem(view)
).toBeTruthy(); ).toBeTruthy();
}); });
@ -105,15 +105,15 @@ describe('<NavLinks />', () => {
}; };
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<NavLinks {...landingPageProps} />); shallow.render(<NavLinks {...landingPageProps} />);
const result = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect( expect(
hasThanksForDonating(result) && hasThanksForDonating(view) &&
hasCurriculumNavItem(result) && hasCurriculumNavItem(view) &&
hasProfileAndSettingsNavItems(result, landingPageProps.user.username) && hasProfileAndSettingsNavItems(view, landingPageProps.user.username) &&
hasForumNavItem(result) && hasForumNavItem(view) &&
hasNewsNavItem(result) && hasNewsNavItem(view) &&
hasRadioNavItem(result) && hasRadioNavItem(view) &&
hasSignOutNavItem(result) hasSignOutNavItem(view)
).toBeTruthy(); ).toBeTruthy();
}); });
}); });
@ -131,8 +131,8 @@ describe('<AuthOrProfile />', () => {
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<AuthOrProfile {...defaultUserProps} />); shallow.render(<AuthOrProfile {...defaultUserProps} />);
const componentTree = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect(avatarHasClass(componentTree, 'default-border')).toBeTruthy(); expect(avatarHasClass(view, 'default-border')).toBeTruthy();
}); });
it('has avatar with gold border for donating users', () => { it('has avatar with gold border for donating users', () => {
@ -147,9 +147,9 @@ describe('<AuthOrProfile />', () => {
}; };
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<AuthOrProfile {...donatingUserProps} />); shallow.render(<AuthOrProfile {...donatingUserProps} />);
const componentTree = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect(avatarHasClass(componentTree, 'gold-border')).toBeTruthy(); expect(avatarHasClass(view, 'gold-border')).toBeTruthy();
}); });
it('has avatar with blue border for top contributors', () => { it('has avatar with blue border for top contributors', () => {
@ -165,9 +165,9 @@ describe('<AuthOrProfile />', () => {
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<AuthOrProfile {...topContributorUserProps} />); shallow.render(<AuthOrProfile {...topContributorUserProps} />);
const componentTree = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect(avatarHasClass(componentTree, 'blue-border')).toBeTruthy(); expect(avatarHasClass(view, 'blue-border')).toBeTruthy();
}); });
it('has avatar with purple border for donating top contributors', () => { it('has avatar with purple border for donating top contributors', () => {
const topDonatingContributorUserProps = { const topDonatingContributorUserProps = {
@ -182,8 +182,8 @@ describe('<AuthOrProfile />', () => {
}; };
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<AuthOrProfile {...topDonatingContributorUserProps} />); shallow.render(<AuthOrProfile {...topDonatingContributorUserProps} />);
const componentTree = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect(avatarHasClass(componentTree, 'purple-border')).toBeTruthy(); expect(avatarHasClass(view, 'purple-border')).toBeTruthy();
}); });
}); });

View File

@ -16,7 +16,19 @@ describe('<Intro />', () => {
const container = rendererCreateWithRedux( const container = rendererCreateWithRedux(
<Intro {...loggedOutProps} /> <Intro {...loggedOutProps} />
).root; ).root;
/**
* This rules had to be disabled because the new lint rules are throwing false positives here.
* They were interpreting react-test-renderer functions as @testing-library/react functions.
*/
// eslint-disable-next-line testing-library/await-async-query
expect(container.findAllByType('blockquote').length === 0).toBeTruthy(); expect(container.findAllByType('blockquote').length === 0).toBeTruthy();
/**
* This rules had to be disabled because the new lint rules are throwing false positives here.
* They were interpreting react-test-renderer functions as @testing-library/react functions.
*/
// eslint-disable-next-line testing-library/await-async-query
expect(container.findAllByType('h1').length === 1).toBeTruthy(); expect(container.findAllByType('h1').length === 1).toBeTruthy();
}); });
@ -24,7 +36,19 @@ describe('<Intro />', () => {
const container = rendererCreateWithRedux( const container = rendererCreateWithRedux(
<Intro {...loggedInProps} /> <Intro {...loggedInProps} />
).root; ).root;
/**
* This rules had to be disabled because the new lint rules are throwing false positives here.
* They were interpreting react-test-renderer functions as @testing-library/react functions.
*/
// eslint-disable-next-line testing-library/await-async-query
expect(container.findAllByType('blockquote').length === 1).toBeTruthy(); expect(container.findAllByType('blockquote').length === 1).toBeTruthy();
/**
* This rules had to be disabled because the new lint rules are throwing false positives here.
* They were interpreting react-test-renderer functions as @testing-library/react functions.
*/
// eslint-disable-next-line testing-library/await-async-query
expect(container.findAllByType('h1').length === 1).toBeTruthy(); expect(container.findAllByType('h1').length === 1).toBeTruthy();
}); });
}); });

View File

@ -42,6 +42,7 @@ describe('AppMountNotifier', () => {
setup(langCode); setup(langCode);
await waitFor(() => { await waitFor(() => {
/* eslint-disable-next-line testing-library/no-node-access */
expect(document.querySelector('html')).toHaveAttribute( expect(document.querySelector('html')).toHaveAttribute(
'lang', 'lang',
langCode langCode

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { render, fireEvent } from '@testing-library/react'; import { render, fireEvent, screen } from '@testing-library/react';
import Form from './Form'; import Form from './Form';
@ -21,17 +21,17 @@ const defaultTestProps = {
}; };
test('should render', () => { test('should render', () => {
const { getByLabelText, getByText } = render(<Form {...defaultTestProps} />); render(<Form {...defaultTestProps} />);
const nameInput = getByLabelText(/name Label/); const nameInput = screen.getByLabelText(/name Label/);
expect(nameInput).not.toBeRequired(); expect(nameInput).not.toBeRequired();
expect(nameInput).toHaveAttribute('type', 'text'); expect(nameInput).toHaveAttribute('type', 'text');
const websiteInput = getByLabelText(/WebSite label/); const websiteInput = screen.getByLabelText(/WebSite label/);
expect(websiteInput).toBeRequired(); expect(websiteInput).toBeRequired();
expect(websiteInput).toHaveAttribute('type', 'url'); expect(websiteInput).toHaveAttribute('type', 'url');
const button = getByText(/submit/i); const button = screen.getByText(/submit/i);
expect(button).toHaveAttribute('type', 'submit'); expect(button).toHaveAttribute('type', 'submit');
expect(button).toBeDisabled(); expect(button).toBeDisabled();
}); });
@ -40,7 +40,7 @@ test('should render with default values', () => {
const websiteValue = 'http://mysite.com'; const websiteValue = 'http://mysite.com';
const nameValue = 'John'; const nameValue = 'John';
const { getByLabelText, getByText } = render( render(
<Form <Form
{...defaultTestProps} {...defaultTestProps}
enableSubmit={true} enableSubmit={true}
@ -48,13 +48,13 @@ test('should render with default values', () => {
/> />
); );
const nameInput = getByLabelText(/name Label/); const nameInput = screen.getByLabelText(/name Label/);
expect(nameInput).toHaveValue(nameValue); expect(nameInput).toHaveValue(nameValue);
const websiteInput = getByLabelText(/WebSite label/); const websiteInput = screen.getByLabelText(/WebSite label/);
expect(websiteInput).toHaveValue(websiteValue); expect(websiteInput).toHaveValue(websiteValue);
const button = getByText(/submit/i); const button = screen.getByText(/submit/i);
expect(button).toBeEnabled(); expect(button).toBeEnabled();
}); });
@ -66,13 +66,13 @@ test('should submit', () => {
}; };
const websiteValue = 'http://mysite.com'; const websiteValue = 'http://mysite.com';
const { getByLabelText, getByText } = render(<Form {...props} />); render(<Form {...props} />);
const websiteInput = getByLabelText(/WebSite label/); const websiteInput = screen.getByLabelText(/WebSite label/);
fireEvent.change(websiteInput, { target: { value: websiteValue } }); fireEvent.change(websiteInput, { target: { value: websiteValue } });
expect(websiteInput).toHaveValue(websiteValue); expect(websiteInput).toHaveValue(websiteValue);
const button = getByText(/submit/i); const button = screen.getByText(/submit/i);
expect(button).toBeEnabled(); expect(button).toBeEnabled();
fireEvent.click(button); fireEvent.click(button);

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import BlockSaveButton from './block-save-button'; import BlockSaveButton from './block-save-button';
@ -10,14 +10,14 @@ test('<BlockSaveButton /> snapshot', () => {
}); });
test('Button text should default to the correct translation key', () => { test('Button text should default to the correct translation key', () => {
const { getByRole } = render(<BlockSaveButton />); render(<BlockSaveButton />);
expect(getByRole('button')).toHaveTextContent('buttons.save'); expect(screen.getByRole('button')).toHaveTextContent('buttons.save');
}); });
test('Button text should match "children"', () => { test('Button text should match "children"', () => {
const testText = 'My Text Here'; const testText = 'My Text Here';
const { getByRole } = render(<BlockSaveButton>{testText}</BlockSaveButton>); render(<BlockSaveButton>{testText}</BlockSaveButton>);
expect(getByRole('button')).toHaveTextContent(testText); expect(screen.getByRole('button')).toHaveTextContent(testText);
}); });

View File

@ -3,6 +3,7 @@
exports[`<Loader /> matches the fullScreen render snapshot 1`] = ` exports[`<Loader /> matches the fullScreen render snapshot 1`] = `
<div <div
class="fcc-loader full-screen-wrapper" class="fcc-loader full-screen-wrapper"
data-testid="fcc-loader"
> >
<div <div
class="sk-fade-in sk-spinner line-scale-pulse-out" class="sk-fade-in sk-spinner line-scale-pulse-out"
@ -19,6 +20,7 @@ exports[`<Loader /> matches the fullScreen render snapshot 1`] = `
exports[`<Loader /> matches to the default render snapshot 1`] = ` exports[`<Loader /> matches to the default render snapshot 1`] = `
<div <div
class="fcc-loader " class="fcc-loader "
data-testid="fcc-loader"
> >
<div <div
class="sk-fade-in sk-spinner line-scale-pulse-out" class="sk-fade-in sk-spinner line-scale-pulse-out"

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { render, cleanup } from '@testing-library/react'; import { render, cleanup, screen } from '@testing-library/react';
import Loader from './loader'; import Loader from './loader';
@ -12,8 +12,9 @@ describe('<Loader />', () => {
}); });
it('adds the correct class when given a fullScreen prop', () => { it('adds the correct class when given a fullScreen prop', () => {
const { container } = render(<Loader fullScreen={true} />); render(<Loader fullScreen={true} />);
expect(container.firstChild).toHaveClass('full-screen-wrapper'); const fccLoader = screen.getByTestId('fcc-loader');
expect(fccLoader).toHaveClass('full-screen-wrapper');
}); });
/** /**
@ -22,12 +23,14 @@ describe('<Loader />', () => {
*/ */
it('matches to the default render snapshot', () => { it('matches to the default render snapshot', () => {
const { container } = render(<Loader />); render(<Loader />);
expect(container.firstChild).toMatchSnapshot(); const fccLoader = screen.getByTestId('fcc-loader');
expect(fccLoader).toMatchSnapshot();
}); });
it('matches the fullScreen render snapshot', () => { it('matches the fullScreen render snapshot', () => {
const { container } = render(<Loader fullScreen={true} />); render(<Loader fullScreen={true} />);
expect(container.firstChild).toMatchSnapshot(); const fccLoader = screen.getByTestId('fcc-loader');
expect(fccLoader).toMatchSnapshot();
}); });
}); });

View File

@ -17,7 +17,10 @@ function Loader({ fullScreen, timeout }: LoaderProps): JSX.Element {
return () => clearTimeout(timerId); return () => clearTimeout(timerId);
}, [setShowSpinner, showSpinner, timeout]); }, [setShowSpinner, showSpinner, timeout]);
return ( return (
<div className={`fcc-loader ${fullScreen ? 'full-screen-wrapper' : ''}`}> <div
className={`fcc-loader ${fullScreen ? 'full-screen-wrapper' : ''}`}
data-testid='fcc-loader'
>
{showSpinner && <Spinner name='line-scale-pulse-out' />} {showSpinner && <Spinner name='line-scale-pulse-out' />}
</div> </div>
); );

View File

@ -10,8 +10,8 @@ describe('<Landing />', () => {
it('renders when visiting index page and logged out', () => { it('renders when visiting index page and logged out', () => {
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();
shallow.render(<IndexPage {...loggedOutProps} />); shallow.render(<IndexPage {...loggedOutProps} />);
const result = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
expect(result.type.displayName === 'Landing').toBeTruthy(); expect(view.type.displayName === 'Landing').toBeTruthy();
}); });
}); });

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import Profile from './Profile'; import Profile from './Profile';
@ -55,9 +55,9 @@ const notMyProfileProps = {
describe('<Profile/>', () => { describe('<Profile/>', () => {
it('renders the report button on another persons profile', () => { it('renders the report button on another persons profile', () => {
const { getByText } = render(<Profile {...notMyProfileProps} />); render(<Profile {...notMyProfileProps} />);
const reportButton: HTMLElement = getByText('buttons.flag-user'); const reportButton: HTMLElement = screen.getByText('buttons.flag-user');
expect(reportButton).toHaveAttribute('href', '/user/string/report-user'); expect(reportButton).toHaveAttribute('href', '/user/string/report-user');
}); });

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import HeatMap from './HeatMap'; import HeatMap from './HeatMap';
@ -41,15 +41,15 @@ describe('<HeatMap/>', () => {
*/ */
it('calculates the correct longest streak', () => { it('calculates the correct longest streak', () => {
const { getByTestId } = render(<HeatMap {...props} />); render(<HeatMap {...props} />);
expect(getByTestId('longest-streak').textContent).toContain( expect(screen.getByTestId('longest-streak')).toHaveTextContent(
'profile.longest-streak' 'profile.longest-streak'
); );
}); });
it('calculates the correct current streak', () => { it('calculates the correct current streak', () => {
const { getByTestId } = render(<HeatMap {...props} />); render(<HeatMap {...props} />);
expect(getByTestId('current-streak').textContent).toContain( expect(screen.getByTestId('current-streak')).toHaveTextContent(
'profile.current-streak' 'profile.current-streak'
); );
}); });

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-call */
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import TimeLine from './TimeLine'; import TimeLine from './TimeLine';
import { useStaticQuery } from 'gatsby'; import { useStaticQuery } from 'gatsby';
@ -45,29 +45,25 @@ beforeEach(() => {
describe('<TimeLine />', () => { describe('<TimeLine />', () => {
it('Render button when only solution is present', () => { it('Render button when only solution is present', () => {
// @ts-ignore // @ts-ignore
const { container } = render(<TimeLine {...propsForOnlySolution} />); render(<TimeLine {...propsForOnlySolution} />);
const showViewButton = screen.getByRole('link', { name: 'buttons.view' });
expect( expect(showViewButton).toHaveAttribute(
container.querySelector('#btn-for-5e46f802ac417301a38fb92b') 'href',
).toHaveAttribute('href', 'https://github.com/freeCodeCamp/freeCodeCamp'); 'https://github.com/freeCodeCamp/freeCodeCamp'
);
}); });
it('Render button when both githubLink and solution is present', () => { it('Render button when both githubLink and solution is present', () => {
// @ts-ignore // @ts-ignore
const { container } = render(<TimeLine {...propsForOnlySolution} />); render(<TimeLine {...propsForOnlySolution} />);
const linkList = container.querySelector( const menuItems = screen.getAllByRole('menuitem');
'#dropdown-for-5e4f5c4b570f7e3a4949899f + ul' expect(menuItems).toHaveLength(2);
); expect(menuItems[0]).toHaveAttribute(
// @ts-ignore
const links = linkList.querySelectorAll('a');
expect(links[0]).toHaveAttribute(
'href', 'href',
'https://github.com/freeCodeCamp/freeCodeCamp1' 'https://github.com/freeCodeCamp/freeCodeCamp1'
); );
expect(menuItems[1]).toHaveAttribute(
expect(links[1]).toHaveAttribute(
'href', 'href',
'https://github.com/freeCodeCamp/freeCodeCamp2' 'https://github.com/freeCodeCamp/freeCodeCamp2'
); );
@ -75,9 +71,9 @@ describe('<TimeLine />', () => {
it('rendering the correct button when files is present', () => { it('rendering the correct button when files is present', () => {
// @ts-ignore // @ts-ignore
const { getByText } = render(<TimeLine {...propsForOnlySolution} />); render(<TimeLine {...propsForOnlySolution} />);
const button = getByText('buttons.show-code'); const button = screen.getByText('buttons.show-code');
expect(button).toBeInTheDocument(); expect(button).toBeInTheDocument();
}); });
}); });

View File

@ -5,10 +5,10 @@ import { SearchBar } from './search-bar';
describe('<SearchBar />', () => { describe('<SearchBar />', () => {
it('renders to the DOM', () => { it('renders to the DOM', () => {
const shallow = ShallowRenderer.createRenderer(); const utils = ShallowRenderer.createRenderer();
shallow.render(<SearchBar {...searchBarProps} />); utils.render(<SearchBar {...searchBarProps} />);
const result = shallow.getRenderOutput(); const view = utils.getRenderOutput();
expect(result).toBeTruthy(); expect(view).toBeTruthy();
}); });
/* Todo: When e2e testing is in place, /* Todo: When e2e testing is in place,

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { createStore } from '../../redux/createStore'; import { createStore } from '../../redux/createStore';
@ -15,75 +15,64 @@ describe('<certification />', () => {
// shallow rendering does not render children component // shallow rendering does not render children component
// form buttons are not included in shallow render // form buttons are not included in shallow render
it('Should render show cert button for claimed legacy cert', () => { it('Should render show cert button for claimed legacy cert', () => {
const { container } = renderWithRedux( renderWithRedux(<CertificationSettings {...defaultTestProps} />);
<CertificationSettings {...defaultTestProps} />
);
expect( expect(
container.querySelector( screen.getByRole('link', {
'a[href="/certification/developmentuser/legacy-data-visualization"]' name: 'buttons.show-cert'
) })
).toHaveTextContent('buttons.show-cert'); ).toHaveAttribute(
}); 'href',
'/certification/developmentuser/legacy-data-visualization'
it('Should link show cert button to the claimed legacy cert', () => {
const { container } = renderWithRedux(
<CertificationSettings {...defaultTestProps} />
); );
expect(
container.querySelector(
'a[href="/certification/developmentuser/legacy-data-visualization"]'
)
).toBeInTheDocument();
}); });
// full forms with unclaimed certs should not shallow render show cert button // full forms with unclaimed certs should not shallow render show cert button
it('Should not render show cert button for unclaimed cert with completed projects', () => { it('Should not render show cert button for unclaimed cert with completed projects', () => {
const { container } = renderWithRedux( renderWithRedux(<CertificationSettings {...defaultTestProps} />);
<CertificationSettings {...defaultTestProps} />
);
expect( const allClaimedCerts = screen.getAllByRole('link', {
container.querySelector( name: 'buttons.show-cert'
'a[href="/certification/developmentuser/legacy-back-end"]' });
)
).not.toHaveTextContent('buttons.show-cert'); allClaimedCerts.forEach(cert => {
expect(cert).not.toHaveAttribute(
'href',
'/certification/developmentuser/legacy-back-end'
);
});
}); });
// empty forms with unclaimed certs should not shallow render show cert button // empty forms with unclaimed certs should not shallow render show cert button
it('Should not render show cert button for cert with no completed projects', () => { it('Should not render show cert button for cert with no completed projects', () => {
const { container } = renderWithRedux( renderWithRedux(<CertificationSettings {...defaultTestProps} />);
<CertificationSettings {...defaultTestProps} />
);
expect( const allClaimedCerts = screen.getAllByRole('link', {
container.querySelector( name: 'buttons.show-cert'
'a[href="/certification/developmentuser/legacy-front-end"]' });
)
).not.toHaveTextContent('buttons.show-cert'); allClaimedCerts.forEach(cert => {
expect(cert).not.toHaveAttribute(
'href',
'/certification/developmentuser/legacy-front-end'
);
});
}); });
it('Render button when only solution is present', () => { it('Render button when only solution is present', () => {
const { container } = renderWithRedux( renderWithRedux(<CertificationSettings {...propsForOnlySolution} />);
<CertificationSettings {...propsForOnlySolution} />
);
expect( expect(
container.querySelector('#btn-for-5e46f802ac417301a38fb92b') screen.getByRole('link', {
name: 'buttons.show-solution'
})
).toHaveAttribute('href', 'https://github.com/freeCodeCamp/freeCodeCamp'); ).toHaveAttribute('href', 'https://github.com/freeCodeCamp/freeCodeCamp');
}); });
it('Render button when both githubLink and solution is present', () => { it('Render button when both githubLink and solution is present', () => {
const { container } = renderWithRedux( renderWithRedux(<CertificationSettings {...propsForOnlySolution} />);
<CertificationSettings {...propsForOnlySolution} />
);
const linkList = container.querySelector(
'#dropdown-for-5e4f5c4b570f7e3a4949899f + ul'
);
const links = linkList.querySelectorAll('a');
const links = screen.getAllByRole('menuitem');
expect(links[0]).toHaveAttribute( expect(links[0]).toHaveAttribute(
'href', 'href',
'https://github.com/freeCodeCamp/freeCodeCamp1' 'https://github.com/freeCodeCamp/freeCodeCamp1'
@ -96,11 +85,9 @@ describe('<certification />', () => {
}); });
it('rendering the correct button when files is present', () => { it('rendering the correct button when files is present', () => {
const { getByText } = renderWithRedux( renderWithRedux(<CertificationSettings {...propsForOnlySolution} />);
<CertificationSettings {...propsForOnlySolution} />
);
const button = getByText('buttons.show-code'); const button = screen.getByText('buttons.show-code');
expect(button).toBeInTheDocument(); expect(button).toBeInTheDocument();
}); });
}); });

View File

@ -13,16 +13,16 @@ describe('<Honesty />', () => {
const componentToRender = ( const componentToRender = (
<Honesty isHonest={false} updateIsHonest={updateIsHonestMock} /> <Honesty isHonest={false} updateIsHonest={updateIsHonestMock} />
); );
const component = renderer.render(componentToRender); const view = renderer.render(componentToRender);
expect(component).toMatchSnapshot('Honesty'); expect(view).toMatchSnapshot('Honesty');
}); });
test('<Honesty /> snapshot when isHonest is true', () => { test('<Honesty /> snapshot when isHonest is true', () => {
const componentToRender = ( const componentToRender = (
<Honesty isHonest={true} updateIsHonest={updateIsHonestMock} /> <Honesty isHonest={true} updateIsHonest={updateIsHonestMock} />
); );
const component = renderer.render(componentToRender); const view = renderer.render(componentToRender);
expect(component).toMatchSnapshot('HonestyAccepted'); expect(view).toMatchSnapshot('HonestyAccepted');
}); });
test('should call updateIsHonest method on clicking agree button', () => { test('should call updateIsHonest method on clicking agree button', () => {
@ -30,6 +30,11 @@ describe('<Honesty />', () => {
<Honesty isHonest={false} updateIsHonest={updateIsHonestMock} /> <Honesty isHonest={false} updateIsHonest={updateIsHonestMock} />
).root; ).root;
/**
* This rules had to be disabled because the new lint rules are throwing false positives here.
* They were interpreting react-test-renderer functions as @testing-library/react functions.
*/
// eslint-disable-next-line testing-library/await-async-query
root.findByType(Button).props.onClick(); root.findByType(Button).props.onClick();
expect(updateIsHonestMock).toHaveBeenCalledWith({ isHonest: true }); expect(updateIsHonestMock).toHaveBeenCalledWith({ isHonest: true });
}); });

View File

@ -12,6 +12,7 @@ exports[`<CompletionModalBody /> matches snapshot 1`] = `
</span> </span>
<svg <svg
class="completion-success-icon" class="completion-success-icon"
data-testid="fcc-completion-success-icon"
height="50" height="50"
viewBox="0 0 200 200" viewBox="0 0 200 200"
width="50" width="50"
@ -70,6 +71,7 @@ exports[`<CompletionModalBody /> matches snapshot 1`] = `
</div> </div>
<div <div
class="progress-bar-percent" class="progress-bar-percent"
data-testid="fcc-progress-bar-percent"
style="width: 0%;" style="width: 0%;"
> >
<div <div

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { render, fireEvent } from '@testing-library/react'; import { render, fireEvent, screen } from '@testing-library/react';
import CompletionModalBody from './completion-modal-body'; import CompletionModalBody from './completion-modal-body';
@ -22,26 +22,22 @@ describe('<CompletionModalBody />', () => {
}); });
test('renders with 0% width initially', () => { test('renders with 0% width initially', () => {
const { container } = render(<CompletionModalBody {...props} />); render(<CompletionModalBody {...props} />);
expect(container.querySelector('.progress-bar-percent')).toHaveAttribute( expect(screen.getByTestId('fcc-progress-bar-percent')).toHaveStyle({
'style', width: '0%'
'width: 0%;' });
);
}); });
test('has the correct width after animation', () => { test('has the correct width after animation', () => {
const { container } = render(<CompletionModalBody {...props} />); render(<CompletionModalBody {...props} />);
fireEvent.animationEnd( fireEvent.animationEnd(screen.getByTestId('fcc-completion-success-icon'));
container.querySelector('.completion-success-icon') as HTMLElement
);
jest.runAllTimers(); jest.runAllTimers();
expect(container.querySelector('.progress-bar-percent')).toHaveAttribute( expect(screen.getByTestId('fcc-progress-bar-percent')).toHaveStyle({
'style', width: `${props.completedPercent}%`
`width: ${props.completedPercent}%;` });
);
}); });
}); });
}); });

View File

@ -77,6 +77,7 @@ export class CompletionModalBody extends PureComponent<
<div className='completion-challenge-details'> <div className='completion-challenge-details'>
<GreenPass <GreenPass
className='completion-success-icon' className='completion-success-icon'
data-testid='fcc-completion-success-icon'
onAnimationEnd={() => { onAnimationEnd={() => {
setTimeout(() => { setTimeout(() => {
this.animateProgressBar(completedPercent); this.animateProgressBar(completedPercent);
@ -94,6 +95,7 @@ export class CompletionModalBody extends PureComponent<
</div> </div>
<div <div
className='progress-bar-percent' className='progress-bar-percent'
data-testid='fcc-progress-bar-percent'
style={{ width: `${this.state.shownPercent}%` }} style={{ width: `${this.state.shownPercent}%` }}
> >
<div className='progress-bar-foreground'> <div className='progress-bar-foreground'>

View File

@ -22,10 +22,10 @@ function getComponentNameAndProps(elementType, pathname) {
} }
}); });
shallow.render(<Provider store={store}>{LayoutReactComponent}</Provider>); shallow.render(<Provider store={store}>{LayoutReactComponent}</Provider>);
const renderedComponent = shallow.getRenderOutput(); const view = shallow.getRenderOutput();
return { return {
props: renderedComponent.props, props: view.props,
name: renderedComponent.type.WrappedComponent.displayName name: view.type.WrappedComponent.displayName
}; };
} }