vitest/test/core/test/mocked.test.ts
Simon Abbott 9f887f3598
fix: automock getters and setters (#1903)
* fix: automock getters and setters

* refactor: do not mock getters/setters

Co-authored-by: Vladimir Sheremet <sleuths.slews0s@icloud.com>
2022-08-30 18:48:57 +03:00

141 lines
4.5 KiB
TypeScript

import { assert, describe, expect, test, vi, vitest } from 'vitest'
// @ts-expect-error not typed module
import { value as virtualValue } from 'virtual-module'
import { two } from '../src/submodule'
import * as mocked from '../src/mockedA'
import { mockedB } from '../src/mockedB'
import { MockedC, asyncFunc, exportedStream } from '../src/mockedC'
import MockedDefault, { MockedC as MockedD } from '../src/mockedD'
import * as globalMock from '../src/global-mock'
vitest.mock('../src/submodule')
vitest.mock('virtual-module', () => ({ value: 'mock' }))
vitest.mock('../src/mockedC')
vitest.mock('../src/mockedD')
/**
* Get a property descriptor from an object.
*
* This is different from `Object.getOwnPropertyDescriptor` because it recurses
* into the prototype chain until it either finds a match or reaches the end.
*
* @param object The object that contains the property.
* @param property The property.
* @returns The property's descriptor, or undefined if no matching property was found.
*/
function getPropertyDescriptor(object: any, property: PropertyKey) {
for (let o = object; o; o = Object.getPrototypeOf(o)) {
const descriptor = Object.getOwnPropertyDescriptor(o, property)
if (descriptor)
return descriptor
}
return undefined
}
test('submodule is mocked to return "two" as 3', () => {
assert.equal(3, two)
})
test('globally mocked files are mocked', () => {
// Mocked in setup.ts
expect(globalMock.mocked).toBe(true)
})
test('can mock esm', () => {
const spy = vi.spyOn(mocked, 'mockedA')
mockedB()
expect(spy).toHaveBeenCalled()
expect(spy).toHaveReturnedWith('A')
})
test('mocked exports should override original exports', () => {
expect(virtualValue).toBe('mock')
})
describe('mocked classes', () => {
test('should not delete the prototype', () => {
expect(MockedC).toBeTypeOf('function')
expect(MockedC.prototype.doSomething).toBeTypeOf('function')
expect(MockedC.prototype.constructor).toBe(MockedC)
})
test('should mock the constructor', () => {
const instance = new MockedC()
expect(instance.value).not.toBe(42)
expect(MockedC).toHaveBeenCalledOnce()
})
test('should mock functions in the prototype', () => {
const instance = new MockedC()
expect(instance.doSomething).toBeTypeOf('function')
expect(instance.doSomething()).not.toBe('A')
expect(MockedC.prototype.doSomething).toHaveBeenCalledOnce()
expect(MockedC.prototype.doSomething).not.toHaveReturnedWith('A')
})
test('should mock getters', () => {
const instance = new MockedC()
expect(instance).toHaveProperty('getOnlyProp')
const descriptor = getPropertyDescriptor(instance, 'getOnlyProp')
expect(descriptor?.get).toBeDefined()
expect(descriptor?.set).not.toBeDefined()
expect(instance.getOnlyProp).toBe(42)
// @ts-expect-error Assign to the read-only prop to ensure it errors.
expect(() => instance.getOnlyProp = 4).toThrow()
const getterSpy = vi.spyOn(instance, 'getOnlyProp', 'get').mockReturnValue(456)
expect(instance.getOnlyProp).toEqual(456)
expect(getterSpy).toHaveBeenCalledOnce()
})
test('should mock getters and setters', () => {
const instance = new MockedC()
expect(instance).toHaveProperty('getSetProp')
const descriptor = getPropertyDescriptor(instance, 'getSetProp')
expect(descriptor?.get).toBeDefined()
expect(descriptor?.set).toBeDefined()
expect(instance.getSetProp).toBe(123)
expect(() => instance.getSetProp = 4).not.toThrow()
const getterSpy = vi.spyOn(instance, 'getSetProp', 'get').mockReturnValue(789)
expect(instance.getSetProp).toEqual(789)
expect(getterSpy).toHaveBeenCalledOnce()
const setterSpy = vi.spyOn(instance, 'getSetProp', 'set')
instance.getSetProp = 159
expect(setterSpy).toHaveBeenCalledWith(159)
})
})
describe('default exported classes', () => {
test('should preserve equality for re-exports', () => {
expect(MockedDefault).toEqual(MockedD)
})
test('should preserve prototype', () => {
expect(MockedDefault.prototype.constructor).toBe(MockedDefault)
expect(MockedD.prototype.constructor).toBe(MockedD)
})
})
test('async functions should be mocked', () => {
expect(asyncFunc()).toBeUndefined()
expect(vi.mocked(asyncFunc).mockResolvedValue).toBeDefined()
vi.mocked(asyncFunc).mockResolvedValue('foo')
expect(asyncFunc()).resolves.toBe('foo')
})
// This is here because mocking streams previously caused some problems (#1671).
test('streams', () => {
expect(exportedStream).toBeDefined()
})