Errors in Javascript unit testing: despite being stubbed, functions are still being activated

I have encountered issues while writing unit tests, and I am currently facing errors that I am trying to troubleshoot.

The specific unit test concerns the index.ts file, which calls the features/index.ts file. To simulate the default export from features/index.ts, I am using sinon for stubbing. However, running the tests results in an error message indicating

TypeError: Cannot read property 'resolve' of undefined
, with the source being pointed to the features/feature1.ts file.

Below are relevant snippets extracted from the testing setup and TypeScript files:

features/feature1.ts
import path from "path";
import fs from "fs";
import {Setup} from "../types";

const TEMPLATE_ROOT = path.resolve(__dirname,"../../templates");
const INDEX_TEMPLATE = fs.readFileSync(TEMPLATE_ROOT, "index.js", "utf8");

export const setup: Setup = async ({config, options}) => {
  // Internal code removed
}
features/index.ts
import {setup as feature1} from "./feature1.ts";
import {setup as feature2} from "./feature2.ts";

type FeatureTypes = "feature1" | "feature2"

type Features = {
  [key in FeatureTypes]: Setup;
};

const features: Features = {
  feature1: feature1,
  feature2: feature2 
}

export default features
index.ts
import features from "./features"
import { Config, Options  } from "./types";

export async function init(config: Config, options: Options): Promise<void> {
  const nextFeature = options.features ? options.features.shift() : undefined;
  if (nextFeature) {

    // Other irrelevant code

    await Promise.resolve(features[nextFeature]({ config, options }));
    return init(config, options);
  }
}
index.spec.ts
import { expect } from "chai";
import * as sinon from "sinon";
import { init } from '.';
import * as features from "./features";
import { Config, Options  } from "./types";

describe("init", () => {
  const sandbox: sinon.SinonSandbox = sinon.createSandbox();
  let featuresStub: sinon.SinonStub;
  
  beforeEach(() => {
    featuresStub = sandbox.stub(features, "default").returns({
      feature1: sandbox.stub().resolves(),
      feature2: sandbox.stub().resolves(),
    });
  });

  afterEach(() => {
    sandbox.restore();
  });

  it("should call setup features", async () => {
    const setup: Setup = {
      features: [
        "feature1",
        "feature2",
      ],
    };

    await init({}, options);
    expect(featuresStub).to.have.been.calledOnce;
  });

  // rest of tests
});

I have also attempted changing the stub setup to:

import * as feature1 from ".features/feature1";
import * as feature2 from ".features/feature2";

// Other code

describe("init", () => {
  const sandbox: sinon.SinonSandbox = sinon.createSandbox();
  let feature1Stub: sinon.SinonStub;
  let feature2Stub: sinon.SinonStub;
  
  beforeEach(() => {
    feature1Stub = sandbox.stub(feature1, "setup");
    feature2Stub = sandbox.stub(feature2, "setup");

    feature1Stub.resolves()
    feature2Stub.resolves()
  });

  // Rest of code and tests
});

I am puzzled as to why it's attempting to execute the code

const TEMPLATE_ROOT = path.resolve(__dirname,"../../templates");
even though I have stubbed the function calling it.

Answer №1

Realized the issue was with the import statements

import path from "path";
import fs from "fs";

Corrected version:

import * as path from "path";
import * as fs from "fs";

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

Can someone provide a clarification on the meaning of this Javascript code snippet?

I stumbled upon the code snippet below: let customHandler; clearTimeout(customHandler); customHandler = setTimeout(() => {...}); This code example is actually part of a Vue application and consists of the following method: public handleMultiSelectIn ...

Switch background and disable hover effect with a click

I'm facing some issues with JavaScript and I can't seem to solve the problem on my own. What I want is, when I click on #footerblock, for the background of #footerblock to change, and then for the footer to lose its "hover effect". <script> ...

Renew the php blade foreach loop using jQuery to update data live

