Closed opauloh closed 5 months ago
Pinging @elastic/kibana-cloud-security-posture (Team:Cloud Security)
Compilation of Information available on MSW docs that are relevant when using MSW in node.js:
In Node.js, MSW enables API mocking by patching native request-issuing modules, like http and https, which gives it the means to observe and affect the outgoing traffic for the current process.
One of the most common uses of MSW in Node.js is with test runners like Jest or Vitest. While the general principles of MSW in Node.js still apply there, the test runners expose a convenient setup API to enable mocking in the right phases of the test run.
There are three key steps to integrating MSW with any test runner:
To confirm a successful setup, create a simple outgoing request listener on the server object:
server.events.on('request:start', ({ request }) => {
console.log('MSW intercepted:', request.method, request.url)
})
The confirmation API is useful for developing tests.
Does it support request library XYZ?
Yes. Mock Service Worker supports all request libraries, both existing and those about to be released in the future. This is one of the benefits you get by mocking your API at the network level
Although there’s no Service Worker in Node.js, MSW provides you with a designated API to reuse the same request handlers in Node.js
ReferenceError: fetch is not defined in Node.js
This error means that the version of Node.js you’re using doesn’t support the global Fetch API.
Resolve this by upgrading to Node.js version 18 or higher. MSW does not support Node.js versions below version 18.
Kibana node version is 20+, so we don't
Request/Response/TextEncoder is not defined (Jest)
Make sure you are using Node.js v18 or newer before reading further. This issue is caused by your environment not having the Node.js globals for one reason or another. This commonly happens in Jest because it intentionally robs you of Node.js globals and fails to re-add them in their entirely. As the result, you have to explicitly add them yourself.
Create a jest.polyfills.js file next to your jest.config.js with the following content:
// jest.polyfills.js
/**
* @note The block below contains polyfills for Node.js globals
* required for Jest to function when running JSDOM tests.
* These HAVE to be require's and HAVE to be in this exact
* order, since "undici" depends on the "TextEncoder" global API.
*
* Consider migrating to a more modern test runner if
* you don't want to deal with this.
*/
const { TextDecoder, TextEncoder } = require('node:util')
Object.defineProperties(globalThis, {
TextDecoder: { value: TextDecoder },
TextEncoder: { value: TextEncoder },
})
const { Blob, File } = require('node:buffer')
const { fetch, Headers, FormData, Request, Response } = require('undici')
Object.defineProperties(globalThis, {
fetch: { value: fetch, writable: true },
Blob: { value: Blob },
File: { value: File },
Headers: { value: Headers },
FormData: { value: FormData },
Request: { value: Request },
Response: { value: Response },
})
Make sure to install undici. It’s the official fetch implementation in Node.js.
Then, set the setupFiles option in jest.config.js to point to the newly created jest.polyfills.js:
// jest.config.js module.exports = { setupFiles: ['./jest.polyfills.js'], } Pay attention it’s the setupFiles option, and not setupFilesAfterEnv. The missing Node.js globals must be injected before the environment (e.g. JSDOM). If you fin
Summary
This ticket aims to improve the Integration tests of React components by introducing a Mocked Server that can handle HTTP calls performed by components and functions on the client to return a mocked response whenever an interaction with the server happens.
To achieve that, this ticket proposes introducing MSW. Mock Service Worker (aka MSW) is an API mocking library for browsers and Node.js. With MSW, we can intercept outgoing requests, observe them, and respond to them using mocked responses.
This ticket focuses on using MSW on Node.js, to improve the experience in the development of tests for React components that interact with multiple integrated functions and components (integrations tests). The main goal is to add more capabilities and improve our experience when writing integration tests with Jest by using MSW to intercept requests performed by the React components and mock its response. With this, we can drastically reduce the need for mocking functions when testing integrated front-end components, as it allows the components to interact with a server.
Motivation
Currently, integration tests for React components that interact with the server are hard to write and maintain, as they often require mocking functions implementation and responses, this can lead to tests that do not accurately verify the intended functionality and can be hard to maintain as the implementation of the functions changes.
This leads to situations our team faces now, where due to the difficult maintainability of integration tests, we rely much more on End-to-End tests, and maintaining those many End-to-End comes with its own set of tradeoffs, as oftentimes End-to-End tests are detected by the CI as failing or flaky, and as flakiness can happen in End-to-end tests due to its nature of multiple integrated systems, this concept proposes that it's better to reserve End-to-end tests for the features in the most critical path and tests that test multiple integrated systems as those will benefit most of the end-to-end testing. For all the other tests we should focus on unit and integration tests.
This is where MSW comes in, as MSW allows us to mock server responses in our tests, this way we can avoid mocking the functions that would interact with the server, and we can perform integration tests in the React components in a more realistic way, as we can test how the components behave in different states of the lifecycle such as loading, error, and success.
This proposes that we should use MSW to enhance our integration tests and give preference to writing integration tests over End-to-End tests whenever possible, but this doesn't mean that we should stop writing end-to-end tests, as end-to-end tests are still important for the features in the most critical path and tests that test multiple integrated systems.
Examples of end-to-end tests we should keep include:
Example of end-to-end tests this ticket proposes on migrating to integration tests:
Current state: Currently, a large portion of our end-to-end tests, tests only how the UI behaves with the APIs when Elasticsearch contains certain data, and as we are using the Functional Test Runner (FTR) service, we are starting an Elasticsearch client for our tests, and every test resets Elasticsearch data and ingests other samples of data to the Elasticsearch Client that runs alongside the FTR. These tests consume a lot of processing time, and should best be used if we are aiming to test specific particularities of our integrated systems (Kibana + Specific Elasticsearch features, Integration between different plugins, APM server, etc). For tests that aim to test how the UI behaves accordingly with Elasticsearch or API response, we should aim to perform integrations tests instead, as in concept, since we are inserting the data we want into the Elasticsearch client, it's not very different from storing the response of the APIs and Elasticsearch queries generated to be tested by Jest integrations, but it’s acknowledged that End-to-end tests cost more than integration tests, as it takes more time to develop due to being slow to run, takes more processing time on CI, and it also costs engineering time to debug occasional flakiness.
Goal:
Reduce the overall number of Cloud Security end-to-end tests that run on CI, to reduce flakiness and increase the speed at which tests are run and developed, this way we can focus on providing less, but with higher quality End-to-end tests. Also increases the confidence of integration tests by reducing the amount of mocking needed to write tests, which also improves the development experience.
Challenges: Determine which tests are on the critical path that we will still want to keep in End-to-end testing. As a new tool was introduced, comprehensive documentation will be needed to ensure the tests will be created as intended
Definition of Done
Out of scope
References