टाइपस्क्रिप्ट के साथ मजाक में निर्भरता


100

एक मॉड्यूल का परीक्षण करते समय एक अलग फ़ाइल में निर्भरता होती है। उस मॉड्यूल को jest.Mockटाइप करने के लिए असाइन करते समय एक त्रुटि मिलती है कि mockReturnThisOnceनिर्भरता पर विधि (या कोई अन्य jest.Mock विधि) मौजूद नहीं है, यह इसलिए है क्योंकि यह पहले से टाइप किया गया है। Jest.Mock से प्रकारों को टाइप करने के लिए टाइपस्क्रिप्ट प्राप्त करने का उचित तरीका क्या है?

यहाँ एक त्वरित उदाहरण है।

निर्भरता

const myDep = (name: string) => name;
export default myDep;

test.ts

import * as dep from '../depenendency';
jest.mock('../dependency');

it('should do what I need', () => {
  //this throws ts error
  // Property mockReturnValueOnce does not exist on type (name: string)....
  dep.default.mockReturnValueOnce('return')
}

मुझे लगता है कि यह एक बहुत ही सामान्य उपयोग का मामला है और यह सुनिश्चित नहीं है कि यह कैसे ठीक से टाइप करें। कोई भी सहायताकाफी प्रशंसनीय होगी!


2
अगर मुझे याद है कि आयात करने से पहले आपको मज़ाक करना होगा। बस पहले 2 लाइनों को स्विच करें। लेकिन मुझे इस पर यकीन नहीं है।
थॉमस

3
@ ES6 के माध्यम से आयातित थॉमसकेलेन मॉड्यूल importपहले मूल्यांकन किए जाते हैं, इससे कोई फर्क नहीं पड़ता कि आप आयात से पहले कुछ कोड डालते हैं। तो यह काम नहीं करेगा।
13

@ थोमस कॉल को jest.mock कोड के शीर्ष पर फहराया जाता है - जेस्ट मैजिक मुझे लगता है ... ( रेफरी ) हालांकि, यह कुछ नुकसान पैदा करता है, जैसे जब मॉड्यूल कारखाने पैरामीटर के साथ jest.mock () कॉल इसलिए m m m फ़ंक्शन जैसेmock...
तोबी

जवाबों:


105

आप टाइप कास्टिंग का उपयोग कर सकते हैं और test.tsइस तरह दिखना चाहिए:

import * as dep from '../dependency';
jest.mock('../dependency');

const mockedDependency = <jest.Mock<typeof dep.default>>dep.default;

it('should do what I need', () => {
  //this throws ts error
  // Property mockReturnValueOnce does not exist on type (name: string)....
  mockedDependency.mockReturnValueOnce('return');
});

टीएस ट्रांसपिलर इस बात से अवगत नहीं है कि इस jest.mock('../dependency');प्रकार के परिवर्तन से depआपको टाइप कास्टिंग का उपयोग करना होगा। चूंकि आयातित depएक प्रकार की परिभाषा नहीं है, इसलिए आपको इसका प्रकार प्राप्त करना होगा typeof dep.default

यहां कुछ अन्य उपयोगी पैटर्न हैं जो मैंने जेस्ट और टीएस के साथ अपने काम के दौरान पाया है

जब आयातित तत्व एक वर्ग होता है तो आपको उदाहरण के लिए टाइपोफ़ का उपयोग नहीं करना पड़ता है:

import { SomeClass } from './SomeClass';

jest.mock('./SomeClass');

const mockedClass = <jest.Mock<SomeClass>>SomeClass;

यह समाधान तब भी उपयोगी होता है जब आपको कुछ नोड देशी मॉड्यूल का मजाक उड़ाना पड़ता है:

import { existsSync } from 'fs';

jest.mock('fs');

const mockedExistsSync = <jest.Mock<typeof existsSync>>existsSync;

यदि आप जेस्ट ऑटोमैटिक मॉक का उपयोग नहीं करना चाहते हैं और मैनुअल बनाना पसंद करते हैं

import TestedClass from './TestedClass';
import TestedClassDependency from './TestedClassDependency';

const testedClassDependencyMock = jest.fn<TestedClassDependency>(() => ({
  // implementation
}));

it('Should throw an error when calling playSomethingCool', () => {
  const testedClass = new TestedClass(testedClassDependencyMock());
});

testedClassDependencyMock()नकली वस्तु उदाहरण TestedClassDependencyवर्ग या प्रकार या इंटरफ़ेस हो सकता है


3
मुझे jest.fn(() =>...इसके बजाय उपयोग करना पड़ा jest.fn<TestedClassDependency>(() =>...(मैंने सिर्फ jest.fn के बाद टाइप कास्टिंग को हटा दिया) क्योंकि इंटेलीजे शिकायत कर रहा है। अन्यथा इस जवाब ने मुझे धन्यवाद देने में मदद की! मेरे पैकेज में इसका उपयोग करते हुए। Json: "@ type / jest": "^ 24.0.3"
A. Masson

jest.mock('./SomeClass');उपरोक्त कोड में क्या है ?
रेजा

12
हम इसे पिछले टीएस वर्जन और जेस्ट 24 :(
विंसेंट

1
@ रेज़ा यह ऑटो मॉक, jestjs.io/docs/en/es6-class-mocks#automatic-mock
ब्रूस ली

8
<jest.Mock<SomeClass>>SomeClass: अभिव्यक्ति मेरे लिए एक टीएस त्रुटि उत्पादनConversion of type 'typeof SomeClass' to type 'Mock<SomeClass, any>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Type 'typeof SomeClass' is missing the following properties from type 'Mock<SomeClass, any>': getMockName, mock, mockClear, mockReset, and 11 more.ts(2352)
the21st

64

mockedts-jestयहाँ बताए गए तरीके से सहायक का उपयोग करें

// foo.spec.ts
import { mocked } from 'ts-jest/utils'
import { foo } from './foo'
jest.mock('./foo')

// here the whole foo var is mocked deeply
const mockedFoo = mocked(foo, true)

test('deep', () => {
  // there will be no TS error here, and you'll have completion in modern IDEs
  mockedFoo.a.b.c.hello('me')
  // same here
  expect(mockedFoo.a.b.c.hello.mock.calls).toHaveLength(1)
})

test('direct', () => {
  foo.name()
  // here only foo.name is mocked (or its methods if it's an object)
  expect(mocked(foo.name).mock.calls).toHaveLength(1)
})

और अगर

  • तुम इस्तेमाल tslint
  • ts-jest आपके देव-आश्रितों में है,

इस नियम को अपने में जोड़ें tslint.json:"no-implicit-dependencies": [true, "dev"]


यहाँ कुछ और उदाहरण दिए जा रहे हैं ts-jestऔर कक्षाओं का उपयोग कर रहे हैं: github.com/tbinna/ts-jest-mock-examples और यह पोस्ट: stackoverflow.com/questions/58639737/…
टोबी

5
सबसे ज्यादा वोट पाने वाले लोगों की तुलना में यह ज्यादा बेहतर जवाब है।
नकलीप्लांड्रोइड

रेपो में @Tobi टेस्ट में विफल रहता है
Kreator

1
@ फ्रांस्वा रोमेन - इस पोस्ट की लिंक मृत है
jarodsmk

1
@jarodsmk I ने लिंक अपडेट किया। धन्यवाद
फ़्राँस्वा रोमेन

18

मैं Mocked (पंक्ति 515) के प्रकार के ऊपर @ प्रकार / jest / index.d.ts से पैटर्न का उपयोग करता हूं:

import { Api } from "../api";
jest.mock("../api");

const myApi: jest.Mocked<Api> = new Api() as any;
myApi.myApiMethod.mockImplementation(() => "test");

2
मुझे पूरा यकीन है कि आप बस कर सकते हैंconst myApi = new Api() as jest.Mocked<Api>;
स्नोफ्रॉगदेव

4
@neoflash: TypeScript 3.4 में सख्त मोड में नहीं है - यह शिकायत करेगा कि Api प्रकार पर्याप्त रूप से ओवरलैप नहीं है jest.Mock<Api>। आपको साथ जाना होगा const myApi = new Api() as any as jest.Mock<Api>और मैं कहूंगा कि ऊपर वाला डबल जोर से बेहतर है।
पाओलोस्टाइल

@ टूट: 3.4 के लिए सख्त मोड ताजा है? क्या आपके पास इस संबंध में कोई लिंक है?
समाप्त करें

@elmpp: निश्चित नहीं कि आपका क्या मतलब है। "सख्त मोड" से मेरा मतलब "strict": truetsconfig.json में था। यह सामान को कवर करता है noImplicitAny, strictNullChecksआदि, इसलिए आपको इसे उनके लिए व्यक्तिगत रूप से सच करने के लिए सेट नहीं करना है।
पाओलोस्टाइल

मुझे नहीं मिला। आप केवल एक उदाहरण की विधि को क्यों रोक रहे हैं, अर्थात myApi? यह सामान्य रूप Apiसे परीक्षण किए जा रहे मॉड्यूल के भीतर वर्ग द्वारा शुरू किए गए अन्य सभी उदाहरणों को सही नहीं ठहराएगा ?
इवान वांग

17

टाइपस्क्रिप्ट संस्करण 3.x और 4.x के लिए दो समाधानों का परीक्षण किया गया है , दोनों वांछित कार्य कर रहे हैं

1) jest.MockedFunction का उपयोग करें

import * as dep from './dependency';

jest.mock('./dependency');

const mockMyFunction = dep.myFunction as jest.MockedFunction<typeof dep.myFunction>;

2) jest.Mock का उपयोग करें

import * as dep from './dependency';

jest.mock('./dependency');

const mockMyFunction = dep.default as jest.Mock;

इन दोनों समाधानों में कोई अंतर नहीं है। दूसरा छोटा है और इसलिए मैं उस एक का उपयोग करने का सुझाव दूंगा।

दोनों कास्टिंग समाधान mockMyFunctionजैसे mockReturnValueया https://jestjs.io/docs/en/mock-function-api.html पर किसी भी जेस्ट मॉक फ़ंक्शन को कॉल करने की अनुमति देता हैmockResolvedValue

mockMyFunction.mockReturnValue('value');

mockMyFunction उम्मीद के लिए आम तौर पर इस्तेमाल किया जा सकता है

expect(mockMyFunction).toHaveBeenCalledTimes(1);

धन्यवाद! मुझे यह स्वीकार किए गए उत्तर से अधिक पसंद है क्योंकि a) IMO को पढ़ना आसान है और b) यह सिंटैक्स त्रुटियों के बिना JSX में काम करता है
दान फ्लेचर

