Git Product home page Git Product logo

ts-mock-imports's People

Contributors

dependabot[bot] avatar emandm avatar github-actions[bot] avatar riojack avatar rpbeukes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ts-mock-imports's Issues

Mocking superclass

Is there any way to mock superclass call. Kindly consider the below scenario to resolve to mock

export default class DefaultClass extends TestClass {
  testData: string;
  constructor(a: string, b: string) {
    this.testData = a + ' '+ b + ' data';
  }
}


import { TestClass } from './test-class';

export default class DefaultClass extends TestClass {
  constructor(a: string) {
    super(a, 'default class');
  }

  foo() {
    return this.testData;
  }
}

import DefaultClass from './default-class';

export class DefaultClassConsumer extends  DefaultClass{
  private testClass: testDefaultExport;
  constructor() {
    super('Consumer');
  }

  public consumerCall() {
    return this.foo(); // Returns "Consumer default class data"
  }
}

Here am testing DefaultClassConsumer class using ts-mock-imports and the parent class constructor is called by super method. Because of this I couldnt create a object for "DefaultClassConsumer" Let me know is there any solution for this ๐Ÿ‘

Argument of type <string> is not assignable to parameter of type...

I'm excited about using this library, and I'm suspecting it's some configuration that's causing me headaches. But I have a 3rd party library (airtable) that I am trying to stub for testing purposes. Below is my simplified code:

import { ImportMock } from "ts-mock-imports";
import Airtable from "airtable";

const airtableMock = ImportMock.mockClass(Airtable, "Airtable");
const stub = airtableMock.mock("destroy");

I keep getting the following errors for the mockClass and the mock functions:

error TS2345: Argument of type '"Airtable"' is not assignable to parameter of type '"prototype" | "Base" | "Record" | "Table" | "Error" | "apiKey" | "apiVersion" | "endpointUrl" | "noRetryIfRateLimited" | "requestTimeout" | "default_config" | "configure" | "base" | undefined'.

8 const airtableMock = ImportMock.mockClass(Airtable, "Airtable");
error TS2345: Argument of type '"destroy"' is not assignable to parameter of type '"prototype" | "Base" | "Record" | "Table" | "Error" | "apiKey" | "apiVersion" | "endpointUrl" | "noRetryIfRateLimited" | "requestTimeout" | "default_config" | "configure" | "base" | undefined'.

8 ImportMock.mockFunction(Airtable, "destroy");

Mocking a static class resolves the wrong type

Hello! First, thank you for your hard work maintaining this helpful library. It solved a big problem for me.

I am experiencing a bug with ImportMock.mockStaticClass where it appears to be mocking the wrong type and causing a TypeScript error. I am trying to mock a static method on the DynamoDBDocumentClient called from in the package @aws-sdk/lib-dynamodb.

I have an example very similar to the following Gist: https://gist.github.com/BraydonKains/3b8e8fc56ce08b7df17868d18f19da28

This results in a TypeScript error:

Type 'StaticMockManager<BatchExecuteStatementCommand>' is not assignable to type 'StaticMockManager<DynamoDBDocumentClient>'.
  Type 'BatchExecuteStatementCommand' is missing the following properties from type 'DynamoDBDocumentClient': config, destroy, sendts(2322)

As an experiment, I deleted the type in the variable declaration and had the language server infer the type from usage; this resulted in inferring the same unexpected StaticMockManager<DynamoDBLibModule.BatchExecuteStatementCommand>.

I am unsure if this bug is a result of strange declaration on the side of the AWS package or is somehow a bug in this package, but I thought this would be the best place to start.

Thank you in advance!

Still Having Timeout Error With Multiple Tests In One File

Hello!

I opened this issue a few days ago: #16

Unfortunately, it was very rudely closed without actually being resolved.

@EmandM had a strange comment about 2 second timeouts. I very much do not think this is an issue with mocha timeouts, but rather an issue with this library.

I changed the command I'm using to test to this:

mocha -r ts-node/register src/**/*.test.ts --timeout 5000

But I am getting the exact same behavior- the tests pass when run individually (with it.only), but they fail when all run together. I think there is something in the library that is not being cleaned up properly.

Mocking function to throw error?

Hi,

Firstly thank you for this wonderful library, it's awesome, and the way typings kind of just work is amazing - one thing I couldn't quite get to work though is throwing an error instead of the functions normal return.

I am using jest as my testing library - everything else seems to work perfectly.

Link to test-repo

package.json devDependencies:

"devDependencies": {
    "@types/jest": "25.1.3",
    "jest": "25.1.0",
    "sinon": "9.0.0",
    "ts-jest": "25.2.1",
    "ts-mock-imports": "1.2.6",
    "ts-node": "8.0.2",
    "typescript": "3.8.2"
}

Utils file:

export function someFunction() {
    return "Hello";
}

SomeClass file:

import { someFunction } from "./Utils";

export function dependentFunction(name: string) {
    return `${someFunction()} ${name}`;
}

TestFile:

import { ImportMock } from "ts-mock-imports";
import * as SomeClass from "./SomeClass";
import * as Utils from "./Utils";

interface IMock {
    restore(): void;
}

describe(`Testing SomeClass`, () => {
    let mocks: IMock;

    beforeEach(() => {
        if (mocks) {
            mocks.restore();
            mocks = null;
        }
    });

    test(`Can return without mocking`, () => {
        expect(SomeClass.dependentFunction("Test")).toBe("Hello Test");
    });

    test(`Can mock return as string`, () => {
        mocks = ImportMock.mockFunction(Utils, "someFunction", "Foo");
        expect(SomeClass.dependentFunction("Test")).toBe("Foo Test");
    });

    /* โ†“ - This one doesn't work */
    test(`Can mock an error`, () => {
        mocks = ImportMock.mockFunction(Utils, "someFunction", () => {
            throw Error("This is an error");
        });
        expect(() => SomeClass.dependentFunction("Test")).toThrow("This is an error");
    });
});

Timeout Error With Multiple Tests In One File

Hi!

Thanks for this great project. Mocking things with sinon in typescript has always been somewhat difficult for me, and I really like the api of this library!

The thing is though, I am getting this error when I run the tests in this file:

(node:91020) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
  ok
undefined
;foobarrr
    1) ok

  deleteBook sucessfull call
deleted! 46
    โœ“ returns 200 containing the data that Book.deleteBook resolves.

  deleteBook errors
err is Error: Oh no, there was an error!
    โœ“ returns 400 with errors array containing Book.deleteBook error


  2 passing (2s)
  1 failing

  1) ok
       ok:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/Users/jim/Git-Projects/CRUD-Lambda-TypeScript-Mongo/src/create.test.ts)
      at listOnTimeout (internal/timers.js:531:17)
      at processTimers (internal/timers.js:475:7)



npm ERR! Test failed.  See above for more details.

It's strange because if I run either of them with an "it.only" then each of them pass individually!

Do I need to add some extra cleanup code in order to mock a thing multiple times within a file?

Thanks! ๐Ÿ™

Possible to mock aws-sdk?

I know there's an aws-sdk-mock package, but I like that ts-mock-imports is generic. That said, I'm having trouble mocking it. There's so may different ways to import which could be where I'm getting tripped up.

Just wondering if others have successfully mocked aws-sdk with this lib?

Mocking class properties

I'm currently trying to write unit-tests involving a library exporting a Class instance that exposes all the functionality I want to access behind properties. Basically my system under test looks somewhat like this:

class SUT {
    let client;
    constructor(config) {
        this.client = new Client(config.get(...));
    }
    
    async doSomething() {
        const result = await this.client.someProp.someFn(...);
        // filter result and return afterwards
    }
}

Unfortunately I have been unable to mock the dependency out using ImportMock.mockClass. The problem seems to be that the code does not invoke the mocked property as a function. I'd initially tried to replace client.someProp.someFn() by using

client = ImportMock.mockClass(clientMod, "Client");
const assertStub = stub();
client.mock("someProp", { someFn: assertStub }); 

This fails with the error message "someFn is not a function". Debugging into the SUT reveals that someProp is replaced with a function instead of a property. To remedy this I attempted to change the mock of "someProp" using the underlying sinon stub like the following:

client = ImportMock.mockClass(clientMod, "Client");
let stub = client.mock("someProp");
stub.get(() => {
    return { someFn: assertStub };
});

Unfortunately this also fails. The error message here is "Object.defineProperty called on non-object".
I think my usecase should be covered by MockManager.replace directly, but I am not certain.
Happy to build and PR an implementation, if my diagnosis is correct.

How to mock default methods?

Hi, thanks for such a library. I loved it!

How should I mock default methods (not classes), like this one below?

// notify.ts
import needle from 'needle'

// want to mock the `needle` default method

export const notify = async () => {
   return needle( /* ... */ )
}

