Overriding a library function with the same namespace name in a mocking scenario

In a scenario akin to a previous inquiry, my goal is to mock an external library utilizing sinon. The challenge lies in the fact that this library exports two functions and a namespace under the identical name of FastGlob.

While I possess a basic understanding of function overloading, there is uncertainty regarding how namespaces interact with function overloading in this specific case.

My objective is to mock the initial function definition; however, sinon seems to be detecting the namespace instead.

declare function FastGlob(source: PatternInternal | PatternInternal[], options: OptionsInternal & EntryObjectPredicate): Promise<EntryInternal[]>;

The following depicts the library's definition file:

import { Options as OptionsInternal } from './settings';
import { Entry as EntryInternal, FileSystemAdapter as FileSystemAdapterInternal, Pattern as PatternInternal } from './types';

declare function FastGlob(source: PatternInternal | PatternInternal[], options: OptionsInternal & EntryObjectPredicate): Promise<EntryInternal[]>;
declare function FastGlob(source: PatternInternal | PatternInternal[], options?: OptionsInternal): Promise<string[]>;
declare namespace FastGlob {
    type Options = OptionsInternal;
    type Entry = EntryInternal;
    type Task = taskManager.Task;
    type Pattern = PatternInternal;
    type FileSystemAdapter = FileSystemAdapterInternal;
    function sync(source: PatternInternal | PatternInternal[], options: OptionsInternal & EntryObjectPredicate): EntryInternal[];
    function sync(source: PatternInternal | PatternInternal[], options?: OptionsInternal): string[];
    function stream(source: PatternInternal | PatternInternal[], options?: OptionsInternal): NodeJS.ReadableStream;
    function generateTasks(source: PatternInternal | PatternInternal[], options?: OptionsInternal): Task[];
    function isDynamicPattern(source: PatternInternal, options?: OptionsInternal): boolean;
    function escapePath(source: PatternInternal): PatternInternal;
}
export = FastGlob;

Various attempts have been made, but TypeScript seems only able to locate the functions within the namespace (such as sync, stream, etc.). Removing the function's string identifier leads to a different issue.

import * as FastGlob from 'fast-glob';
import { stub, SinonStub } from "sinon";
import { Pattern, Entry, Options } from "fast-glob";

(stub(FastGlob, "FastGlob") as unknown as SinonStub<[s: Pattern | Pattern[], o: Options], Promise<Entry[]>>).resolves([{test: '/test/'} as unknown as Entry])

This is how the application code integrates the library:

import * as glob from 'fast-glob';
const paths: Array<string> = await glob('./my/glob/**/*.ts', { absolute: true });

Answer №1

To effectively stub fast-glob, you will need an additional module due to the way it is defined. For more information on this issue, refer to this sinon issue.

If you require an example of how to use an additional module, check out proxyquire.

Here is a sample of glob.ts:

// File: glob.ts
import glob from 'fast-glob';


async function getPaths(input: string): Promise<Array<glob.Entry|string>> {
  return glob(input, { absolute: true });
}

export { getPaths };

You can test using the spec file provided below:

// File: glob.spec.ts
import * as FastGlob from 'fast-glob';
import sinon from 'sinon';
import proxyquire from 'proxyquire';
import { expect } from 'chai';

describe('Glob', () => {
  const fakeInput = './node_modules/**/settings.js';
  it('getPaths using first fast-glob definition', async () => {
    const fakeResult = [{ test: '/test/' } as unknown as FastGlob.Entry];
    const fakeFunc = sinon.fake.resolves(fakeResult);
    // Create stub using proxyquire.
    const glob = proxyquire('./glob', {
      'fast-glob': sinon.fake.resolves(fakeResult),
    });
    const paths = await glob.getPaths(fakeInput);
    expect(paths).to.deep.equal(fakeResult);
    expect(fakeFunc.calledOnceWithExactly(fakeInput));
  })

  it('getPaths using second fast-glob definition', async () => {
    const fakeResult = ['/test/'];
    const fakeFunc = sinon.fake.resolves(fakeResult);
    // Create stub using proxyquire.
    const glob = proxyquire('./glob', {
      'fast-glob': sinon.fake.resolves(fakeResult),
    });
    const paths = await glob.getPaths(fakeInput);
    expect(paths).to.deep.equal(fakeResult);
    expect(fakeFunc.calledOnceWithExactly(fakeInput));
  })
});

When running this using ts-mocha and nyc in the terminal, you should see the following results:

$ npx nyc ts-mocha glob.spec.ts 


  Glob
    ✔ getPaths using first fast-glob definition (137ms)
    ✔ getPaths using second fast-glob definition


  2 passing (148ms)

--------------|---------|----------|---------|---------|-------------------
File          | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
--------------|---------|----------|---------|---------|-------------------
All files     |     100 |      100 |     100 |     100 |                   
 glob.spec.ts |     100 |      100 |     100 |     100 |                   
 glob.ts      |     100 |      100 |     100 |     100 |                   
--------------|---------|----------|---------|---------|-------------------

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

The JsonFormatter is throwing an error because it is trying to access the property 'on' of an undefined variable

