Conversation
- Add `{ spy: true }` option to `rs.mock`, `rs.doMock`, `rs.mockRequire`, `rs.doMockRequire`
- When `spy: true`, module is auto-mocked but original implementations are preserved
- All exports are wrapped in spy functions that track calls while executing original code
- Add `MockModuleOptions` type with literal `{ spy: true }` (throws error for other values)
- Add e2e tests for spy mode with mockImplementation, mockReturnValue, unmock
- Update documentation with examples for factory function, rs.fn(), rs.mockObject(), and partial mock
Deploying rstest with
|
| Latest commit: |
3eb17ff
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6079ae64.rstest.pages.dev |
| Branch Preview URL: | https://mockspy.rstest.pages.dev |
rs.mock('module', { spy: true }) optionspy: true option in rs.mock()
There was a problem hiding this comment.
Pull request overview
Adds { spy: true } support to rs.mock()-family APIs so modules can be auto-mocked while preserving original implementations, with documentation and e2e coverage.
Changes:
- Extend core typings to accept
{ spy: true }for module mocking APIs. - Implement spy-mode handling in the webpack runtime mock hooks.
- Add e2e tests and update EN/ZH docs for the new spy behavior.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
packages/core/src/types/mock.ts |
Introduces MockModuleOptions and updates rs.mock/doMock/mockRequire/doMockRequire signatures to accept { spy: true }. |
packages/core/src/core/plugins/mockRuntimeCode.js |
Adds runtime support for { spy: true } across 4 mock entry points by wrapping original exports via mockObject(..., { spy: true }). |
e2e/mock/tests/mockSpy.test.ts |
Adds e2e coverage for rs.mock(..., { spy: true }) behavior (call tracking + preserving implementation). |
e2e/mock/tests/doMockSpy.test.ts |
Adds e2e coverage for rs.doMock(..., { spy: true }) behavior. |
website/docs/en/api/runtime-api/rstest/mock-modules.mdx |
Documents { spy: true } usage and reorganizes module mocking docs. |
website/docs/zh/api/runtime-api/rstest/mock-modules.mdx |
Same documentation updates for ZH. |
website/docs/en/api/runtime-api/rstest/mock-functions.mdx |
Updates examples to use { spy: true } in the module-mocking context. |
website/docs/zh/api/runtime-api/rstest/mock-functions.mdx |
Same example update for ZH. |
website/AGENTS.md |
Adds sentence-style heading capitalization guideline. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| __webpack_require__.r(__webpack_exports__); | ||
| for (const key in mockedModule) { | ||
| __webpack_require__.d(__webpack_exports__, { | ||
| [key]: () => mockedModule[key], | ||
| }); |
There was a problem hiding this comment.
rs.mock(..., { spy: true }) marks the replacement as an ESM module (__webpack_require__.r(__webpack_exports__)) and only re-exports enumerable keys from mockedModule. For CommonJS targets (where consumers use default-import interop via __webpack_require__.n), this can break import x from 'cjs-module' because there is no default export defined. Consider adding a default export (e.g., mapping to the spied module) when the original module is not __esModule, to preserve default-import behavior.
| rs.mocked(increment).mockReturnValueOnce(111); | ||
| rs.mocked(increment).mockReturnValueOnce(222); | ||
|
|
||
| expect(increment(1)).toBe(111); | ||
| expect(increment(1)).toBe(222); | ||
| // Falls back to previous mockReturnValue(999) |
There was a problem hiding this comment.
This test is order-dependent: it expects the third call to fall back to a mockReturnValue(999) configured in a previous test. If tests are reordered or run with isolation, this can become flaky. Set the baseline mockReturnValue within this test (or reset+configure in a beforeEach) so the test is self-contained.
| rs.mocked(increment).mockReturnValueOnce(111); | |
| rs.mocked(increment).mockReturnValueOnce(222); | |
| expect(increment(1)).toBe(111); | |
| expect(increment(1)).toBe(222); | |
| // Falls back to previous mockReturnValue(999) | |
| rs.mocked(increment).mockReturnValue(999); | |
| rs.mocked(increment).mockReturnValueOnce(111); | |
| rs.mocked(increment).mockReturnValueOnce(222); | |
| expect(increment(1)).toBe(111); | |
| expect(increment(1)).toBe(222); | |
| // Falls back to baseline mockReturnValue(999) set in this test |
| expect(increment).toHaveBeenCalledTimes(2); | ||
| expect(increment).toHaveBeenCalledWith(1); | ||
| expect(increment).toHaveBeenCalledWith(5); | ||
| expect(rs.isMockFunction(increment)).toBe(true); |
There was a problem hiding this comment.
These assertions can be flaky if this file’s tests run in a different order: rs.doMock(..., { spy: true }) may reuse an existing mock function (mockObject returns existing _isMockFunction values as-is), so call history can carry over between tests and make toHaveBeenCalledTimes(2) fail. Consider resetting mocks/modules (e.g., rs.resetAllMocks() / rs.resetModules() / rs.doUnmock(...)) in beforeEach/afterEach to keep tests isolated.
Summary
Support the
{ spy: true }option inrs.mock()and related APIs, allowing modules to be auto-mocked while preserving their original implementations.Features
{ spy: true }option tors.mock,rs.doMock,rs.mockRequire,rs.doMockRequirespy: true, all module exports are wrapped in spy functions that:toHaveBeenCalled,toHaveBeenCalledWith, etc.)MockModuleOptionstype with literal{ spy: true }(throws error for invalid values)Changes
packages/core/src/types/mock.ts: AddMockModuleOptionstypepackages/core/src/core/plugins/mockRuntimeCode.js: Handle{ spy: true }option in 4 mock functionse2e/mock/tests/mockSpy.test.ts: E2E tests for spy modee2e/mock/tests/doMockSpy.test.ts: E2E tests for doMock with spywebsite/docs/*/api/runtime-api/rstest/mock-modules.mdx: Documentation updateswebsite/docs/*/api/runtime-api/rstest/mock-functions.mdx: Documentation updateswebsite/AGENTS.md: Add heading-case guideline