I have a foreach cycle in my HTML, and at one point, some data is posted from JavaScript. I would like to append it once it is added to the database. I need to find a way to refresh the foreach loop without reloading the entire page (I could simply use ap ...

When utilizing the Page Object Model in Playwright with TypeScript, a Linting Error may occur, specifically a Parsing error related

Recently, I started using playwright and decided to implement the page object model using typescript. Everything was going smoothly until I ran a lint check. Unfortunately, the linting check failed in the Pull Request Check on GitHub. The error is occurri ...

Can you guide me on how to programmatically set an option in an Angular 5 Material Select dropdown (mat-select) using typescript code?

I am currently working on implementing an Angular 5 Material Data Table with two filter options. One filter is a text input, while the other is a dropdown selection to filter based on a specific field value. The dropdown is implemented using a "mat-select" ...

The components for my children are not being displayed within the Drawer component in Material UI and React

Why are the Material UI components and other project components not displayed when I use my DrawerForm component? List of dependencies: react: 18.2.0 react-dom: 18.2.0 @amcharts/amcharts5: 5.3.6 @mui/icons-material: 5.11.11 @mui/material: 5.11.12 Code s ...

Is there a way to determine if a tuple is of infinite or finite length?

Is there a way to determine if a tuple is finite or infinite? I've been working on a solution, but it doesn't cover all cases: type IsFinite<T extends any[], Finite = true, Infinite = false> = T extends [] ? Finite : T extends (infer E ...

`Accessing information within a nested JSON array``

I'm currently parsing through the JSON data below. While I can extract the id and name fields without any issues, I am encountering a problem when trying to access json.templates[i].dailyemails.length, as it always returns 0. Below is the structure o ...

Verifying a form submission using a personalized model popup

I have several delete forms in my application that I want to confirm using javascript/jQuery before proceeding. An easy way to do this is: $('form.confirm-form').submit(function(){ return confirm('Are you sure?'); }); This method ...

Does Angular's compile function operate asynchronously?

In my service, I use $compile to compile the template. The JavaScript functions are executed one after another, but in order to retrieve the final HTML content, I have to place html() within a timeout callback. Otherwise, the template includes {{ placeho ...

Initiate navigation in AngularJS through routing

My AngularJS app has a reset link that I need to use to reset it... <a ng-click="resetApp()">reset</a> The button press is being handled in the main controller... $scope.resetApp = function(){ if(confirm("You will lose data...")){ ...

Utilizing JSON information acquired through AJAX within a distinct function

Sorry if this question has been asked before, I tried following suggestions from another post but they didn't work for me. What I'm trying to do is fetch some JSON data, save a part of it in a variable, and then use that variable in a different f ...

You are unable to utilize ScrollView within BottomSheet in React Native

After developing a search feature and page in my app, I encountered an issue with displaying content in BottomSheets. Despite using a DataTable, I found that a ScrollView cannot be nested inside the BottomSheet, resulting in not all content fitting vertica ...

"Need help passing an API key in the header of a Vue.js project? I recently encountered this issue while using a

How can I include an API key in the header of a Vue.js request? I am using DRF pagination. methods: { getPostData() { axios .get("http://192.168.43.126:8000/api/?page=" + this.currentPage, { headers: { &q ...

Validating a single field for City, State, and ZIP in jQuery/JavaScript

I am trying to validate an input field that requires City, State (two letter abbreviation), and ZIP code (5 numeric digits) in the format 'City, State ZIP'. Could someone please help me with validating this specific format and characters? Appre ...

Error happening outside of controllers or services but not being recorded

I've encountered an issue where exceptions occurring outside of controllers or services in plain JavaScript code are not being reported, do not appear in the console, and cannot be handled. For example, if there is an exception within a Car class that ...

Developing a unique TypeScript singleton pattern tailored for multiple PouchDB instances

I have developed a node application that interfaces with multiple databases. I've designed a class which allows me to create various databases effortlessly, as they share similar CRUD operations. The Class: class DatabaseService { private dbName: ...

When passing parameters through a URL in TypeScript, the display shows up as "[object object]" rather than as a string

Hey there! I'm trying to pass some string parameters to my URL to fetch information from an API. Everything seems fine, and when displayed in an alert, the URL looks exactly as it should (no [object, object] issue). var startDate = "2020-09-20"; var ...

How can I import multiple variables in TypeScript?

I have a React application built with TypeScript, and my project directory is structured as follows: App.tsx /pages Page1.tsx The contents of Page1.tsx are shown below: Page1.tsx class PageParams { constructor() { } } class Page1 { co ...