I have encountered an error while attempting to generate an HTML report using cucumber-html-reporter The error message is: Unhandled rejection TypeError: Cannot read property 'on' of undefined at new JsonFormatter (C:\path-to-project\ ...

Steps for converting an array of objects to a different array of objects in TypeScript

Is there a way to transform an array of objects into another array of objects in TypeScript? a : [ {bcdbcd : 1, abcabc : "value1"}, {bcdbcd : 2, abcabc : "value2"}, {bcdbcd : 3, abcabc : "value3"} ] a : [ {label: 1, ...

Why is it that the form consistently comes back as invalid?

I populated my edit form inputs with data from an API response, https://i.sstatic.net/2HUpr.png When I click on Continue, the validate() function is triggered. validate() { this.$refs.form.validate() console.log('this.$refs.form.va ...

creating curved lines in three.js

I'm looking for assistance in creating a globe using three.js where I can project arcs representing exports and imports between countries. I have a basic globe set up, but I need guidance on the following: 1. How to use country shape files instead of ...

Obtain the Week Input's Value

Is there a way to store the value of a week input in a variable and then display it in a span? I attempted the following code: <input type="week" name="week" id="week-selector"> <span id="kalenderwoche"> ...

Creating routes in ExpressJs and rendering pages using Vanilla JavaScript

When I send a request to app.get("/auth/login", (req, res) => { res.sendFile(path.join(__dirname + "/authentication/login.html")); }); using fetch("/auth/login", { method: "GET" }); I'm able to receive the HTML page as a response. ...

Tips for obscuring URLs in AngularJS code without relying on base 64 encoding or Gulp obfuscation techniques

I'm looking for a way to obfuscate specific URLs in my AngularJS code without using base 64 encoding. Is there a method to only obfuscate URLs? var app_data = { 'APP_CONFIG': { 'USER_URL': 'http://127.1.1.0:8000/ ...

Limit the allowable React Component prop type in Typescript

To promote composition within our codebase, we utilize passing components as props. Is there a way to enforce type checking for the components passed as props? For instance, let's consider a commonly used Typography component throughout the codebase, ...

Preventing unnecessary 'unused parameter' alerts in TypeScript

I've come across this scenario multiple times and have finally decided to explore the correct approach for handling it. When dealing with an abstract parent class that declares a method, and some concrete sub-classes implementing actual logic in their ...

What sets Fetch Promise apart in terms of delivery success?

Struggling with using strapi in my project, as the fetch function returns a promise instead of JSON data This is my code : const [products, setProducts] = useState([]); useEffect(() => { (async () => { try { l ...

What could be the root cause behind the error encountered while trying to authenticate a JWT?

I've been working on integrating a Google OAuth login feature. Once the user successfully logs in with their Google account, a JWT token is sent to this endpoint on my Express server, where it is then decoded using jsonwebtoken: app.post('/login/ ...

Identify the invalid field within an Angular form

After the form is rendered, I need to identify which fields are not valid after 5 seconds. Currently, I have a button that is set as ng-disabled="!step1Form.$valid". However, I would like to add a CSS class, possibly in red, to highlight the invalid fields ...

Using form submission to implement reCAPTCHA v3 in g-recaptcha

Is the Recaptcha API causing trouble? I have the key on both the submit button and the form tag, but it's only sending the sitekey without generating tokens. Any suggestions are welcome. You can either use the key in the form tag: <form method=&qu ...

Looking to automatically populate input fields using AJAX?

Need help auto filling input bars with AJAX, encountering a small issue Below is the HTML code: <input type="text" name="url" id="url"> <input type="text" name="name" id="name"> <input type="text" name="catagory" id="catagory> When t ...

What steps can I take to fix the 'node module error' while deploying a project on Vercel?

While working with the world-countries package, I encountered an issue during deployment in Vercel. The error message indicated that a ';' was missing in the index.d.ts file of world-countries located in the node_module directory. Here is the ex ...

Unable to extract all advertisements from Facebook Marketplace

https://i.stack.imgur.com/xEhsS.jpg I'm currently attempting to scrape listings from Facebook marketplace, however, only the first listing is being scraped. Does anyone have any suggestions on how I can scrape the entire list of listings? CODE (async ...

Resolving Incompatibility Problems Between Devices

While learning Typescript with React, I have encountered type compatibility issues when converting dates. Below is the content of my data.ts file: import { Result } from "./columns"; export enum Quality { High = "high", Medium = & ...

Designing unique variations using Material UI

I am currently exploring the creation of custom variants for the Button component in Material UI. To start off, I am developing a customized component based on the Button component with specific styles: // CTA.js import { makeStyles } from "@materia ...

Ways to monitor the scores in Player versus Computer matchups

I'm currently working on my first coding challenge and I must admit, as a beginner in coding, I'm struggling with creating a scorecard to track the player versus computer score over a certain number of games. I've tried various methods, inc ...

Implementing CORS in ReactJs: A Step-by-Step Guide

When working with React.js, I often use this fetchData config: fetchData = () => { fetch("http://localhost:8000/batch_predict", { method: "POST", headers: { 'Accept': 'application/json, text/plain, */*&apo ...