jester: constantly jest navigator's mock & check against userAgent/vendor

Purpose:

  • Need to iterate through different combinations of the userAgent
  • Simulate navigator behavior
  • Execute the test

Observation:

  • I simulated the navigator.userAgent, simulation works as planned, first test executes as expected
  • Second simulation is performed, but the test detects the userAgent value from the initial simulation

Function to be tested:

export const isBrowseriOS = () => {
  console.log(navigator.userAgent, ' & ', navigator.vendor);
  return (
    navigator.vendor === 'Apple Computer, Inc.' ||
    (/iPad|iPhone|iPod/.test(navigator.userAgent) &&
      !window.MSStream &&
      'ontouchend' in document)
  );
};

Test file:

import { isBrowseriOS } from './isIOS';

const browserDevices = [
  {
    name: 'iPhone 12 Pro',
    userAgent:
      'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
    vendor: 'Apple Computer, Inc.',
    iOSDevice: true,
  },
   {
     name: 'Samsung SM-G955U',
     userAgent:
       'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36',
     vendor: 'Google Inc.',
     iOSDevice: false,
   },
  
];

describe.each(browserDevices)('iOS test for $name', (device) => {
  beforeEach(() => {
    Object.defineProperty(window, 'navigator', {
      value: {
        userAgent: device.userAgent,
        vendor: device.vendor,
      },
    });
  });
  afterEach(() => jest.resetAllMocks());
  it(`returns ${device.iOSDevice}`, () => {
    expect(isBrowseriOS()).toBe(device.iOSDevice);
  });
});

Outcome: https://i.sstatic.net/OiySk.png

Answer №1

the solution involved utilizing the configurable: true, property within the beforeEach function and resetting it back to its default setting in the afterEach function;

see the functional implementation below:

function:

declare global {
  interface Window {
    MSStream?: any;
  }
}
export const isiOSDevice = () =>
  navigator.vendor === 'Apple Computer, Inc.' ||
  (/iPad|iPhone|iPod/.test(navigator.userAgent) &&
    !window.MSStream &&
    'ontouchend' in document);

test file:

import { isiOSDevice } from './isIOS';

const browserDevices = [
  // List of devices with their corresponding user agent details
];

describe.each(browserDevices)('iOS test for $name', (device) => {
  const { userAgent: originalUserAgent } = window.navigator;

  beforeEach(() => {
    Object.defineProperty(window, 'navigator', {
      configurable: true,
      writable: true,
      value: { userAgent: device.userAgent, vendor: device.vendor },
    });
  });

  afterEach(() => {
    Object.defineProperty(window, 'navigator', {
      configurable: true,
      value: originalUserAgent,
    });
  });

  it(`should return ${device.iOSDevice}`, () => {
    expect(isiOSDevice()).toBe(device.iOSDevice);
  });
});

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

Tips on transforming Angular 2/4 Reactive Forms custom validation Promise code into Observable design?

After a delay of 1500ms, this snippet for custom validation in reactive forms adds emailIsTaken: true to the errors object of the emailAddress formControl when the user inputs [email protected]. https://i.stack.imgur.com/4oZ6w.png takenEmailAddress( ...

Obtaining a customized variation of a class identified by a decorator

I am working with a class that is defined as follows: class Person { @OneToOne() pet: Animal; } Is there a method to obtain a transformed type that appears like this? (Including {propertyKey}Id: string to properties through the use of a decorator) ...

Preparing a component for evaluation

When I execute the app and load views using @useview('resources/panels/data-table-panel.html'), everything works fine. However, running a component test results in failure due to a 404 error caused by the html file not being found. After changin ...

Is it possible for a property to be null or undefined on class instances?

Consider this TypeScript interface: export interface Person { phone?: number; name?: string; } Does having the question mark next to properties in the interface mean that the name property in instances of classes implementing the interface ca ...

Issue with TypeORM findOne method causing unexpected output

I am encountering an issue with my User Entity's Email Column when using TypeORM's findOne function. Instead of returning null for a non-existent email, it is returning the first entry in the User Entity. This behavior does not align with the doc ...

Storing checkbox status in Angular 7 with local storage

