Skip to content

Conversation

@nishitmistry
Copy link
Contributor

@nishitmistry nishitmistry commented Jan 17, 2026

  • Starting the migration of enzyme test to @testing-library/react under task Move remaining enzyme tests to @testing-library/react #3767
  • Added @testing-library/jest-dom package for some handy assertion methods
  • Changed the mountComponentWithStore to use @testing-library/react package's render method.
  • Fixed the tests which broke with the change made to mountComponentWithStore method.

@mathjazz
Copy link
Collaborator

Thanks for your contribution, @nishitmistry! Is this ready for a review or do you still plan to make changes?

@mathjazz mathjazz closed this Jan 20, 2026
@mathjazz mathjazz reopened this Jan 20, 2026
@nishitmistry
Copy link
Contributor Author

Hey @mathjazz, I am done with the migrations of store related tests, you can go ahead with the review.

Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

Added some high-level questions and comments. Please also rebase against main.

Thanks for your contributions to Pontoon!


import { FailedChecks } from './FailedChecks';
import { vi } from 'vitest';
import { expect } from 'vitest';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not put everything in one line?

import { vi, expect } from 'vitest';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

});

expect(wrapper.find('ul > *')).toHaveLength(3);
expect(container.querySelectorAll('ul > *')).toHaveLength(3);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please help me understand what's the motivation for this change (and many other similar changes below)? Is find() coming from enzyme?

Copy link
Contributor Author

@nishitmistry nishitmistry Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, find() is returned by the mount() method of enzyme, which locates a node based on any selector. There's no such method in React Testing Library to select a node with html selector, so we use the container's querySelector() to select the nodes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using querySelector() is a bit of a code smell with testing-library, tbh. It's ok to do so initially here, but it would be good to leave // TODO code comments in the vicinity of each such test to replace them with getBy* and similar testing-library-ish approaches.


