So a test for a single page application written with Playwright might look like what you can see here. You have this page route helper function provided by Playwright, which we can use to intercept all the requests that are made from the browser to a microservice, for example. So if a request is made to slash API slash items, we tell it that the request should not go through to the real microservice. But instead, we directly return, for example, a single shopping list item.
OK, so those were monoliths and single page applications. But now, what about an architecture that, like I showed you before, where we have a client-side part and also a server-side part within a single application, like it's the case with, for example, Next.js or Next.js, or also when you have your own single page application with a custom back-end for front-end, for example, and microservices. So this is important here. Like we saw with monolithic application and also with single page applications without a server-side part, we can use different techniques. But this special case where we have a server-side piece within our front-end application and microservices, and we get our data from microservices, we need or we face a problem.
An architecture might look something like this, where you have your Next.js application with your client-side components, like your view stuff, and also a server-side piece, which typically are your API routes in a Next.js application. And your client-side code fetches data from the server-side, from the API routes in the Next.js example. And this server-side piece gets its data from microservices. So as I said, here we face a problem that we have two kinds of requests. We have browser-to-server requests, which we can see here from the client-side piece to the server-side piece. But we also have server-to-server requests from our API routes to one or multiple microservices. And when writing tests, we can only mock those requests, but we can't mock those requests here from the server-side to services. What we could do, so one workaround we could choose to use, is that we write tests for the separate pieces.
So we don't have one test for our whole Next.js application or for one feature of our whole Next.js application, but we have separate tests for the client-side part and another test for the server-side part or server-side piece of the application. And this is a valid decision we can make. We can choose to write tests for the different pieces, but there is one problem with this. Because when we go this route, we also have to make sure that we also test the combination of these two so that we test the border crossing from the client-side to server-side. Because if we don't do this, although we might have perfect test coverage because we have tests for the client-side code and separate tests for the server-side code, we can't be sure that those two pieces work together correctly if we don't have a test that sits in between the client-side and the server-side.
And we can have a test like that. For example, contract testing, integration testing, there are different ways how we can achieve this. And contract testing, as it's also in the title of this talk, is a good way to do this. And in fact, for this border here, I highly recommend to use contract testing. So for the border between our application and the microservices, we don't want to have a single test that tests, or maybe just a few, real end-to-end tests. But the vast majority of the features, we don't want to test in a way that we test the whole system, including all the microservices. But we want to have separate tests for our Next.js application and for our services. And here, we can use contract testing to make sure that those two pieces work together also and not only in isolation.
Comments