使用Jasmine+Karma测试时SpyOn报'B无setter/不可写'错误的解决咨询
Fixing "B is not declared writable or has no setter" in Jasmine Tests for Rollup-Compiled Code
Let's break down why you're hitting this error and walk through the fixes step by step.
Why the Error Happens
Your test has two key issues:
- B isn't exported: In your original code, you only export
A, somainFunctionsdoesn't contain aBproperty at all. Trying to spy on a non-existent property is invalid. - Const exports are non-writable: Even if you did export
Bwithconst, ES module exports declared withconstare read-only by default. Jasmine'sspyOnneeds to replace the function, which fails on non-writable properties.
Solution 1: Wrap Functions in an Object (Recommended)
The cleanest way to make your functions testable is to encapsulate them in an object. Object properties are writable by default, so Jasmine can spy on them without extra work.
Update Your Main Code (main.js)
export const appFunctions = { B: () => { console.log("B is called"); }, A: () => { appFunctions.B(); } };
Write the Test (test.js)
import { appFunctions } from './main.js'; describe('When calling function A', function() { beforeEach(() => { // Spy on B and mock its implementation (use .callThrough() if you want to keep the original behavior) spyOn(appFunctions, 'B').and.stub(); // Call the function we're testing appFunctions.A(); }); it('should invoke function B', function() { expect(appFunctions.B).toHaveBeenCalled(); }); });
Solution 2: Export B and Make It Writable
If you prefer to keep individual function exports, you can export B explicitly and modify its writability before spying on it.
Update Your Main Code (main.js)
export const B = () => { console.log("B is called"); }; export const A = () => { B(); };
Write the Test (test.js)
import * as mainFunctions from './main.js'; describe('When calling function A', function() { beforeEach(() => { // Make B writable so Jasmine can replace it with a spy Object.defineProperty(mainFunctions, 'B', { writable: true }); // Set up the spy spyOn(mainFunctions, 'B'); // Call A mainFunctions.A(); }); it('should invoke function B', function() { expect(mainFunctions.B).toHaveBeenCalled(); }); });
Why This Works
- Object encapsulation: By putting
AandBin an object, we avoid the read-only restriction ofconstexports, making it easy for Jasmine to spy onB. - Writable export adjustment: When using individual exports,
Object.definePropertyoverrides the read-only setting, allowing Jasmine to replaceBwith a spy function.
内容的提问来源于stack exchange,提问作者dilusha_dasanayaka
相关产品推荐
相关产品推荐

