Sharing data between beforeAll / beforeEach and tests in Jest: A guide

Our API testing utilizes jest with intricate scenarios. The beforeAll functions are used to establish general helper variables for each test, as well as implement tenant separation. In some cases, the beforeEach functions are employed to set up tenant separation along with default configurations for the test tenant...

For example, a test may appear like this (notably, TypeScript is utilized for writing the tests):

let apiClient: ApiClient;
let tenantId: string;

beforeAll(async () => {
    apiClient = await getClientWithCredentials();
});

beforeEach(async () => {
    tenantId = await createNewTestTenant();
});

describe('describing complex test scenario', () => {
    it('should have some initial state', async () => {
        await checkState(tenantId);
    });

    it('should have some state after performing op1', async () =>{
        await op1(tenantId);
        await checkStateAfterOp1(tenantId);
    });

    it('should have some state after performing op2', async () =>{
        await op2(tenantId);
        await checkStateAfterOp2(tenantId);
    });

    it('should have some state after performing op1 and op2', async () =>{
        await op1(tenantId);
        await op2(tenantId);
        await checkStateAfterOp1AndOp2(tenantId);
    });

    it('the order of op1 and op2 should not matter', async () =>{
        await op2(tenantId);
        await op1(tenantId);
        await checkStateAfterOp1AndOp2(tenantId);
    });    
});

describe('another similar complex scenario', () => {
    // ... continuation of similar scenarios
});

The challenge lies in determining the optimal way to share the variables initialized by beforeAll and beforeEach. When executed with the --runInBand option, the above test functions correctly, but issues arise when run in parallel, particularly involving undefined values for tenantId. Serial execution leads to successful outcomes for approximately 50-60% of the tests on an 8-core/16-thread build agent, while quad-core CPUs achieve around 80% success rate. Variations occur based on the level of parallelism.

Exploring potential solutions, references were made to utilizing this for context sharing, which proved ineffective, or encapsulating everything within describe:

An attempt was made at a straightforward approach:

describe('tests', () => {
    let apiClient: ApiClient;
    let tenantId: string;

    beforeAll(async () => {
        apiClient = await getClientWithCredentials();
    });

    beforeEach(async () => {
        tenantId = await createNewTestTenant();
    });

    describe('describing complex test scenario', () => {
        it('should have some initial state', async () => {
            await checkState(tenantId);
        });

        // Additional test operations...

    });

    describe('another similar complex scenario', () => {
        // ... continuation of similar scenarios
    });
});

Unfortunately, this adjustment did not yield the desired outcome. An aspiration remains to execute the tests in parallel, yet documentation guidance on this aspect is elusive. Any insights or pointers in the right direction would be greatly appreciated.

Answer №1

Do you think this approach would be suitable for your needs?