I am looking for a way to keep checkboxes checked even after the page is refreshed. My current approach involves storing the checked values in local storage, but I am unsure of how to maintain the checkbox status in angular 7 .html <div *ngFor="let i ...

When trying to pull a component from Svelte, I receive an error message stating "Selection Range

I'm still relatively new to svelte, so I might be handling things incorrectly. Whenever I attempt to separate my button component, regardless of whether I name the component ./Button.svelte, ./Button, Button.svelte, or try variations with capitalizat ...

The deletion of property '1' from the [object Array] is not possible

How to Retrieve a List in My Components Using Input : @Input() usersInput: Section[]; export interface Section { displayName: string; userId: number; title: number; } Here is the Value List : 0: displayName: "بدون نام" ...

The HTML canvas drawImage method overlays images when the source is modified

Trying to implement a scroll animation on my website, I came across a guide for creating an "Apple-like animation" using image sequences. Even though I'm new to Angular, I attempted to adapt the code to work with Angular. However, instead of animatin ...

Efficiently waiting for all useEffect Chains in Jest and Enzyme while handling asynchronous calls: a guide

Here is a Minimal Component example: import React, { useState, useEffect } from "react"; import { API } from "aws-amplify"; export default function TestComponent(props) { const [appointmentId, setAppointmentId] = useState(props.appo ...

Having issues with importing momentjs by reference in TypeScript with amd configuration

I'm puzzled by the difference in behavior between these two snippets: import * as moment from "../Typings/moment"; One works, while this one doesn't: /// <reference path="../Typings/moment.d.ts" /> import * as moment from "moment"; It t ...

Warning: The attribute 'EyeDropper' is not recognized within the context of 'Window & typeof globalThis'

Attempting to utilize "window.EyeDropper" in a project that combines vue2 and TypeScript. When writing the following code: console.log(window.EyeDropper); An error message is generated by my Vetur plugin: Property 'EyeDropper' does not exist on ...

Missing from the TypeScript compilation are Angular5's polyfills.ts and main.ts files

Here is the structure of my Angular5 project. https://i.stack.imgur.com/tmbE7.png Within both tsconfig.app.json and package.json, there is a common section: "include": [ "/src/main.ts", "/src/polyfills.ts" ] Despite trying various solu ...

A guide on transforming a string into an array of objects using Node.js

Hey everyone, I have a single string that I need to convert into an array of objects in Node.js. let result = ""[{'path': '/home/media/fileyear.jpg', 'vectors': [0.1234, 0.457, 0.234]}, {'path': '/home/med ...

Is it possible to modify the parameters of a function by utilizing a MethodDecorator without affecting the "this" value?

Consider a scenario where you need to dynamically modify method arguments using a decorator at runtime. To illustrate this concept, let's simplify it with an example: setting all arguments to "Hello World": export const SillyArguments = (): MethodDec ...

TypeDoc is having trouble locating the Angular 2 modules

Currently, I am attempting to create documentation files using TypeDoc. When executing TypeDoc with the command below: /node_modules/.bin/typedoc --module system --target ES5 --exclude *.spec.ts* --experimentalDecorators --out typedoc app/ --ignoreCompile ...

What are the two different ways to declare a property?

I am trying to update my interface as shown below interface Student{ Name: String; age: Number; } However, instead of the current structure, I would like it to be like this interface Student{ Name: String; age | DOB: Number | Date; } This means t ...

Encountering an issue with TypeScript error code TS2322 when trying to assign a className to the @

Encountering a typescript error when trying to apply a className to a Box element. Interestingly, the same code works on other developers' machines with almost identical configurations. Current dependencies: "@material-ui/core": "4.11. ...

Specifying data type in the fetch method

Screenshot depicting fetch function I'm currently working on a project using Next.js with Typescript and trying to retrieve data from a Notion database. I've encountered an error related to setting up the type for the database_id value. Can anyon ...

A guide on applying color from an API response to the border-color property in an Angular application

When I fetch categoryColor from the API Response, I set border-left: 3px solid {{element.categoryColor}} in inline style. Everything is functioning correctly with no development issues; however, in Visual Studio, the file name appears red as shown in the i ...