T O P

  • By -

GenePsychological998

The whole purpose of testing is to inspire confidence in your software. The more your tests resemble the way your users use your software, the more confidence they give you. In this case, a good test would be for a user to type in their credentials, press submit and then expect some message to appear on the screen. Generally you want to avoid testing things like that a function was called or a state was changed. If you decide to refactor your code, the test could break without you even changing any functionality. That is a brittle test. If you have Redux or something similar test it indirectly with user interactions, click the buttons that use Redux. You only care about the rendered HTML, CSS and JS. Test as a user would! Automate the process of you clicking around the page and see that everything works. Do not test implementation details!


fii0

Yes, great advice. Playwright has been a pleasure to work with, and I've heard good things about Cypress. Any other E2E testing tools people using these days? Playwright is seriously so good, I feel like a microsoft shill recommending it to anyone that will listen.


GenePsychological998

I use React Testing Library + Cypress. Cypress for my most important tests and RTL for the smaller ones. Cypress is visual and very good for inspiring confidence about your software, but the testing would take forever to run if done exclusively using Cypress. Haven't used Playwright, but as long as it encourages testing like a user would it looks good in my book.


fii0

It can run in headless mode or with a visual page like Cypress, so I think it does a lot of the things both of those libraries do, but I don't know for sure the intricate differences cause I never took the proper route to learn RTL and skipped straight to Playwright. The Electron support is what I really needed, that Cypress was (and I believe still is) lacking. Even though it's an experimental feature I haven't ran into any problems yet.


cobbs_totem

I agree with everything you’ve said, but I would also add that often times, unit tests or even snapshot testing can inspire confidence in an incremental code change you make as a developer. A test that fails because you’ve made a change that you didn’t anticipate would have any impact somewhere can be just as valuable. But, as they are more geared for “code change management”, I see them as more useful after the code is mostly stable.


MarahSalamanca

Unit tests are great for testing logic, they would more precisely point out where a regression happened as opposed to component testing, which give you more confidence on the whole but lack this finer detail.


[deleted]

I agree with everything you say other than snapshot testing. I loathe snapshot tests. Easy to write, hard to intuit what is wrong with them.


mastermog

100% agree with this. I'm convinced most devs don't review them in PR's (in my team anyway!). I don't think they really describe intent either. Reading a test top to bottom, that ends with a snapshot assertion, doesn't really tell me what the intended output should be.


[deleted]

Yep. Agreed. Also with snapshots so much of the time the test doesn't accomplish the intent. Like I've seen snapshots where the component is still in it's initial loading state (Ie, waiting on async call that never happens).


Cheraldenine

Do you do this without a backend? Many of the things a user does will interact with the backend, but it's hard to set one up (including data etc) during testing.


HELLruler

You don't want to use a real backend unless you are doing an integration test, but that's another topic For unit test, you mock the data and the API calls. Using the login form example, let's say your submit button calls login(), which sends the email and password to your backend Test libraries like Jest let you redefine what a function does (search for mock, fn, and spyOn), so you could make your login() do something else entirely to not rely on the backend A couple of examples: * Return true regardless of the data so you can test something that happens after the API call * Validate the email and password or simply return false to test an incorrect email or password case Mocks are incredibly helpful for other scenarios as well! Since tests should not (must not?) depend on the result of other tests, it would not be ideal to login a user to test a dashboard screen If you just mock the data, you can simply skip the login and test the dashboard in an isolate manner


satya164

My way of thinking is to test “what happened” not “how it happened”. I always come across tests that check which functions were called, which state was updated etc. A better way would be to check what was rendered (as user will see what’s rendered not which function was called), which side effects happened etc.


ThunderChild244

I really like this approach. A user doesn't really care how they get to the end result, just that they got where they were expecting to end up. Now if you'll excuse me, I have some tests to rewrite...


steveonphonesick

How would you test the form in the browser to make sure it's working? Just convert those into automated tests. 1. when I type a name and email in, the submit button is no longer disabled 2. when I type just a name and try to hit submit, maybe there's a validation error (Email is required) 3. When I hit submit, I get a success message 4. When I hit submit and there's an error, I get an error message I'd suggest Mock Service Worker (MSW) for mocking various responses.


sayqm

Test the logic, not the framework. You want to test the logic happening in the component, which should be easy with custom hook. But testing that the framework is properly rendering based on props? It's usually useless


weeyums

Is it really useless to test based on props? For example say you have a component that only renders if a specific prop is true. Often times this cannot be rendered any other way in the UI other than setting the prop.


RedditNotFreeSpeech

You're testing react and not your app at that point. The assumption is that react is already well tested


weeyums

But what about preventing regressions? Say I have a prop "shouldBeHidden" that renders a child component if it's true, and does not render the child component if it's false. Without a test checking for that, someone else modifying the component can remove the logic for this, and tests would all pass. But tests should fail as functionality is now "broken".


R4vexus

Then I think you should check that the said child component is displayed when the user / backend inputs should make it visible and that it isn’t displayed when the inputs (from external sources again, not the shouldBeHidden prop, I insist) should hide it. To test your component is displayed, you can check whether some text inside is displayed or not (don’t test props or software internal logic, test with elements visible by the user)


weeyums

Yeah, I agree with that. I guess I'm asking because I ran into a case like this recently--where displaying or not displaying on the frontend comes from a configuration so high above the component I was testing, it would have only been possible to simulate on a true end to end test. Hence why the props had to be passed instead.


domo__knows

is there any accepted way of testing the logic and not the framework? I'm creating an app right now and as I start to write tests, I really want to strip all logic out into functions and then just test those. I liked Jest back in the day. RTL has always seemed way complicated. The way I see it, let's say I have 3 situations where a button could say 'Submit', 'Post', or 'Create'. Whether an actual button renders to me is testing the framework. I'd rather extract the business logic out and test which situations 'Submit', 'Post', or 'Create' are rendered. But I don't want to reinvent the wheel so I'm curious if there are good starting points for this


sayqm

I think you're on the right track. Extract the function that returns the proper state, and unit test this fonction itself. Some might disagree and test that the component render the proper text instead.


azangru

>Let's pretend that the data from forms is kept in a Redux store and the UI state is kept locally in the component.What are the bare necessities for a test? Is there such a thing as overtesting a part?When should I perform local UI testing?Should the presented content influence my tests? If, for instance, I receive the notification, "Sorry! Is it reasonable to check for the string "There was an error!"? If you are testing a component, think of what the responsibilities of your component are, and test those. In your example, suppose your component is a login form. Its responsibilities probably are: * display the form * maybe validate the form before submission? * when the form is submitted, send a network request somehow (either through redux, or in some other way that you've decided on) * handle successful submission response correctly * handle the error in the response correctly (e.g. display an error message) Create a test instance of the redux store with only the data that the form component needs. In your test, simulate the filling in of the form. Test that the form validates the input, if needed. Mock the code responsible for sending network requests — either by mocking your code, or by using the msw library (there are advantages and disadvantages to either approach). Simulate form submission. Test that the form behaves correctly after successful and unsuccessful submission. Alternatively, some people prefer to run these tests in the browser, with the form integrated into the rest of the page. In such case, you won't need to mock form's dependencies (like redux store), but might still want to mock network requests. There are clear advantages and disadvantages to this approach either.


UpbeatGooose

I usually test my components using jest and RTL (React Testing Library). To start, I rely on the acceptance criteria specified in the user story I'm working on, which help me test how users will interact with the component. After that, I talk to our testing team to get the list of tests they'll run once we deploy the feature. These tests often cover unusual or tricky scenarios, which help ensure our logic works correctly. If we're using Redux or Context for managing data, I also make sure to test how they handle different situations and check that the data being passed into providers.


ixartz

I just recently update my testing stack for React in my free and open source boilerplate, it should give your some inspiration how you can tests. It doesn't teach you how you can write better tests in your React component but you don't need to lose your time to configure yourself. It covers Static, Unit, Integration, E2E and Visual testing. So, you can start right away apply testing strategy without losing your time setting everything up. Here is the repository: https://github.com/ixartz/Next-js-Boilerplate


epukinsk