7

कास्ट as jest.Mock

बस समारोह में कास्टिंग jest.Mockकरना चाहिए चाल:

(dep.default as jest.Mock).mockReturnValueOnce('return')


6

यहाँ मैंने jest@24.8.0 और ts-jest@24.0.2 के साथ क्या किया है :

स्रोत:

class OAuth {

  static isLogIn() {
    // return true/false;
  }

  static getOAuthService() {
    // ...
  }
}

परीक्षा:

import { OAuth } from '../src/to/the/OAuth'

jest.mock('../src/utils/OAuth', () => ({
  OAuth: class {
    public static getOAuthService() {
      return {
        getAuthorizationUrl() {
          return '';
        }
      };
    }
  }
}));

describe('createMeeting', () => {
  test('should call conferenceLoginBuild when not login', () => {
    OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
      return false;
    });

    // Other tests
  });
});

यह कैसे एक गैर-डिफ़ॉल्ट वर्ग का मजाक उड़ाया जाता है और यह स्थिर तरीके हैं:

jest.mock('../src/to/the/OAuth', () => ({
  OAuth: class {
    public static getOAuthService() {
      return {
        getAuthorizationUrl() {
          return '';
        }
      };
    }
  }
}));

यहां आपकी कक्षा के प्रकार से कुछ ऐसा रूपांतरण होना चाहिए jest.MockedClassया कुछ ऐसा होना चाहिए । लेकिन यह हमेशा त्रुटियों के साथ समाप्त होता है। इसलिए मैंने इसे सीधे इस्तेमाल किया, और इसने काम किया।

