Jest 的模拟常量不起作用(同一测试文件中的多个模拟)
Mocking constant with Jest not working (Multiple mocks in same test file)
我遇到的问题是在 jest.doMock
之后组件中的模拟常量没有改变。
看看minimal repo。
我尝试使用 mock
而不是 doMock
- 同样的错误。
App.test.js
import React from "react"
import App from './App'
import '@testing-library/jest-dom'
import { render } from "@testing-library/react";
describe('testing app.js', () => {
// To reset manually mocked values
beforeEach(() => {
jest.resetModules()
});
test("SET CONSTANT TO 1", () => {
jest.doMock('./myConstants.js', () => ({
CONSTANT: {
NUMBER: 1
}
}))
const { getByText, getByLabelText } = render(<App />)
expect(getByText('1')).toBeInTheDocument()
})
test("SET CONSTANT TO 3", () => {
jest.doMock('./myConstants.js', () => ({
CONSTANT: {
NUMBER: 3
}
}))
const { getByText, getByLabelText } = render(<App />)
expect(getByText('3')).toBeInTheDocument()
})
})
App.js
import React from "react"
import { CONSTANT } from './myConstants.js'
console.log(CONSTANT)
const App = () => {
return (
<div>
{CONSTANT.NUMBER}
</div>
);
}
export default App;
myConstants.js:
export const CONSTANT = { NUMBER: 2 }
以上两个测试都失败了。其中之一的输出是:
TestingLibraryElementError: Unable to find an element with the text: 3. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
<body>
<div>
<div>
2
</div>
</div>
</body>
29 | }))
30 | const { getByText, getByLabelText } = render(<App />)
> 31 | expect(getByText('3')).toBeInTheDocument()
扩展解决方案
虽然提供的解决方案运行完美,但我不想重写我要测试的每个组件(通过添加 require(...)
)。解决方法是使用 import("./App").then((module)
import React from "react"
import App from './App'
import '@testing-library/jest-dom'
import { render } from "@testing-library/react";
describe('testing app.js', () => {
// To reset manually mocked values
beforeEach(() => {
jest.resetModules()
});
jest.doMock('./myConstants.js', () => {
return {
__esModule: true,
CONSTANT: {
NUMBER: 1
}
}
})
test("SET CONSTANT TO 1", () => {
// Wait for mock done
return import('./myConstants.js').then((constants) => {
console.log(constants.CONSTANT.NUMBER)
expect(constants.CONSTANT.NUMBER).toBe(1)
import("./App").then((module) => {
const { getByText, getByLabelText } = render(<module.default />)
expect(getByText('1')).toBeInTheDocument()
})
})
})
})
使用 jest.doMock
比您想象的要复杂得多。基本上,它需要您按照 https://jestjs.io/docs/en/jest-object#jestdomockmodulename-factory-options.
中所述执行几个步骤
这意味着您必须更改测试以满足上述要求:
test("SET CONSTANT TO 1", () => {
jest.doMock('./myConstants.js', () => {
return {
__esModule: true,
CONSTANT: {
NUMBER: 1
}
}
})
// Wait for mock done
return import('./myConstants.js').then(() => {
const { getByText, getByLabelText } = render(<App />)
expect(getByText('1')).toBeInTheDocument()
})
})
// While you also require your code right before using instead of `require` at the top level:
const App = () => {
// Require to use it right before using it
const { CONSTANT } = require('./myConstants.js');
return (
<div>
{CONSTANT.NUMBER}
</div>
);
}
我猜我们也可以通过仍然使用 jest.mock
直接改变模拟值,如下所示:
import React from "react"
import App from './App'
import '@testing-library/jest-dom'
import { render } from "@testing-library/react";
import { CONSTANT} from "./myConstants";
jest.mock('./myConstants.js', () => ({
CONSTANT: {
NUMBER: 0,
}
}))
describe('testing app.js', () => {
// To reset manually mocked values
beforeEach(() => {
jest.resetModules()
});
test("SET CONSTANT TO 1", () => {
// Mutate directly mocked value by setting our desired value
CONSTANT.NUMBER = 1;
const { getByText, getByLabelText } = render(<App />)
expect(getByText('1')).toBeInTheDocument()
})
test("SET CONSTANT TO 3", () => {
// Likewise we set it as 3
CONSTANT.NUMBER = 3;
const { getByText, getByLabelText } = render(<App />)
expect(getByText('4')).toBeInTheDocument()
})
})
我遇到的问题是在 jest.doMock
之后组件中的模拟常量没有改变。
看看minimal repo。
我尝试使用 mock
而不是 doMock
- 同样的错误。
App.test.js
import React from "react"
import App from './App'
import '@testing-library/jest-dom'
import { render } from "@testing-library/react";
describe('testing app.js', () => {
// To reset manually mocked values
beforeEach(() => {
jest.resetModules()
});
test("SET CONSTANT TO 1", () => {
jest.doMock('./myConstants.js', () => ({
CONSTANT: {
NUMBER: 1
}
}))
const { getByText, getByLabelText } = render(<App />)
expect(getByText('1')).toBeInTheDocument()
})
test("SET CONSTANT TO 3", () => {
jest.doMock('./myConstants.js', () => ({
CONSTANT: {
NUMBER: 3
}
}))
const { getByText, getByLabelText } = render(<App />)
expect(getByText('3')).toBeInTheDocument()
})
})
App.js
import React from "react"
import { CONSTANT } from './myConstants.js'
console.log(CONSTANT)
const App = () => {
return (
<div>
{CONSTANT.NUMBER}
</div>
);
}
export default App;
myConstants.js:
export const CONSTANT = { NUMBER: 2 }
以上两个测试都失败了。其中之一的输出是:
TestingLibraryElementError: Unable to find an element with the text: 3. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
<body>
<div>
<div>
2
</div>
</div>
</body>
29 | }))
30 | const { getByText, getByLabelText } = render(<App />)
> 31 | expect(getByText('3')).toBeInTheDocument()
扩展解决方案
虽然提供的解决方案运行完美,但我不想重写我要测试的每个组件(通过添加 require(...)
)。解决方法是使用 import("./App").then((module)
import React from "react"
import App from './App'
import '@testing-library/jest-dom'
import { render } from "@testing-library/react";
describe('testing app.js', () => {
// To reset manually mocked values
beforeEach(() => {
jest.resetModules()
});
jest.doMock('./myConstants.js', () => {
return {
__esModule: true,
CONSTANT: {
NUMBER: 1
}
}
})
test("SET CONSTANT TO 1", () => {
// Wait for mock done
return import('./myConstants.js').then((constants) => {
console.log(constants.CONSTANT.NUMBER)
expect(constants.CONSTANT.NUMBER).toBe(1)
import("./App").then((module) => {
const { getByText, getByLabelText } = render(<module.default />)
expect(getByText('1')).toBeInTheDocument()
})
})
})
})
使用 jest.doMock
比您想象的要复杂得多。基本上,它需要您按照 https://jestjs.io/docs/en/jest-object#jestdomockmodulename-factory-options.
这意味着您必须更改测试以满足上述要求:
test("SET CONSTANT TO 1", () => {
jest.doMock('./myConstants.js', () => {
return {
__esModule: true,
CONSTANT: {
NUMBER: 1
}
}
})
// Wait for mock done
return import('./myConstants.js').then(() => {
const { getByText, getByLabelText } = render(<App />)
expect(getByText('1')).toBeInTheDocument()
})
})
// While you also require your code right before using instead of `require` at the top level:
const App = () => {
// Require to use it right before using it
const { CONSTANT } = require('./myConstants.js');
return (
<div>
{CONSTANT.NUMBER}
</div>
);
}
我猜我们也可以通过仍然使用 jest.mock
直接改变模拟值,如下所示:
import React from "react"
import App from './App'
import '@testing-library/jest-dom'
import { render } from "@testing-library/react";
import { CONSTANT} from "./myConstants";
jest.mock('./myConstants.js', () => ({
CONSTANT: {
NUMBER: 0,
}
}))
describe('testing app.js', () => {
// To reset manually mocked values
beforeEach(() => {
jest.resetModules()
});
test("SET CONSTANT TO 1", () => {
// Mutate directly mocked value by setting our desired value
CONSTANT.NUMBER = 1;
const { getByText, getByLabelText } = render(<App />)
expect(getByText('1')).toBeInTheDocument()
})
test("SET CONSTANT TO 3", () => {
// Likewise we set it as 3
CONSTANT.NUMBER = 3;
const { getByText, getByLabelText } = render(<App />)
expect(getByText('4')).toBeInTheDocument()
})
})