Playing around with Jest by creating tests that await the resolution of a promise

I'm currently working on integrating an API found at https://developer.mozilla.org/en-US/docs/Web/API/Performance/measureUserAgentSpecificMemory. The code I am using has a simplified class structure.

export class Memory {
  private stopped = false
  private isUserAgentSpecificMemorySupported = true
  public memoryData: any = []
  constructor() {}

  public startMonitoring(): () => void {
    if (this.isUserAgentSpecificMemorySupported) {
      this.scheduleMeasurement()
    }

    return () => {
      this.stopped = true
    }
  }

  private async performMeasurement(): Promise<void> {
    const memory = await (window.performance as any).measureUserAgentSpecificMemory()
    const type = memory.breakdown.filter((e: any) => e.types.includes('JavaScript'))
    this.memoryData.push(type[0].bytes)
  }
}

This relates to testing with Jest.

import {Memory} from './memory'

type UserAgentSpecificMemoryBreakdown = {
  bytes: number
  types: Array<string>
}

type UserAgentSpecificMemory = {
  bytes: number
  breakdown: Array<UserAgentSpecificMemoryBreakdown>
}

type MockWindow = {
  crossOriginIsolated?: boolean
  performance: {
    measureUserAgentSpecificMemory?: () => Promise<UserAgentSpecificMemory>
  }
}

const data = {
  bytes: 1500,
  breakdown: [
    {
      bytes: 1000000,
      types: ['JavaScript'],
    },
    {
      bytes: 0,
      types: ['DOM'],
    },
  ],
}

describe('Test Memory Class', () => {
  let mockWindow: MockWindow
  let windowSpy: jest.SpyInstance

  beforeEach(() => {
    windowSpy = jest.spyOn(window, 'window', 'get')
    mockWindow = {
      ...window,
      performance: {
        measureUserAgentSpecificMemory: jest.fn(() => Promise.resolve(data)),
      },
    }
    windowSpy.mockImplementation(() => mockWindow)
  })

  afterEach(() => {
    windowSpy.mockRestore()
  })

  it('should measure User Agent Specific Memory', async () => {
    let memory = new Memory()

    memory.startMonitoring()
    expect(memory.memoryData).toEqual([1000000])
  })
})

I'm seeking guidance on how to implement asynchronous handling in the test script.

Your assistance is highly appreciated.

Answer №1

Window is an object and if it lacks the window function, you won't be able to spy on it.

In your actual codebase, simply mocking the measureUserAgentSpecificMemory function should suffice:

import { Memory } from './memory'


describe('Memory', () => {
  const data = {
    bytes: 1500,
    breakdown: [
      {
        bytes: 1000000,
        types: ['JavaScript'],
      },
      {
        bytes: 0,
        types: ['DOM'],
      },
    ],
  };

  let memory: Memory;
  let measureUserAgentSpecificMemory: jest.Mock;

  beforeEach(() => {
    measureUserAgentSpecificMemory = jest.fn().mockResolvedValue(data);
    (window as any).performance = {
      measureUserAgentSpecificMemory,
    };

    memory = new Memory();
  });

  it('should calculate User Agent Specific Memory', async () => {
    memory.startMonitoring();

    expect(memory.memoryData).toEqual([1000000]);
    expect(measureUserAgentSpecificMemory).toHaveBeenCalled();
  });
});

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

Modify the background color of a particular TD element when clicking a button using JavaScript and AJAX

When I click on the "Active account" button inside the designated td with the <tr id="tr_color" >, I want the value "1" to be added to the 'active_account' column in the database. I have been successful with this functionality. However, I a ...

Next.js TypeScript project encountered an issue: "An error occured: 'TypeError: Cannot read property 'toLowerCase' of undefined'"

I am currently developing a Next.js TypeScript project and am facing a perplexing runtime error. The error message reads: TypeError: Cannot read property 'toLowerCase' of undefined This error is triggered in my code when I try to invoke the toLo ...

Ways to retrieve a variable from outside of a function

I am in need of sending the following batch data to the database, but I am facing difficulties in including the course_id along with the batchData. Currently, I am retrieving the course_id from another service that fetches data from a course table. I am ...

Discover the method for measuring the size of a dynamically generated list