return (
<li className={cn} onClick={handleSelectEntity}>
<li className={cn} onClick={handleSelectEntity} data-testid='entity'>
Copy link
Collaborator

@mathjazz mathjazz Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of adding data-* attributes just for the sake of testing. Is it really necessary?

Copy link
Contributor Author

@nishitmistry nishitmistry Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't query based on the component as we do with Enzyme ( wrapper.find(Entity); is not possible in React Testing Library). So if we wish to know whether a particular component exists or not, adding data-testid='entity' and then querying it would be the way afaik.
React Testing Library recommends an accessibility-based testing approach RTL queries priority guide, but the task is limited to just the migration.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The testid attributes do have their place, but as the page you link to itself documents, they should only be used when no other option works.

@nishitmistry nishitmistry force-pushed the shift-mocked-store-enzyme-test-to-rtl branch from 579e89f to 8ba0e27 Compare January 23, 2026 16:44
@nishitmistry nishitmistry requested a review from mathjazz January 23, 2026 16:48
@nishitmistry nishitmistry marked this pull request as draft January 23, 2026 17:41
@mathjazz mathjazz mentioned this pull request Jan 23, 2026
@nishitmistry nishitmistry marked this pull request as ready for review January 25, 2026 09:49
@nishitmistry nishitmistry force-pushed the shift-mocked-store-enzyme-test-to-rtl branch from 28d5063 to fd687b4 Compare January 25, 2026 09:56
@mathjazz mathjazz requested review from eemeli and removed request for mathjazz January 29, 2026 12:30
Copy link
Member

@eemeli eemeli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty decent. A few too many test ids and on occasion a bit too verbose, but decent. More comments inline.

@@ -30,7 +30,9 @@ describe('<FailedChecks>', () => {
it('does not render if no errors or warnings present', () => {
const wrapper = mountFailedChecks({ errors: [], warnings: [] });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go with the destructuring style you use elsewhere in this PR.

Suggested change
const wrapper = mountFailedChecks({ errors: [], warnings: [] });
const { container } = mountFailedChecks({ errors: [], warnings: [] });

This same suggestion also applies to other places where the render() result is used.

});

expect(wrapper.find('ul > *')).toHaveLength(3);
expect(container.querySelectorAll('ul > *')).toHaveLength(3);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using querySelector() is a bit of a code smell with testing-library, tbh. It's ok to do so initially here, but it would be good to leave // TODO code comments in the vicinity of each such test to replace them with getBy* and similar testing-library-ish approaches.

<section className='history'>
<section
className='history'
data-testid='history-History--no-translations'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've taken this testid from the localization id. Rather than doing so, this (and potentially other similar cases) seem like a perfect use case for getByText().

@@ -52,7 +53,7 @@ describe('<EntitiesList>', () => {
hasMore: true,
});
const wrapper = mountComponentWithStore(EntitiesList, store);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking this suggestion in two to deal with GitHub's limitations; similar also applies to other tests -- the getBy* functions should be preferred where they're an option, and they don't need an expect() wrapper for an N=1 expected result.

Suggested change
const wrapper = mountComponentWithStore(EntitiesList, store);
const { getByTestId } = mountComponentWithStore(EntitiesList, store);

});
const wrapper = mountComponentWithStore(EntitiesList, store);
expect(wrapper.find('SkeletonLoader')).toHaveLength(1);
expect(wrapper.queryByTestId('skeleton-loader')).toBeInTheDocument();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(wrapper.queryByTestId('skeleton-loader')).toBeInTheDocument();
getByTestId('skeleton-loader');

Comment on lines +38 to +39
expect(wrapper.container).toHaveTextContent('Klingon');
expect(wrapper.container).toHaveTextContent('kg');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the tests (not just in this file, but also elsewhere) that use .toHaveTextContent() and other replacements for Enzyme's .text() might be best replaced with getByText(), which also accepts a regexp argument.


it('renders a plain translation correctly', () => {
const wrapper = createTranslation('', PLAIN_TRANSLATION);
createTranslation('', PLAIN_TRANSLATION);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
createTranslation('', PLAIN_TRANSLATION);
const { getByText } = createTranslation('', PLAIN_TRANSLATION);


const gt = wrapper.find('GenericTranslation');
expect(gt.props().content).toMatch(/^Un cheval/);
expect(screen.getByText(/^Un cheval/)).toBeInTheDocument();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(screen.getByText(/^Un cheval/)).toBeInTheDocument();
getByText(/^Un cheval/);

const views = Array.from(
wrapper.find('.translationform').instance().querySelectorAll('.cm-content'),
).map((el) => el.cmView.view);
const form = wrapper.container.querySelector('.translationform');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't getByRole('form') work here?

Comment on lines +226 to +250
expect(container.querySelectorAll('.accesskeys button')).toHaveLength(8);
expect(
container.querySelectorAll('.accesskeys button')[0],
).toHaveTextContent('C');
expect(
container.querySelectorAll('.accesskeys button')[1],
).toHaveTextContent('a');
expect(
container.querySelectorAll('.accesskeys button')[2],
).toHaveTextContent('n');
expect(
container.querySelectorAll('.accesskeys button')[3],
).toHaveTextContent('d');
expect(
container.querySelectorAll('.accesskeys button')[4],
).toHaveTextContent('i');
expect(
container.querySelectorAll('.accesskeys button')[5],
).toHaveTextContent('t');
expect(
container.querySelectorAll('.accesskeys button')[6],
).toHaveTextContent('e');
expect(
container.querySelectorAll('.accesskeys button')[7],
).toHaveTextContent('s');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this would be more legible:

Suggested change
expect(container.querySelectorAll('.accesskeys button')).toHaveLength(8);
expect(
container.querySelectorAll('.accesskeys button')[0],
).toHaveTextContent('C');
expect(
container.querySelectorAll('.accesskeys button')[1],
).toHaveTextContent('a');
expect(
container.querySelectorAll('.accesskeys button')[2],
).toHaveTextContent('n');
expect(
container.querySelectorAll('.accesskeys button')[3],
).toHaveTextContent('d');
expect(
container.querySelectorAll('.accesskeys button')[4],
).toHaveTextContent('i');
expect(
container.querySelectorAll('.accesskeys button')[5],
).toHaveTextContent('t');
expect(
container.querySelectorAll('.accesskeys button')[6],
).toHaveTextContent('e');
expect(
container.querySelectorAll('.accesskeys button')[7],
).toHaveTextContent('s');
const buttonTexts = Array.from(
container.querySelectorAll('.accesskeys button'),
button => button.textContent
);
expect(buttonTexts).toMatchObject(['C', 'a', 'n', 'd', 'i', 't', 'e', 's']);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants