How to test route changes with NextJS, Vitest, and React Testing Library - reactjs

What is the best way to test routing in a NextJS app? I am using it as a static site generator and am not really using any server-side rendered capability. How do I test routing for the entire application? Ex, let's say my site starts on the route /first-route and I fire an event that changes the route to /second-route. How should I test that? I am trying to use Vitest and React Testing Library. I would really appreciate any guidance!

It's tricky. You may want to consider using something like Cypress for these tests as they are more like end-to-end tests.
You may get away with a tool like next-page-tester - though in my experience that causes more problems than it solves for complex apps.
But if you just want to test that something happens when the path changes, I've had good results with next-router-mock. There's plenty of options available in their docs, but a simple example might look like this:
import mockRouter from "next-router-mock";
describe('tests', () => {
it('changes the url', () => {
mockRouter.setCurrentUrl("/pizza");
})
})

Related

How to do test in React and Node?

I am building a full-stack app with React and Express and I want to ask you something. I decided to improve the app I want to do a test. And what library should I use? I heard about jest or something like that to test React Component but maybe exist a modern solution. To test in express Mocha will be good or again any modern solution exist?
Testing React
There's a bunch of example Testing Recipes for testing rendering, data fetching, events and much more using Jest.
Testing Express.js
I generally recommend Mocha for most of JS unit testing, incl. Express' routes and expected results. Have a look at Express' own Mocha test set for examples.
What to test?
Well, you should test as many methods as you can. Critical methods first. Test them for returning what they should, and not returning what they shouldn't. Also test how they behave given extreme values, undefined values, etc. Check if they throw the right errors when needed.
When using authentication, ALWAYS test your routes to throw appropriate errors (like 401 or 403) for unauthorised access or insufficient privileges respectively.
If not sure what to test, spend some more time reading about testing strategies :-)

How to test `contenteditable` events with React Testing Library

I am trying to write tests for one of our rich text components which was implemented with slate js editor in react js. So when writing tests, I am retrieveing the element div[contenteditable='true'], but not able to simulate events like change, blur, focus. The handlers attached to editor component are not getting called. I tried multiple combinations, but no luck. Can someone please help on this? Is it possible to simulate events for contenteditable element using testing library (contenteditable is implemented using slatejs)?
Like you've discovered, contenteditable isn't supported by JSDOM. React Testing Library (RTL) is built on top of JSDOM, so it's not possible to test the Slate editor properly with RTL until JSDOM implements support for contenteditable.
Use a browser automation library together with Testing Library
Your options are then to use a tool that creates a real browser context. Testing Library have integrations with many tools that do exactly that: TestCafe, Cypress, Nightwatch, Puppeteer.
You can also use the above tools on their own, without Testing Library.
I've solved this using Puppeteer, and there are two approaches:
Run a local server and tell Puppeteer to go to something like localhost:3000
Set the content directly with page.setContent(htmlString)
(1) is the most common, and you'll find many guides for this since it's a common approach for end-to-end testing (google search).
(2) is a little trickier because you will have to transform and bundle your source for each test, and then inject it as HTML into the browser page. I prefer this approach because the testing experience is much more similar to using RTL. I've created a repository with an example of this setup with the Slate editor here: https://github.com/marcusstenbeck/puppeteer-react-testing-template/

ReferenceError: crypto is not defined

I am testing my React app and when it runs a test that executes the Web Cryptography API, specifically await crypto.subtle.generateKey I get the following error message
ReferenceError: crypto is not defined
It seems as if React Testing Library didn't have access to the library, which makes sense, since this is an API native to the browser, and React Testing Library simulates a library.
How can I add the library so that the test passes? Following the TDD principles, I shouldn't modify the code so that it passes the test.
As #Jayce44 suggested you can just add a mock to the window object. It is a good pattern to erase any random component in your tests anyway (especially in TDD). Defining a fake/mock crypto module where you define the output of it based on the test case has many benefits to write solid test cases.Depending on the framework you are using this could look something like:
beforeEach(() => {
setupCryptoWithExpectedValue(42)
});
test(() => {
productionCodeUsingCrypto()
}
I met the same problem as you, but in fact he is not a problem。
because this API can only run in localhost and HTTPS environments.
therefore, the scenario where you make an error may be running in the HTTP environment

Microfrontends React/Component based splitting

Background:
I am confronted with the task to modernize a tool and convert it to microservices with a react frontend. My idea was to have a general top-level component containing e.g. the Nav and a component for each microservice that contains the functionality.
Approaches:
bundle the components locally so that it becomes effectively a monolithic frontend and the the forntend code is seperated just in the repo.
I think that would give up on the advantage of not having to redeploy your entire app for every change
lazy-load a minified bundle of each of the components from the microservice by defining them in a config file
With this approach I could just webpack each component on their own and async import it from the Main Page but maybe there would be a huge overhead
I read about component based splitting with react-loadable and bundling react-router or webpack, but I can't find information on how to load small bundles form different URL-Endpoints.
Question:
Is it possible to bundle react components on their own and import them from different Resource-URL's and how would one approach that ?(Or is React even suitable for that)
So after quite some search and experiments I found the Project Mosaic of Zalando, which is what I wanted. It offers a great way of React Component Splitting to support Micro Frontends. Note however that it is probably not suitable for smaller projects as it takes some time to get into the material and setting up all necessary applications.
Take a look at the below link:
https://www.martinfowler.com/articles/micro-frontends.html
I've recently made a project based on that article and I think that it might be what You are looking for.
I made the wrapper app which is rendering the microfrontends dynamically on the runtime based on the URL and routings. In the article above, there is a demo app showing the idea.
Every microfrontend is the separate project with it's own code repo.
https://demo.microfrontends.com/
Each app is hosted and js chunks are getting loaded on the runtime. This code might make it a little bit more clear what's going on there.
componentDidMount() {
const { name, host } = this.props;
const scriptId =micro-frontend-script-${name}`;
if (document.getElementById(scriptId)) {
this.renderMicroFrontend();
return;
}
fetch(`${host}/asset-manifest.json`)
.then(res => res.json())
.then(manifest => {
const script = document.createElement('script');
script.id = scriptId;
script.src = `${host}${manifest['main.js']}`;
script.onload = this.renderMicroFrontend;
document.head.appendChild(script);
});
}`
I hope You'll find that helpful :)
Good luck!

Splitting React App to 2 Independent Parts

The app I'm developing (Node.js + Express + React + Alt) is addressed to 2 types of crowds - Teachers, for which it is a large app with multiple routes, and students, for which it is a very small app with a single route.
I want to separate these 2 parts completely, so the code of teachers part won't be loaded when students route is rendered.
I have two reasons in mind:
Better loading times for students' app - There's no point in downloading and running that big chunk of JavaScript when I know it won't be needed.
Security Aspect - Although there's no data exposure, I'd still rather hide the code the teachers use from the students.
Is there an easy way to do this?
Can I use one React app (And one React-Router)?
Thanks for any help!
The best way to implement this is using the Webpack feature Code Spliting. This allow you automatically split your code in chunks and only load the require code when is needed.
You can see the React Router example: huge-apps
The magic happen in the internal components (require('./routes/*')), here they use the callback method to get the components and look something like this:
export default {
path: 'nameOfComponent',
getComponent(location, cb) {
require.ensure([], (require) => {
cb(null, require('./components/nameOfComponent'))
})
}
}
Require.ensure is detected by Webpack and generate a new chunk with all the code and his internal dependencies.
When the application is executed in the browser the first load only get the main chunk with the routes definition, and each router components is loaded on demand (when you change of route).
For me, this is the most clean way to do it. Because you delegate the responsibility to the build system. In Webpack 2, you could use System.import instead of require.ensure, and is a more ES6 standard.

Resources