test('Some test', () => {
  OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
    return false;
  });
});

लेकिन, यदि यह एक फ़ंक्शन है, तो आप इसे मॉक कर सकते हैं और टाइप वार्तालाप कर सकते हैं।

jest.mock('../src/to/the/Conference', () => ({
  conferenceSuccessDataBuild: jest.fn(),
  conferenceLoginBuild: jest.fn()
}));
const mockedConferenceLoginBuild = conferenceLoginBuild as 
jest.MockedFunction<
  typeof conferenceLoginBuild
>;
const mockedConferenceSuccessDataBuild = conferenceSuccessDataBuild as 
jest.MockedFunction<
  typeof conferenceSuccessDataBuild
>;

4

मैंने इसमें पाया है @types/jest:

/**
  * Wrap a function with mock definitions
  *
  * @example
  *
  *  import { myFunction } from "./library";
  *  jest.mock("./library");
  *
  *  const mockMyFunction = myFunction as jest.MockedFunction<typeof myFunction>;
  *  expect(mockMyFunction.mock.calls[0][0]).toBe(42);
*/

नोट: जब आप करते हैं const mockMyFunction = myFunctionऔर फिर कुछ पसंद mockFunction.mockReturnValue('foo')करते हैं, तो आप बदल रहे हैंmyFunction