I was first trying just like the others, but it doesn't work:

// notify.test.ts

import { notify } from './notify'

import * as needleMod from 'needle'
import { ImportMock } from 'ts-mock-imports'


describe(`mock default`, () => {


  it('should mock default', async () => {
    
    const pYes = Promise.resolve(true)
    const needleDefault = m(needleMod, 'default', pYes)

    await notify()

    expect(needleDefault.callCount).to.eq(1) // never called, always = 0

  })

})

I have tried other combinations as per the readme, but without any luck.

Thanks.

Mocking getters from babell-ed libraries

I needed to mock storiesOf member of @storybook/react. It looked like a simple function member and all went to this code

import * as StorybookReact from '@storybook/react';
const baseStoriesOf = ImportMock.mockFunction(StorybookReact, 'storiesOf');

But it did not work. After long hours of digging, I've found out what was that. Storybook-guys use babel to compile all code. So when we do import ... from '@storybook/react' we actually import this ugly thing:

"use strict";

require("core-js/modules/es6.object.define-property");

Object.defineProperty(exports, "__esModule", {
  value: true
});
Object.defineProperty(exports, "storiesOf", {
  enumerable: true,
  get: function get() {
    return _preview.storiesOf;
  }
});
// and so on

And nothing can help ImportMock.mockFunction to replace [Getter].

Simplified example to reproduce the problem in gist.

Can we do something with that?

Mocking objects

So I have a class in a separate module which exports just that -- class and I have index.ts file to export all module dependencies. In that index.ts I have export default new MongoDb(connectionString, dbName) as Storage; How can I mock it?

sinon dependency not properly listed

package.json lists sinon as devDependency, but the package does not function without sinon as an [implementation] dependency.

When adding ts-mock-imports as a devDependency, sinon will not be installed. Attempting to run in such a state produces:

Error: Cannot find module 'sinon'
Require stack:
- ...\node_modules\ts-mock-imports\lib\import-mock.js
- ...\node_modules\ts-mock-imports\lib\index.js
- MyStuff.unit.tests.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (...\node_modules\ts-mock-imports\src\import-mock.ts:1:1)

Temporary workaround is to also add sinon dependency whenever ts-mock-imports is added, but shouldn't have to do that.

Sinon sandbox-like functionality

Hi, I like this library a lot! It works great for us to mimic how we tested things in Javascript. It is particularly useful in converting our old JS with CommonJS tests to new TS with ES6 imports.

There is just one thing that feels like it is missing, and that is something to mimic this behavior:

const sinon = require('sinon');
const genericService = require('./generic-service');

describe('generic-service', () => {
  const sandbox = sinon.createSandbox();

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

  describe('genericServiceFunction', () => {
    it('should successfully execute the function.', async () => {
      const startJobStub = sandbox.stub(genericService, 'startJob')
        .resolves({job: {id: '123'}});
      const checkJobStub = sandbox.stub(genericService, 'checkJob')
        .resolves({job: {id: '123', status: 'inProgress'}});

      await genericService.genericServiceFunction();

      sinon.assert.calledOnce(startJobStub);
      sinon.assert.calledOnce(checkJobStub);
    });
  });
});

Basically, I want to be able to tie all of the stubs to an object and be able to restore all of them at once (much like how sinon.sandbox works). It makes tests a lot cleaner to write when you can leave all the .restore()s out in favor of one that gets called in the afterEach instead.

I can do the work required for this if necessary, but I wanted to make an issue to track or see if this functionality exists in some capacity already and I just missed it.

Thanks!

Add "How To Expect Something Was Called With The Correct Args" To README docs?

Hi, I am just thinking that for any mocked function called by the function under test, you could have an assertion checking that the mocked function was called with the proper arguments based on the other inputs passed into the FUT...

I'm guessing the solution is probably just regular sinon syntax, but I think it would still help newcomers to have a simple example there in the docs! ๐Ÿ™‚

Unable to mock `fs`

From my TypeScript class, I call:

import * as fs from "fs";
...
fs.writeFileSync(...);

In my tests, I call:

import * as fs from "fs";
import { ImportMock } from "ts-mock-imports";
...
ImportMock.mockFunction(fs, "writeFileSync");

When the test runs, the fs.writeFileSync function is not mocked.

mockOther replaceWith type should be any

Currently, mockOther has a type definition as follows:

