Tips for mock nesting a repository in TypeORM?

I'm struggling to figure out how to stub a nested Repository in TypeORM. Can anyone assist me in creating a sinon stub for the code snippet below? I attempted to use some code from another Stack Overflow post in my test file, but it's not working as expected. The line of code I need to stub is:

const project = await getManager().getRepository(Project).find({ where: queryParams });

Here is the relevant source code:

project.controller.ts

//getConnection and UpdateResult are not utilized in this function
import {
  EntityManager,
  getConnection,
  getManager,
  UpdateResult,
} from "typeorm";
import { Project } from "./project.entity";
import { validate } from "class-validator";
import logger from "../../utils/logger";
export const findOneProject = async (queryParams: {}): Promise<
  Project
> => {
  try {
    const project = await getManager().getRepository(Project).find({
      where: queryParams,
    });
    if (project.length > 1) {
      throw new Error("Found more than one project");
    }
    return project[0];
  } catch (e) {
    throw new Error(`Unable to find project: ${e.message}`);
  }
};

project.test.ts

import sinon from "sinon";
import {  findOneProject } from "./project.controller";
import { Project } from "./project.entity";
import { EntityManager, Repository } from "typeorm";

const mockProject = {
  ID: "insert-id-here",
  name: "name",
};

describe("Testing findOneProject", () => {
  it("Should return the same project", () => {
    const sandbox = sinon.createSandbox();
    // I believe I can stub the repository, but I am unsure how to stub the find() method
    sandbox.stub(EntityManager.prototype, "get").returns({
      getRepository: sandbox
        .stub()
        .returns(sinon.createStubInstance(Repository)),
    });
    const project = await findOneProject(ID: "insert-id-here");
    expect(project).toBe(mockProject);
  });
});

Appreciate any help on this!

Edit: I have provided additional details in the test file for clarity.

Answer №1

If you want to implement Link Seams with CommonJS, then consider using proxyquire to create your seams.

For example:

project.controller.ts:

import { getManager } from 'typeorm';
import { Project } from './project.entity';

export const findOneProject = async (queryParams: {}): Promise<Project> => {
  try {
    const project = await getManager()
      .getRepository(Project)
      .find({
        where: queryParams,
      });
    if (project.length > 1) {
      throw new Error('Found more than one project');
    }
    return project[0];
  } catch (e) {
    throw new Error(`Unable to find project: ${e.message}`);
  }
};

project.entity.ts:

export class Project {
  // implementation
}

project.controller.test.ts:

import sinon from 'sinon';
import chai, { expect } from 'chai';
import proxyquire from 'proxyquire';
import { Project } from './project.entity';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);

const mockProject = {
  ID: 'insert-id-here',
  name: 'name',
};

describe('Testing findOneProject', () => {
  let sandbox: sinon.SinonSandbox;
  before(() => {
    sandbox = sinon.createSandbox();
  });
  it('Should return the same project', async () => {
    const typeormStub = {
      getManager: sandbox.stub().returnsThis(),
      getRepository: sandbox.stub().returnsThis(),
      find: sandbox.stub().resolves([mockProject]),
    };
    const { findOneProject } = proxyquire('./project.controller', {
      typeorm: typeormStub,
    });

    const project = await findOneProject({ id: 1 });
    sandbox.assert.calledOnce(typeormStub.getManager);
    sandbox.assert.calledWithExactly(typeormStub.getRepository, Project);
    sandbox.assert.calledWithExactly(typeormStub.find, { where: { id: 1 } });
    expect(project).to.be.eq(mockProject);
  });

  it('should throw error if found more than one project', async () => {
    const typeormStub = {
      getManager: sandbox.stub().returnsThis(),
      getRepository: sandbox.stub().returnsThis(),
      find: sandbox.stub().resolves([{ name: 'a' }, { name: 'b' }]),
    };
    const { findOneProject } = proxyquire('./project.controller', {
      typeorm: typeormStub,
    });

    await expect(findOneProject({ id: 1 })).to.be.rejectedWith('Found more than one project');
    sandbox.assert.calledOnce(typeormStub.getManager);
    sandbox.assert.calledWithExactly(typeormStub.getRepository, Project);
    sandbox.assert.calledWithExactly(typeormStub.find, { where: { id: 1 } });
  });

  it('should throw error if find project error', async () => {
    const typeormStub = {
      getManager: sandbox.stub().returnsThis(),
      getRepository: sandbox.stub().returnsThis(),
      find: sandbox.stub().rejects(new Error('timeout')),
    };
    const { findOneProject } = proxyquire('./project.controller', {
      typeorm: typeormStub,
    });

    await expect(findOneProject({ id: 1 })).to.be.rejectedWith('Unable to find project: timeout');
    sandbox.assert.calledOnce(typeormStub.getManager);
    sandbox.assert.calledWithExactly(typeormStub.getRepository, Project);
    sandbox.assert.calledWithExactly(typeormStub.find, { where: { id: 1 } });
  });
});

unit test result:

  Testing findOneProject
    ✓ Should return the same project (2395ms)
    ✓ should throw error if found more than one project
    ✓ should throw error if find project error


  3 passing (2s)

-----------------------|---------|----------|---------|---------|-------------------
File                   | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------------|---------|----------|---------|---------|-------------------
All files              |     100 |      100 |     100 |     100 |                   
 project.controller.ts |     100 |      100 |     100 |     100 |                   
 project.entity.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

