Saat menguji modul yang memiliki ketergantungan pada file yang berbeda. Ketika menugaskan modul itu menjadi jest.Mock
skrip ketikan memberikan kesalahan bahwa metode mockReturnThisOnce
(atau metode jest.Mock lainnya) tidak ada pada ketergantungan, ini karena sebelumnya diketik. Apa cara yang tepat untuk mendapatkan ketikan untuk mewarisi tipe dari jest.Mock?
Berikut ini contoh singkatnya.
Ketergantungan
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')
}
Saya merasa ini adalah kasus penggunaan yang sangat umum dan tidak yakin cara mengetiknya dengan benar. Bantuan apa pun akan sangat dihargai!
javascript
unit-testing
typescript
jestjs
Philip Chmalts
sumber
sumber
import
dievaluasi terlebih dahulu, tidak peduli jika Anda meletakkan beberapa kode sebelum mengimpor. Jadi ini tidak akan berhasil.mock...
Jawaban:
Anda dapat menggunakan tipe casting dan Anda
test.ts
akan terlihat seperti ini: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'); });
Transpiler TS tidak mengetahui adanya
jest.mock('../dependency');
perubahan tipedep
sehingga Anda harus menggunakan tipe casting. Karena importdep
bukanlah definisi tipe, Anda harus mendapatkan tipenyatypeof dep.default
.Berikut adalah beberapa pola berguna lainnya yang saya temukan selama bekerja dengan Jest dan TS
Ketika elemen yang diimpor adalah sebuah kelas maka Anda tidak harus menggunakan typeof misalnya:
import { SomeClass } from './SomeClass'; jest.mock('./SomeClass'); const mockedClass = <jest.Mock<SomeClass>>SomeClass;
Solusi ini juga berguna ketika Anda harus memalsukan beberapa modul asli node:
import { existsSync } from 'fs'; jest.mock('fs'); const mockedExistsSync = <jest.Mock<typeof existsSync>>existsSync;
Jika Anda tidak ingin menggunakan mock otomatis bercanda dan lebih suka membuat yang manual
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()
membuat contoh objek tiruanTestedClassDependency
dapat berupa kelas atau jenis atau antarmukasumber
jest.fn(() =>...
alih-alihjest.fn<TestedClassDependency>(() =>...
(saya baru saja menghapus jenis casting setelah jest.fn) karena IntelliJ mengeluh. Kalau tidak, jawaban ini membantu saya, terima kasih! Menggunakan ini di package.json saya: "@ types / jest": "^ 24.0.3"jest.mock('./SomeClass');
dalam kode di atas?<jest.Mock<SomeClass>>SomeClass
ekspresi menghasilkan kesalahan TS bagi saya: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)
Gunakan
mocked
helper darits-jest
seperti yang dijelaskan di sini// 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) })
dan jika
tslint
ts-jest
ada dalam dependensi dev Anda,tambahkan aturan ini ke
tslint.json
:"no-implicit-dependencies": [true, "dev"]
sumber
ts-jest
dan kelas: github.com/tbinna/ts-jest-mock-examples dan pos ini: stackoverflow.com/questions/58639737/…Saya menggunakan pola dari @ types / jest / index.d.ts tepat di atas tipe def untuk Mocked (baris 515):
import { Api } from "../api"; jest.mock("../api"); const myApi: jest.Mocked<Api> = new Api() as any; myApi.myApiMethod.mockImplementation(() => "test");
sumber
const myApi = new Api() as jest.Mocked<Api>;
jest.Mock<Api>
. Anda harus pergi denganconst myApi = new Api() as any as jest.Mock<Api>
dan saya akan mengatakan yang di atas terlihat sedikit lebih baik daripada pernyataan ganda."strict": true
di tsconfig.json. Ini mencakup hal-hal sepertinoImplicitAny
,strictNullChecks
dll., Jadi Anda tidak perlu menyetelnya ke true untuk mereka satu per satu.myApi
? Itu tidak akan secara umum menghentikan semua instance lain yang diprakarsai oleh kelasApi
dalam modul yang sedang diuji, bukan?Ada dua solusi, keduanya adalah fungsi casting yang diinginkan
1) Gunakan jest.MockedFunction
import * as dep from './dependency'; jest.mock('./dependency'); const mockMyFunction = dep.myFunction as jest.MockedFunction<typeof dep.myFunction>;
2) Gunakan jest.Mock
import * as dep from './dependency'; jest.mock('./dependency'); const mockMyFunction = dep.default as jest.Mock;
Tidak ada perbedaan antara kedua solusi ini. Yang kedua lebih pendek dan oleh karena itu saya menyarankan untuk menggunakan yang itu.
Kedua solusi casting memungkinkan untuk memanggil fungsi lelucon apa pun di
mockMyFunction
sukamockReturnValue
ataumockResolvedValue
https://jestjs.io/docs/en/mock-function-api.htmlmockMyFunction.mockReturnValue('value');
mockMyFunction
dapat digunakan secara normal untuk harapanexpect(mockMyFunction).toHaveBeenCalledTimes(1);
sumber
Pemeran
as jest.Mock
Cukup casting fungsi untuk
jest.Mock
melakukan trik:(dep.default as jest.Mock).mockReturnValueOnce('return')
sumber
Inilah yang saya lakukan dengan [email protected] dan [email protected] :
sumber:
class OAuth { static isLogIn() { // return true/false; } static getOAuthService() { // ... } }
uji:
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 }); });
Ini adalah cara memalsukan kelas non-default dan metode statisnya:
jest.mock('../src/to/the/OAuth', () => ({ OAuth: class { public static getOAuthService() { return { getAuthorizationUrl() { return ''; } }; } } }));
Berikut ini adalah beberapa jenis konversi dari jenis kelas Anda ke
jest.MockedClass
atau semacamnya. Tapi selalu berakhir dengan kesalahan. Jadi saya langsung menggunakannya, dan berhasil.test('Some test', () => { OAuth.isLogIn = jest.fn().mockImplementationOnce(() => { return false; }); });
Tapi, jika itu sebuah fungsi, Anda bisa mengejeknya dan melakukan percakapan tipe.
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 >;
sumber
Saya telah menemukan ini di
@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); */
Catatan: Ketika Anda melakukannya
const mockMyFunction = myFunction
dan kemudian sesuatu sepertimockFunction.mockReturnValue('foo')
, Anda juga berubahmyFunction
.Sumber: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jest/index.d.ts#L1089
sumber
Gunakan
as jest.Mock
dan tidak ada yang lainCara paling ringkas untuk mengejek modul yang diekspor seperti
default
di ts-jest yang dapat saya anggap benar-benar bermuara pada casting modul sebagaijest.Mock
.Kode:
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() })
Manfaat:
default
properti di mana pun dalam kode pengujian - Anda merujuk nama fungsi yang diekspor sebenarnya,* as
dalam pernyataan impor,typeof
kata kunci,mocked
.sumber
Pustaka terbaru memecahkan masalah ini dengan plugin babel: https://github.com/userlike/joke
Contoh:
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'); }
Sadarilah itu
dep
danmockReturnValueOnce
sepenuhnya aman. Di atas, tsserver menyadari bahwadepencency
itu diimpor dan ditugaskandep
sehingga semua pemfaktoran ulang otomatis yang didukung tsserver akan bekerja juga.Catatan: Saya memelihara perpustakaan.
sumber