I'm currently working on a chat box that displays messages as a list. One issue I'm facing is that when I click on the start chat button, the chat box opens but the length of the list always remains zero. How can I resolve this problem? $(docu ...

When a function is triggered automatically, it sends back an HTML response by default, whereas executing it manually will yield

My current setup involves an action named fetchUserPermissions that retrieves a permission set from an api endpoint using axios. This action is triggered by another action called init, which is automatically executed through the utility dispatchActionForAl ...

Using Angular 2: Exploring the power of observables for broadcasting events during a forEach loop

Upon testing the service within a forEach loop, I noticed that the parameter I passed to the service ended up being the last one in the iteration. I initially suspected that the issue was due to closures, so I attempted using an anonymous function to add ...

Updating table rows in real-time using SocketIO

My intention is to create a makeshift queueing system using socketIO. I am populating my table dynamically, with each row having a unique identifier. The idea was that when a user clicks a button on a particular row, a socket emit event would be sent to th ...

How can I show the MySQL "result" object to the user using express-handlebars?

In my Node.js code, I currently have a query that looks like this: app.get('/fav/books', function(req, res){ var sql = ("SELECT title, pictureUrl, author, description, genre FROM books") connection.query(sql, function(err, result){ if(err) ...

Explore various THREE.JS 3D models through a clickable link

I am struggling to make each object open a new page using a URL when clicked. No matter what I try, it doesn't seem to work properly. Can someone point out what I might be missing or doing wrong? Here is the click event code for the objects. If needed ...

Router failing to progress to subsequent page despite alterations in URL

In my react application, I have 3 pages: a login page, a homepage, and a video page. The issue is that when the login button is clicked, it successfully makes a POST request but does not navigate to the next page. Although the URL changes to the required ...

What sets apart toBeInTheDocument from getBy* in @testing-library/react?

Can you distinguish between these two methods in react-testing-library? expect(screen.queryByText('<something>')).toBeInTheDocument(); And screen.getByText('<something>'); (The specific getBy* and queryBy* operation are no ...

Convert numbers to words in the Indian currency format as you type up to a 16-digit number, displaying the Indian rupees symbol automatically without the need to click a button

How can we modify the code below to automatically add the Indian rupees symbol in the input field? https://i.sstatic.net/TlNLc.png $('.allow_decimal').keyup(function (event) { $(this).val(function (index, value) { return valu ...

Tips for accessing Ajax data within Ember computed property

I'm facing a challenge with returning data from an Ajax call in a computed property. Despite being aware of the asynchronous nature, I am unable to figure out how to do it due to the specific requirement of returning the data in an array format with o ...

Embarking on a fresh XR experience

As a newcomer to TypeScript, I am exploring how to create a functionality similar to a "double-click" event for a hand-input controller in my Three.js application. Here is my approach: - I monitor a click event - I check the timing between the last click ...

Need help incorporating a "section trail" into your website's navigation sidebar using JS/jquery? Here's how you can do it!

My website is quite extensive and contains numerous elements. There are times when I find myself wanting to navigate back and forth between different sections of the page. I've noticed that some websites have a feature called a "page trail," which di ...

How can I empty the value of a UI widget (such as an input field, select menu, or date picker) in Webix UI?

Is there a way in Webix UI to clear widget values individually, rather than collectively based on form id? I'm looking for a method using a mixin like $$(<form-id>).clear(). I need control of individual elements, so is there a proper way to res ...

Are there any equivalents to template literals in the opposite direction?

Template literals make it super simple to create output like this: const age = 22; console.log(`Paul is ${age} years old.`) // => Paul is 22 years old. As I work on extracting information from text, I wonder if there's a way to do the reverse usi ...

Displaying HTML content from a Vuejs response within a Dialog box

After receiving a response from the server via a REST request in HTML format, I have saved it in a data:[] variable. When I log this data on the console, it appears as raw HTML code. This reply is currently stored as a String, and my challenge now is to co ...

Encountering browser freezing issues with a Next.JS app when trying to add an input field

I am currently utilizing Next.JS to construct a form with two inputs. I have followed the traditional React approach for input text reading and validation. "use client" import { firebaseApp } from '@/app/firebase'; import React, { useCa ...

Locate every instance of items in an array within a string

My files have a structure similar to this: https://i.stack.imgur.com/KyaVY.png When a user conducts a search, they send an array to the backend. This array always includes at least one element. For example, if they send ['javascript'] to the b ...