Access specific files within a workspace in VS Code with read-only permissions

Currently, I am engaged in a typescript project within Visual Studio Code. In my workflow, a gulp task is responsible for transferring code to a designated folder. The files copied will be utilized by corresponding files located in the destination folder t ...

The build error TS1036 is thrown when a function with a return statement is moved to index.d.ts, even though it worked perfectly in a standard TS file

In my project using Node v14.x and StencilJS (React) v2.3.x, I encountered an issue with a test-helper file containing a function that converts string-arrays to number-arrays: export function parseNumericStringOrStringArrayToIntegers(value: string | (strin ...

What is the best way to obtain a reference to an instance of my Angular 2 directive?

Angular 2 rc 5 was written using typescript 1.9 I am trying to access the instance of my attribute directive. Although I am using ViewChild, which typically works with components, it is giving me a handle to the element containing the directive. template ...

Unable to loop through the "dataList" retrieved from a service call to the java backend within an Angular 9 application

After receiving JSON data from a Java backend service called houseguidelines, the information is sent to an Angular application via a service call. I am attempting to iterate over this returned JSON data and add it to an array I have created. Unfortunately ...

An issue has occurred where all parameters for the DataService in the D:/appangular/src/app/services/data.service.ts file cannot be resolved: (?, [object Object])

Upon running the command ng build --prod, an error is encountered. Error in data.service.ts: import { BadInput } from './../common/bad-input'; import { AppError } from './../common/app-error'; import { Injectable } from '@angular ...

Angular is encountering a circular dependency while trying to access a property called 'lineno' that does not actually exist within the module exports

I am working on an Angular project and using the Vex template. My project utilizes Angular 9 and Node.js v15.2.0. Every time I run the project with the command ng serve -o, it displays a warning message. https://i.stack.imgur.com/8O9c1.png What could b ...

Is there a way to utilize Typescript enum types for conditional type checking?

I'm working with restful services that accept enum values as either numbers or strings, but always return the values as numbers. Is there a way to handle this in TypeScript? Here's my attempt at it, although it's not syntactically correct: ...

What could be the reason for my npm package installed globally to not be able to utilize ts-node?

Recently, I've been working on developing a CLI tool for my personal use. This tool essentially parses the standard output generated by hcitool, which provides information about nearby bluetooth devices. If you're interested in checking out the ...

The side menu fails to appear when pressed

When using the push method, I am unable to see the side menu. However, it works fine with the setRoot navigation. How can I resolve this issue and display the side menu when using the push method? dashboard.html <ion-col col-9> <ion-searchbar ...

Sending data from parent component to change MUI Button color (React with typescript)

Recently, I've been integrating MUI (v5) into a create-React-App with typescript. I have a custom theme set up as well. My goal is to develop a MyButton Component that accepts a buttonType prop (of type string), which corresponds to my theme.palette, ...

Methods for assigning values to a formControl using an array

I have an array of objects and I am attempting to loop through the array, dynamically setting values to a formControl and not displaying anything if the value is null. I have searched for similar solutions but haven't found any references or examples ...

Reducing image file sizes in Ionic 3

I have been struggling to compress an image client-side using Ionic 3 for the past couple of days. I have experimented with: ng2-img-max - encountered an error when utilizing the blue-imp-canvas-to-blob canvas.toBlob() method (which is a dependency of ng2 ...

Tips on utilizing boolean assignment in a ternary operator with an optional property that is an array in TypeScript

I'm trying to determine the value of an object property based on whether an optional prop is an array. Here's the scenario: const requestingMultipleDevices = Array.isArray(deviceIds); Then I have this object structure: { data: requestingM ...

The JSON object, which has been converted into a string and sent over the network,

Attempting to set up a websocket server using TypeScript in Node.js, the following code was used: ws.on('message', (msg: string) => { console.log("got message:" + msg); const m = JSON.parse(msg); console.log(m); ...

Mixing Jest and Cypress in a TypeScript environment can lead to Assertion and JestMatchers issues

When utilizing [email protected] alongside Jest, we are encountering TypeScript errors related to Assertion and JestMatchers. What is the reason for these TypeScript errors when using Jest and [email protected] in the same project? ...

Jest: A runtime error occurred because the property being accessed is undefined

Currently, I am testing my React class which includes the import statement import dotnetify from "dotnetify";. While this works without any issues, Jest is reporting that dotnetify is undefined. Interestingly, when I switch the import to const do ...

Sinon's useFakeTimers does not impact the Node express server

I'm currently in the process of upgrading my node version from 12.x to 16.x. One issue I've encountered is that in the newer version of node, the express server no longer takes into account sinon's fake timers when setting the date header in ...

Tips on revealing TypeScript modules in a NodeJS environment

Currently, I am working on developing a TypeScript library. My goal is to make this library compatible with both TypeScript and JavaScript Node projects. What would be the most effective approach for achieving this? Should I create two separate versions ...

I am experimenting with an express middleware that can either return next() or next("route")

After developing a middleware function that returns next() if a route's parameters are defined by queryItems, I came across a useful tool called node-mocks-http. However, it does not fake the next object. This led me to explore how this can be achieve ...

Tips for building an interface in TypeScript with a restricted range of indices

I'm working on a function that accepts parameters of type Record<string, string>. How can I define a type with a limited set of indexes without triggering a TypeScript compiler error? Is there a way to create an interface with only specific ind ...