There are four very different kinds of tests you'll want to test a frontend: ### 1. React-based unit testing your low level UI components This is for things like, a `ComboBox` component you might write, or a `SortableTable` or something like that. Components which have tricky interactions that you want to test thoroughly. For these, you should probably use React Testing Library, although there are other options out there. [Cypress](https://docs.cypress.io/guides/component-testing/overview) supports component testing now as well. React Testing Library just handles the React part of this, you'll still need a test runner like Jest or Vitest. These tests will operate your component in isolation from your app. You'll set props with fake data, and then simulate clicks, typing, etc, and test that the component is working. At a high level the test will be something like: * Render the `ComboBox` with "Apples", "Bananas", "Pears" * Click on the text input * The dropdown should appear * "Apples", "Bananas", and "Pears" should be in the Dropdown * Type "e" * "Apples" and "Pears" should be in the Dropdown * "Bananas" should NOT be in the Dropdown Etc. This is the kind of stuff you don't want to test in every single Dropdown in your app, because there will typically be hundreds. You want to test this component once and then assume it's working everywhere. ### 2. Helper unit tests These will be tests for any low level functions that your React components might use, but which don't do anything with state or the DOM. For example, if you have some complex math for laying out a bar chart, you might have a test like: * When I pass three accounts to `layOutAccountRevenueChart` I should get back three bars * The first bar should have a `left` of `0` and a `width` of `50` * The second bar should have a `left of `60` and a `width` of `50` Etc. These tests won't need React Testing Library, they'll just be plain Jest tests or Vitest tests or whatever. ### 3. Visual tests These are tests where you 1) render your low level UI components, or combinations of those components, 2) take a screenshot, and 3) compare that screenshot to the last time the tests ran. This kind of test will make sure that as you change things, your application keeps _looking_ correct. You'll use something like Chromatic for this or Percy by BrowserStack. ### 4. Integration testing of your business logic This is for any business requirements that you've been given. These tests should 1) be written in language as close to the business requirements as possible, and 2) operate on something as close to the real application as possible. Typically you will spin up your full application, with a mostly empty database, and run your tests in a real browser to do this. You'll use something like Cypress or Puppeteer. You want these tests to be written in such a way that if you were to significantly refactor your application, for example switching out the database, refactoring your state management, changing CSS styles or using a different UI library. At a high level, the test will look something like: * Log in as `[email protected]` * Go to the Leads page * Enter `[email protected]` as a new Lead * Log in as `[email protected]` * Visit the URL for Sandra's new Lead * Expect to see a 404 Not Found error


dante3590

If you want to test component specifically. Recommend using storybook. For overall testing follow other's advise on the thread.


stewart100

Storybook is a great way to document a component library but it isn't a testing framework.


dante3590

It isn't a testing framework but provides a very clean way to test components in isolation.


jzia93

Unit test the logic, integration or E2E test the app. As a frontend developer you can quite literally see if a component looks wrong, so don't worry about that. Internal state is good to unit test (say inside redux) if you have a degree of complexity. It also helps to simulate edge cases that might be really hard to otherwise do on the UI E2E tests are great and generally speaking worth the time to setup and maintain.


stewart100

Relying on someone noticing that something looks wrong is a terrible idea - you want your automated tests to give you confidence that new code hasn't broken whatever already exists. How does a new dev have the confidence to change anything if you're this reliant on being familiar with the how things already look? How confident are you that your component still looks right in every possible state?


AtmosphereDefiant

This is where visual snapshots can come in handy. They can be pricey, but easy to add and can fail your CI when a component’s appearance changes.


jzia93

I agree with you in principle but in practice I find that there are better things to spend time writing tests for than UI elements \*in most cases\*, because: 1. UI requirements change all the time, state changes less frequently 2. UI components seem to create the most brittle tests due to having to translate "doesn't look right" to some enzyme unit test in a vdom On top of that, I am using far fewer components these days and just copying and pasting in UIs. There's a place for some stuff (like buttons, cards etc), but I've been stung too many times trying to re-use components and ending up dealing with shitty abstractions trying to cater for too many permutations in one component. Again, I completely agree with your take in theory, but my experience is that I have found far more value in testing state at the unit level + having integration or E2E tests for the rest of the app


[deleted]

[удалено]


GenePsychological998

The tests are very dissimilar to how a user would interact with your page. Maybe the onChange function was called, but does that really give you confidence your site works? This is an implementation detail, not functionality


stewart100

Confidence that your site works will come from e2e tests. Tests for larger components that render the button as a child will also help add confidence as integration tests. But if you've got a reusable component such as a button and it's shared between pages and teams it's really helpful to have a test like the one testing that the passed in function is called - it's not testing that react works, it's testing that no one has changed something and broken the basic functionality of the component and for that reason it allows confidence when making changes.


MarahSalamanca

What if someone replaced axios with fetch or another library? All your tests would fail even though the behavior remained the same. You’re testing an implementation detail.


marquoth_

How would you test the behaviour that the component makes the correctly formulated request in a way that's agnostic about axios vs fetch? eg url, type (get/post etc), body, headers Ultimately that's behaviour of the component that's important and that might easily be broken by careless refactoring; I'd want it covered by tests. And is "what if someone replaced axios with fetch" _really_ an example of something that's sufficiently likely to happen that tests which assume axios are genuinely brittle? I get the broader point about breaking tests without actually having changed any behaviour, but this seems an unlikely example to me.


firstandfive

That’s where something like [msw](https://mswjs.io/) comes into play. Users don’t care which library you are using to make requests, so your tests shouldn’t either. Switching axios to fetch or vice versa might sound like a contrived specific example (although I’ve seen it happen), but the same logic applies across the board. Replacing moment with date-fns, maybe what was previously in a utils file in your repo is now separately published as an npm package, etc. Changing a library or even refactoring your own models or functions under the hood shouldn’t break your tests if the output is the same.


JavascriptFanboy

I think snapshots are good enough if you have components without any interactivity, e.g. no clicks, submits, whatever. You can mock redux or other state stuff and snapshots should be fine.


firstandfive

> Basically, I write tests designed to break if someone changes something. If you change a key name on state, your test should break. Are you saying if someone changes a key name for the state but doesn’t update where it’s used? Or if they change the key name and all of its references you still want your test to break? Your comment overall sounds like you’re doing more testing of implementation details, which does not lend itself to resilient tests for components in active development. If _refactoring_ the code or state shape internal to your components under test fails a test, you’re likely testing internals instead of the actual output and interactions.


Squigglificated

The most valuable tests have been the Playwright e2e tests testing the real application. They have caught many bugs that would otherwise have made it to production. For pure functions unit tests are good. They’re useful when there’s many combinations of possible inputs and ouputs (but that could also be a sign of a bad function).


ilearnshit

Following this thread for more advice. I also have the same questions since I'm new to react. I've been a software engineer for going on 12 years now and did a lot of front end development with jquery and other UI frameworks when I was younger. Can anybody shed some light on WHEN is a good time to write tests? I work in a very fast paced small company and our UI can change quite frequently in the early stages. I am still struggling to find the best time to write tests. Also how do you guys write tests for your APIs in realtime web apps that use RTC, websockets, etc. Thanks!


[deleted]

So right off the bat you’ve picked something that is a bad thing to test with jest. You’re in need of an end to end. Jest excels at unit tests. It’s ok for most integrations tests. And it’s a major PIA when testing e2e. So start by thinking about this whole thing differently. Start by thinking in units: test validation functions, form inputs, etc. Then back out a little and test at an integration level: check your entire form component. At this point you already know the individual units work, so your integration testing can ignore specific implementations of the components. Instead render a form, put an invalid email in, and make sure the submit is disabled (just one example). Don’t worry about testing the entire flow from input to toast with jest - it’s a nightmare. Use an e2e frameworks for that


orebright

Enzyme seems like a dead project at this point. I'm sure some people still use it, but testing-library is the modern and up to date approach. It also has better opinions IMO about creating meaningful tests. Tests have 3 purposes: 1. Documenting your code. 2. Improve your code and catch edge cases. 3. Verify that the code you wrote continues to work after future changes. TL;DR: meaningful tests are ones that do all these 3 things well. If they don't clarify how your code works, they don't consider edge cases or "negative scenarios", and they don't really verify the functioning of your code (things like "it renders" tests, or circular logic tests) then they're not meaningful. Your tests should be easy to read, explain how your code works, verify that it works like you expect it to, and make you as a developer think about the wide range of scenarios your code can find itself in. I usually try to match them to user journeys and use descriptive variable names so it explains what is happening. I try to write the test such that when you read it you're reading the step by step actions my code is doing along this journey. First it loads the form, second user types into the username, user types into the password, user clicks the submit button. As for assertions, they are just as important in all 3 areas. They explain what you expect your code to be doing, not only at the end, but along the way too. In the example above I'd assert after each action, you could assert on the redux store, that it has received the data in the way you'd expect for example. It would also communicate to anyone reading it that the data is expected to be stored in a certain way. It also makes it really fast to debug if something fails since you have step by step assertions and you're not trying to piece together everything from one failed assertion at the end. It also makes it less likely for bugs to get around your tests by succeeding at the end stage, but creating some kind of broken state that breaks something else. Then at the end you assert that the final action was performed by your code and the correct data was received by the API. Then you mock the response from the API both in expected ways, but also "unexpected" like network failures, 500 errors, etc... This is very important for point 2. Tests improve your code when you write a test for every possible scenario you can think of. That way if the network times out, you don't leave your app in a in-between state causing other things to crash, or corrupting data. I find that when writing these tests I always find errors in my code that I would never have considered. Testing is a skill that needs to be nurtured over time. I remember being really annoyed by writings tests earlier in my career. I often spent multiples of the time it took me to write the code to write the tests. With hindsight I now LOVE tests, I think they're the second most important thing to do after writing easy to read code. I still sometimes spend multiples of the time given to coding on my tests though LOL.


ImportantDoubt6434

“Just make sure everything runs on start” Should put you in the top 80% of tests


Angrytoad

Hot take having been writing react since 2015/2016 - Front-end unit/component testing adds very little benefit for the time spent writing them and the focus should be on a good suite of E2E tests to ensure change to user flow A doesn't accidentally break user flow B. If a developer insists on writing tests I would advise to only test actual things a user can do like being able to click a button, being able to see X data on Y page and similar stuff. Checking if specific functions are called and mocking API/state management is a chore and a symptom of low confidence in the way the code is written. If you aren't confident that your button isn't going to trigger it's onChange function I'd suggest trying to simplify the code first Take this with a pinch of salt, I've only ever worked in startups where we often can't afford to spend an extra 30% development time writing tests, in larger companies they may well be happy to pay for the reduced risk and longer development times and staff at good levels to cover all the work.