स्रोत: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jest/index.d.ts#L1089


4

उपयोग as jest.Mockऔर कुछ नहीं

defaultटीएस-जेस्ट के रूप में निर्यात किए गए मॉड्यूल का मजाक उड़ाने का सबसे संक्षिप्त तरीका है कि मैं मॉड्यूल के कास्टिंग के लिए वास्तव में फोड़े के बारे में सोच सकता हूं jest.Mock

कोड:

import myDep from '../dependency' // No `* as` here

jest.mock('../dependency')

it('does what I need', () => {
  // Only diff with pure JavaScript is the presence of `as jest.Mock`
  (myDep as jest.Mock).mockReturnValueOnce('return')

  // Call function that calls the mocked module here

  // Notice there's no reference to `.default` below
  expect(myDep).toHaveBeenCalled()
})

लाभ:

  • defaultपरीक्षण कोड में कहीं भी संपत्ति का उल्लेख करने की आवश्यकता नहीं है - आप इसके बजाय वास्तविक निर्यात फ़ंक्शन नाम का संदर्भ देते हैं,
  • आप निर्यात के नाम का मजाक उड़ाने के लिए उसी तकनीक का उपयोग कर सकते हैं,
  • कोई * asआयात बयान में,
  • का उपयोग कर कोई जटिल कास्टिंग typeofकीवर्ड ,
  • कोई अतिरिक्त निर्भरता की तरह mocked

मैं आपसे प्यार करता हूं, आखिरकार 4 घंटे के बाद मेरी तलाश खत्म हो जाती है।
LoXatoR

0

हाल ही में एक पुस्तकालय एक बेबल प्लगइन के साथ इस समस्या को हल करता है: https://github.com/userlike/joke

उदाहरण:

import { mock, mockSome } from 'userlike/joke';

const dep = mock(import('./dependency'));

// You can partially mock a module too, completely typesafe!
// thisIsAMock has mock related methods
// thisIsReal does not have mock related methods
const { thisIsAMock, thisIsReal } = mockSome(import('./dependency2'), () => ({ 
  thisIsAMock: jest.fn() 
}));

it('should do what I need', () => {
  dep.mockReturnValueOnce('return');
}

जागरूक रहें depऔर mockReturnValueOnceपूरी तरह से सुरक्षित हैं। शीर्ष पर, tsserver को पता है कि depencencyआयात किया गया था और उसे सौंपा गया थाdep इसलिए सभी स्वचालित रिफैक्टरिंग जो tsserver समर्थन भी काम करेगा।

नोट: मैं पुस्तकालय को बनाए रखता हूं।


0

यह बदसूरत है, और वास्तव में इस कुरूपता से दूर हो रहा है यही कारण है कि मैं भी इस सवाल को देखा, लेकिन एक मॉड्यूल नकली से मजबूत टाइपिंग पाने के लिए, आप इस तरह से कुछ कर सकते हैं:

const myDep = (require('./dependency') as import('./__mocks__/dependency')).default;

jest.mock('./dependency');

सुनिश्चित करें कि आपको './dependency'सीधे मॉक की बजाय आवश्यकता है , या आपको दो अलग-अलग इंस्टेंटेशन मिलेंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.