static mockOther<T extends IModule, K extends keyof T>(module: {
        [importName: string]: T[K];
    } | T, importName?: K, replaceWith?: T[K]): OtherManager<T[K]>;

The important part being: replaceWith?: T[K]. This can be prohibitive when trying to mock large APIs, in which you wish to only mock a few properties.

The reason is that requiring type T[K] means that your mock object must have all the properties defined, even if you wish to only test or mock a few of these properties.

For this reason, I believe the return type would be better served to be any. This enables the developer to specify the shape of the mock object as they like.

Cannot assign to read only property 'Config' of object '[object Module]'

Hi there. Thanks for making such an awesome library. I dusted off an old project, updated all its dependencies, moved from CJS to ESM, and spent some time getting it to compile and run again. Now I'm fixing up my tests and I've run into an interesting error.

TypeError: Cannot assign to read only property 'Config' of object '[object Module]'
    at new MockManager (node_modules\ts-mock-imports\src\managers\mock-manager.ts:17:33)
    at Function.ImportMock.mockClass (node_modules\ts-mock-imports\src\import-mock.ts:10:31)
    at Context.<anonymous> (file:///C:/Users/reach/IdeaProjects/csgo-demo-helper/test/services/DemoPlaybackHelper.test.ts:38:33)
    at processImmediate (node:internal/timers:476:21)

Problematic code:

import {ImportMock, MockManager} from 'ts-mock-imports';
import * as configModule from '../../src/utils/Config';

let configMock: MockManager<configModule.Config>;

configMock = ImportMock.mockClass(configModule, 'Config');
configMock.mock('getConfig', config);

Snippet of Config.ts

export class Config {
    private readonly config: { [p: string]: any };

    public getConfig = (): { [p: string]: any } => {
        return this.config;
    }
}

When ImportMock.mockClass() is run, I get the above error. I was curious if this is different than #24 or if it's the same but the wording of the error has changed. #24 is caused by a change made in Typescript 3.9 but my code was on Typescript 4.1.3 previously with the mocks working just fine which is what makes me curious if this issue could be different.

Cannot set property x of [object Module] which has only a getter

Error

debug.js:21 TypeError: Cannot set property AnalyticsService of [object Module] which has only a getter
    at <Jasmine>
    at new MockManager (mock-manager.js:26)
    at Function.push../node_modules/ts-mock-imports/lib/import-mock.js.ImportMock.mockClass (import-mock.js:15)
    at UserContext.<anonymous> (fbdb-requests.service.spec.ts:54)
    at ZoneDelegate.invoke (zone-evergreen.js:359)
    at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (zone-testing.js:308)
    at ZoneDelegate.invoke (zone-evergreen.js:358)
    at Zone.run (zone-evergreen.js:124)
    at runInTestZone (zone-testing.js:561)
    at UserContext.<anonymous> (zone-testing.js:576)
    at <Jasmine>

Minimal code

import { ImportMock } from 'ts-mock-imports';
import * as analyticsModule from 'services/AnalyticsService';
analyticsServiceMock = ImportMock.mockClass(analyticsModule, 'AnalyticsService');

It's that mock call that mockClass call that blows up. Similarly blows up with mockOther.

Cut down module attempted to be mocked

import * as utils from "utils";

//in the future this should subscribe to the various state services, plan, project, user, etc
// for now? leach off the old analytics service
export class AnalyticsService{
	private globals = {}
	multiselect(){ ... }
}

export let analyticsService = new AnalyticsService();
window.analyticsService = analyticsService;

Other things of note

  • build: angular-cli v8
  • testing framework: jasmine 3.4

Near as I've been able to tell, you're unable to mock es6 imports because they're supposed to be readonly. Which is roughly what the above illustrates. But I figured this package figured out some way around that limitation.

TypeScript 4

Getting warning "[email protected] requires a peer of typescript@>=2.6.1 < 4 but none is installed. You must install peer dependencies yourself." when using TypeScript 4+. As I understand it, TypeScript 4 shouldn't have any breaking changes so should work?

Cannot mock static methods of a class

Hello,

I'm trying to write a test, and I need to mock out a class. The (simplified) class I need to mock looks something like:

export class MyClass {
  private services: any;
  private static instance: MyClass;

  private constructor() {
    this.services = {};
    return MyClass.instance;
  }

  public static getInstance() {
    if( !MyClass.instance ) {
      MyClass.instance = new MyClass();
    }
    return MyClass.instance;
  }

 .. more functions ..
}

Then how this class is used in the module I'm writing a test for:

Import { MyClass } from 'path/to/class'

let service = MyClass.getInstance().get('someservice').service

So I try to mock this out like so:

import { ImportMock, MockManager } from 'ts-mock-imports';
import * as myClassModule from 'path/to/class';

describe('Test Activity Controller', () => {
  let myClassMock: MockManager<myClassModule.MyClass>;

  before('set up mocks', (done) => {
    myClassMock = ImportMock.mockClass(myClassModule, 'MyClass')
    myClassMock.mock('getInstance', {});
    done()
  })

This will lead to a Typescript error: "Argument of type '"getInstance"' is not assignable to parameter of type '"get" | "register" | "unregister" | "cleanup"'.

"get", "register", "unregister", and "cleanup" are all non-static methods available to MyClass. I can mock these functions no problem.

I have tried to use the "mockStaticClass" function, but this doesn't seem to help. I've also tried to use the "mockOther" class, but this is requiring that I build up an object that has the exact same signature as the class that I'm mocking , and this is proving to be tedious.

Has anyone come across this situation before..?

Mocking Symbol.asyncIterator

Hey, I was wondering if you knew whether it was possible to mock an asyncIterator, or an Iterator? Here's my current (failing) attempt:

    const lMockManager = ImportMock.mockClass<Dealer>(Dealer);

    let lAsyncIteratorResolve: (value: string) => void;

    // @ts-ignore
    lMockManager.mock(Symbol.asyncIterator, () =>
    {
        return {
            current: 0,
            last: 2,
            async next()
            {
                return new Promise(resolve =>
                {
                    lAsyncIteratorResolve = resolve;
                });
            },
        };
    });

Here's also a typescript example of duplicating an object including iterator.

How to check parameters of mocked instance

Assuming we have service.ts:

declare class Service {
    /**
     * Override this method to setup any custom request listeners for each new request to the service.
     */
    setupRequestListeners(request: RequestType): void;
}
export = Service;

A file, foo.ts that uses it:

import Service from './service';

function baz() {
    const bar = new Service();
    bar.setupRequestListeners = (request: RequestType) => {
        ...
    }
}

A file, foo.spec.ts that tests foo.ts it:

import * as ServiceImport from './service';
import { baz } from './foo';

describe('foo', () => {
    const serviceImportMock = ImportMock.mockClass(ServiceImport);
    baz();
    const mock = serviceImportMock.getMockInstance();  // This doesn't seem to return the mocked instance.
    expect(mock.setupRequestListeners).to.equal(...);
}

I would like to access the instanciated mock in my tests and test parameters on it. How do I do that? Calling .getMockInstance() doesn't seem to give me the instance.

Mocking Constructors

Hi!

I'm just a TypeScript beginner, so I may not not have a full grasp on the thing I'm trying to do:

I'm currently trying to mock a constructor of an imported class- is there any way? Currently your library only allows to mock away functions.

class Test{
   constructor(hi:string){
       //how can i make sure this is called with the correct string
   }
}

EDIT:
TypeScript now compiles but throws the following error:

TypeError: Cannot stub non-existent own property default
      at Sandbox.stub (node_modules/sinon/lib/sinon/sandbox.js:308:19)
      at Function.ImportMock.mockFunction (node_modules/ts-mock-imports/src/import-mock.ts:18:18)

This is my test code:

      var queue_stub = ImportMock.mockFunction(queue);
      queue_stub.callsFake(function(queue_name, { redis }) {
        expect(queue_name).to.be.a("string");
        expect(redis).to.equal(mock_redis_config);
        return mock_queue;
      });

(I'm trying to mock Bull)

With jest get error: Cannot find module 'sinon' from 'import-mock.js'

Using this with jest, I get the following error:

  โ— Test suite failed to run

    Cannot find module 'sinon' from 'import-mock.js'

    However, Jest was able to find:
    	'./import-mock.d.ts'
    	'./import-mock.js'
    	'./import-mock.js.map'

    You might want to include a file extension in your import, or update your 'moduleFileExtensions', which is currently ['ts', 'tsx', 'js', 'json', 'jsx', 'node', 'd.ts', 'js.map'].

    See https://jestjs.io/docs/en/configuration#modulefileextensions-array-string

      at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:230:17)
      at Object.<anonymous> (node_modules/ts-mock-imports/src/import-mock.ts:1:1)

(NB: Adding "d.ts" and "js.map" to modulefileextensions-array-string help)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.