Testing the creation of a new document ID using mocks in a cloud function unit

When it comes to Firestore cloud function TypeScript unit tests, my focus is on mocking doc().id, while leaving doc('path') untouched. Can anyone suggest how I can achieve this?

admin.firestore().collection('posts').doc().id // Mocking only this line

admin.firestore().collection('posts').doc('1')

I attempted the following approach using sinon, but encountered an infinite loop issue at sinon/proxy-invoke.js:50:47:

const collection = admin.firestore().collection('posts');
sinon.stub(collection, 'doc').callsFake(path => 
   path === undefined ? mock : collection.doc(path)
);
sinon.stub(admin.firestore(), 'collection')
  .callThrough()
  .withArgs('posts')
  .returns(collection)

Another attempt involved the following code, however, the doc(documentPath: string) method ended up being stubbed out as well:

sinon.stub(collection, 'doc')
  //@ts-ignore
  .withArgs()
  .returns(mock)

If there's a workaround available in other mock libraries, I'm open to exploring those options.

Answer №1

Encountering an infinite loop is a common issue when you recursively call the stubbed method in your code:

sinon.stub(collection, 'doc').callsFake(path => 
   path === undefined ? mock : collection.doc(path) // <- this calls the stub again
);

To resolve this problem, it is crucial to extract the original doc method from the object being stubbed. Moreover, utilizing the standard function syntax ensures that the context of this is correctly passed to the fake callback (and any other functions being invoked). Even though the doc function presently accepts only one path argument, incorporating rest parameters is recommended for comprehensive argument handling.

// Retain the untouched function (ensure this is executed just once
// to avoid storing a stubbed function)
const _originalDoc = collection.doc;

sinon.stub(collection, 'doc')
  .callsFake(function (...args) { // critical! Employ `function`, not arrow function
    // The context of `this` within this function is a CollectionReference instance
    return args.length = 0 || args[0] === undefined // don't overlook the return statement
      ? mock.call(this)                // invoke the mocked function
      : _originalDoc.apply(this, args) // trigger the original function with its initial arguments
  });

In case your mock includes invocations of collection.doc(), ensure that the authentic function is called rather than the stubbed version (unless deliberately intended).

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

Oops! The last loader did not provide a Buffer or String as expected

After converting my GraphQL query and HOC component to typescript, I encountered the following error: ERROR in ./client/components/Protected.Route.tsx Module build failed: Error: Final loader (./node_modules/awesome-typescript-loader/dist/entry.js) didn ...

Converting JSON data into an Angular object

I'm struggling to map the JSON data below to an Angular 7 object: [ { "id": "123456", "general": { "number": "123", "name": "my name 1", "description": "My description with <li> html tags ...

Refining a collection of item elements by examining a string attribute, disregarding letter case differences

I'm working on a code snippet that generates item components from my list of objects (Frivillig). <app-frivillig-item *ngFor="let frivilligEl of frivillige" [frivillig]="frivilligEl"> </app-frivillig-item> Now, I have a new requireme ...

Using 'interface' declarations from TypeScript is unsupported in JS for React Native testing purposes

I have a ReactNative app and I'm attempting to create a test using Jest. The test requires classes from a native component (react-native-nfc-manager), and one of the needed classes is defined as follows export interface TagEvent { ndefMessage: N ...

Unexplained Reference Error in Next.js Typescript: Variable Accessed before Initialization

I am currently working on an admin website and encountered the error Block-scoped variable used before its declaration.. I will provide details using images and code. This is my first time seeking help on StackOverflow. Error Message: Block-scoped variab ...

When using Framer Motion for page transitions alongside React Router DOM v6, the layout components, particularly the Sidebar, experience rerenders when changing pages

After implementing page transitions in my React app using Framer Motion and React-Router-DOM, I noticed that all layout components such as the sidebar and navbar were unexpectedly rerendering upon page change. Here's a snippet of my router and layout ...

Exploring the benefits of leveraging TypeScript with AWS NodeJS for improved stacktrace visibility over traditional JavaScript

I'm contemplating the idea of transitioning my existing JavaScript codebase to incorporate TypeScript in NodeJS. One aspect that I am concerned about is being able to view the stack trace in AWS CloudWatch (request log) in case an error occurs during ...

Oops! Make sure to explicitly allow the dependency @types/html2canvas by adding it to the "allowedNonPeerDependencies" option

After installing the html2canvas package in my Angular library project, I encountered an error when compiling in production mode using the command ng build --prod. The specific error message is as follows: ERROR: Dependency @types/html2canvas must be exp ...

Limiting the Size of Highcharts Maps with maxWidth or maxHeight

My attempt to adjust the maxWidth of my world map using highcharts isn't altering its size. I have experimented with the following: responsive: { rules: [{ condition: { maxWidth: 500 }, ... As recomme ...

Can an onSnapshot event be set up for an array in order to track changes?

In my system, each user is associated with multiple groups. Each user's group membership is stored as an array within their user document. Additionally, there is a tasks collection where each task contains an array of authorizedGroups that correspond ...

Can a form component be recycled through the use of inheritance?

Greetings to the Stackoverflow Community, As I delve into this question, I realize that examples on this topic are scarce. Before diving into specifics, let me outline my strategy. I currently have three pages with numerous FormGroups that overlap signif ...

Error: Attempting to access property 'toLocaleLowerCase' of an undefined value

I've been working on a custom pipe following the instructions carefully, but I keep encountering an error when trying to filter my list. Below is the code for my custom pipe: import { Pipe, PipeTransform } from '@angular/core' ...

Can you explain how to adjust the font size for table data in OfficeGen?

I am currently utilizing officeGen library to automatically create word documents. generateDocumentService.js: var generateReportFromTableData = function (tableData) { console.log('tableData: ', tableData); var docx = officegen({ type: &a ...

Tips for accurately specifying types for TypeScript map, reduce, filter, and other functions

Encountering errors in my TS code when attempting to provide the correct type to the built-in .map and .filter functions. For example, using: Object.values(league.games).map((game: Game) => { results in Error: Argument of type '(game: Game) => ...

Refresh the Angular view only when there are changes to the object's properties

I have a situation where I am fetching data every 15 seconds from my web API in my Angular application. This continuous polling is causing the Angular Material expansion panel to reset to its default position, resulting in a slow website performance and in ...

Angular 1.5 Karma unit test causes duplicate loading of ng-mock library

My current web app is built using Typescript 2.4.2 and compiled with the latest Webpack version (2.7.0). I am in the process of incorporating Karma tests utilizing Jasmine as the assertion library. Below is my karma configuration file: 'use strict& ...

React component showing historical highchart data when navigating through previous and next periods

I developed this element to showcase a Highchart. It's utilized within a dashboard element that I access from an item in a list. It mostly works as intended, but not entirely. When I move to the dashboard for item A, everything functions correctly. H ...

Issue: Map container not located when implementing a leaflet map with Angular

Here is the complete error message: core.js:6479 ERROR Error: Map container not found. at NewClass._initContainer (leaflet-src.js:4066) at NewClass.initialize (leaflet-src.js:3099) at new NewClass (leaflet-src.js:296) at Object.createMap [a ...

Expanding the current module definition: A step-by-step guide

I have created a declaration file for an existing npm package, but it seems like one method was not declared. I attempted to add it, but encountered an error. Can someone please assist me? Here is the structure of the existing d.ts file: declare modul ...

Swapping out a knockout observable that is passed as an argument

When passing two observables as parameters, I am attempting to replace them with another observable. However, for some reason, the replacement does not occur, even though changing the value on the observable works. private searchAndReplace = (flag: string ...