describe('tests', () => {
    let apiClient: ApiClient;
    let tenantIds: {id: string, used: boolean}[];

    const findUnusedTenantId = () => {
      const tenant = tenantIds.find(a => !a.used);
      tenant.used = true; 
      return tenant.id
    }

    beforeAll(async () => {
        apiClient = await getClientWithCredentials();
    });

    beforeEach(async () => {
        const id = await createNewTestTenant();
        tenantIds.push({id, used: false})
    });

    describe('describing a complex test scenario', () => {
        let tenantId: string
        it('should start with some initial state', async () => {
            tenantId = fineUnusedTenantId();
            await checkState(tenantId);
        });

        it('should have a certain state after performing operation 1', async () =>{
            await op1(tenantId);
            await checkStateAfterOp1(tenantId);
        });

        // ...
    });
    describe('next scenario', () => {
        let tenantId: string
        it('first test', async () => {
            tenantId = fineUnusedTenantId();
            await checkState(tenantId);
        });

You may want to consider adding an afterAll hook to clean up the database

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Execute TypeScript via command line

After installing ts-global and setting the default ts config, I encountered an issue while trying to compile my file with custom configurations. The command tsc worked fine, but when I tried adding a file path like tsc myfile.ts, nothing seemed to work. F ...

How does the highlighting feature in Fuse.js includeMatches function operate?

Currently, in my Next JS/Typescript web application, I am using the Fuse.js library. However, I am still uncertain about how the includeMatches option functions for highlighting purposes. Whenever I enable this option, I receive a matches object within the ...

Assign the value of a state by accessing it through a string path key within a complexly

I'm currently attempting to modify a deeply nested value in an object by using a string path of the key to access the object. Here is my setup: const [payload, setPayload] = useState({ name: "test", download: true, downloadConfi ...

shallow rendering does not recognize this.props as a function

I'm currently facing an issue while trying to test my (legacy) component using jest/enzyme. Here is a snippet of the component: export default class MyComponent extends Component { constructor( props ) { super( props ); this.handl ...

Issue with Angular 12.1: Unable to retrieve value using "$event.target.value"

I am just starting to dive into the world of Angular and have been using YouTube tutorials as my guide. However, I have encountered an error in one of the examples provided. Below is the code snippet that is causing me trouble. HTML <input type=" ...

What is the reason behind Typescript executing the abstract class before anything else?

I'm currently facing a challenge solving an abstract class problem with Typescript. Let me explain what I am trying to accomplish. There is a class named Sword that extends Weapon. Each Weapon must have certain properties like the damage, but since e ...

Issue with routing in Angular 6 is caused by the "#" character

I am currently working on an Angular 6 project. In my app.routes, I have set it up like this. However, I am facing an issue where I can only access the route using localhost:4200/#/Student instead of localhost:4200/Student. Can you help me identify where t ...

An effective way to define the type of a string property in a React component using Typescript

One of the challenges I'm facing is related to a React component that acts as an abstraction for text fields. <TextField label="Enter your user name" dataSource={vm} propertyName="username" disabled={vm.isSaving} /> In this set ...

Determine whether the radio button has been selected

Within my HTML code, there's a radio button enclosed in a form: <mat-radio-button [(ngModel)]="boxChecked" name="boxChecked" value="boxChecked">Check me</mat-radio-button> In the TypeScript section, I've declared my boolean variable ...

TypeScript type that specifically mandates the properties of an object

Let's consider the following scenario: const myObj = { foo: 'cat', bar: 'dog', baz: 'bird' } as const; type MyValue = 'fish' | 'bear' | 'cow'; const myValueMap: Record<string, MyValue> ...

How can I manage asynchronous calls when querying Mongoose for each element in an array using Express?

Having trouble with the post method below because of a mongoose async issue. The code res.send(suggestions) is being executed before Expense.findOne.exec. app.post('/suggestions', async function(req, res) { const suggestions = await req.body ...

Debugger for Visual Code unable to locate URL in Microsoft Office Add-in

I recently installed the Microsoft Office Add-in Debugger VS code extension, but I'm having trouble getting it to work despite following the instructions. Every time I try, an error message pops up: https://i.sstatic.net/h2FYs.png Upon inspecting my ...

Ways to retrieve a particular element within an array

I am looking to access each individual element of the "to" value within the children property of my array. const items = [{ name: 'Administrator', children: [ { name: 'Catalog', to: 'catalog' }, and he ...

Angular 6 methods that handle Observable data from HTTP GET requests complete execution before constructing the final Data

My goal is to retrieve data from a REST endpoint and then construct a List of instances to return. However, I'm facing an issue where the HTTP GET function returns an Observable method that always results in an empty list before populating it with dat ...

Utilizing enum values in the HTML value attribute with Angular 2

I'm attempting to utilize an enum value in order to set the selected value of an HTML attribute: export enum MyEnum { FirstValue, SecondValue } export function MyEnumAware(constructor: Function) { constructor.prototype.MyEnum = MyEnum; } ...

Is it possible to use 'unrestricted functions' in TypeScript?

As I delved into the Typescript documentation, something caught my attention. Redefining Traditional Class Models C# and Java are often seen as quintessential object-oriented programming (OOP) languages. In these languages, classes act as the fundamental ...

Creating a Proxy for an Array in TypeScript: A Step-by-Step Guide

When attempting to utilize a Proxy for adding logic whenever a value in my array is set to a new value, I encountered an issue with TypeScript. The error arises from the fact that TypeScript does not support indexing an array with anything other than a num ...

Having trouble getting the Angular2 [innerHtml] directive to render properly?

Is there a way to inject HTML code from one Angular component into another using Angular 2 tags? @Component({ selector: 'app-root', template: '<app-a [my-html]="my-html"> </app-a>', styleUrls: ['./app.component.c ...

Display content exclusively in PDF format

On my HTML page, I have two sections - one for inputting values and the other for viewing a PDF. To ensure that the PDF view is hidden until explicitly requested, I need it to remain invisible by default. It should only appear as a PDF when someone clicks ...