fstanis
fstanis

Reputation: 5534

Sinon - spy to wrap *any* property access on object

I have a function that looks roughly like this:

import {someLibraryMethod} from 'someLibrary';

function setFullWidth(el) {
  someLibraryMethod(el);
  el.setAttribute('width', '100%');
}

I'm testing this function by using Sinon to create a mock element that only supports setAttribute:

const fakeElement = {
  setAttribute: sinon.spy()
};
setFullWidth(fakeElement);
assert(fakeElement.setAttribute.calledWithExactly('width', '100%'));

The problem is that someLibraryMethod assumets el is an HTML element and tries to call some other methods on it, such as hasAttribute. I could add these as stubs or spies to fakeElement too, but I was wondering if Sinon has a way to create an object that will spy on any method or property access on it?

Something like:

const fakeElement = sinon.spyOnAnyPropety();
fakeElement.setAttribute(); // valid
fakeElement.hasAttribute(); // valid
fakeElement.foo(); // also valid
// some way to check which methods were called

Upvotes: 1

Views: 1984

Answers (1)

Lin Du
Lin Du

Reputation: 102257

You can use sinon.stub(obj) to

Stubs all the object’s methods.

E.g.

index.ts:

export function setFullWidth(el) {
  el.setAttribute('width', '100%');
  el.hasAttribute('width');
  el.foo();
}

index.spec.ts:

import { setFullWidth } from './';
import sinon, { SinonStubbedInstance } from 'sinon';
import { expect } from 'chai';

describe('58868361', () => {
  const fakeElement = {
    setAttribute(attr, value) {
      console.log('setAttribute');
    },
    hasAttribute(attr) {
      console.log('hasAttribute');
    },
    foo() {
      console.log('foo');
    },
  };
  afterEach(() => {
    sinon.restore();
  });
  it('should spy all methods of el', () => {
    const logSpy = sinon.spy(console, 'log');
    const stub: SinonStubbedInstance<typeof fakeElement> = sinon.stub(fakeElement);
    setFullWidth(fakeElement);
    expect(stub.setAttribute.calledWithExactly('width', '100%')).to.be.true;
    expect(stub.hasAttribute.calledWithExactly('width')).to.be.true;
    expect(stub.foo.calledOnce).to.be.true;
    expect(logSpy.callCount).to.be.equal(0);
    logSpy.restore();
  });

  it('should restore to original methods of el', () => {
    const logSpy = sinon.spy(console, 'log');
    setFullWidth(fakeElement);
    expect(logSpy.callCount).to.be.equal(3);
  });
});

Unit test result with 100% coverage:

  58868361
    ✓ should spy all methods of el
setAttribute
hasAttribute
foo
    ✓ should restore to original methods of el


  2 passing (13ms)

---------------|----------|----------|----------|----------|-------------------|
File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files      |      100 |      100 |      100 |      100 |                   |
 index.spec.ts |      100 |      100 |      100 |      100 |                   |
 index.ts      |      100 |      100 |      100 |      100 |                   |
---------------|----------|----------|----------|----------|-------------------|

Source code: https://github.com/mrdulin/mongoose5.x-lab/tree/master/src/stackoverflow/58868361

Upvotes: 1

Related Questions