18

I have following code in my component

var rect = ReactDOM.findDOMNode(this).getBoundingClientRect();

I use d3js and render graph in the component. But when I run test there are any svg tags. I assume that it happens because all rect's fields equals 0.

Here is output for console.log(rect) in browser:

ClientRect {top: 89, right: 808, bottom: 689, left: 8, width: 800…}

and when I run test:

{ bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0 }

So is there a way to set size of the element?

3 Answers 3

50

My solution is to mock getBoundingClientRect (I'm currently using jest 16.0.1)

describe('Mock `getBoundingClientRect`', () => {
    beforeEach(() => {
        Element.prototype.getBoundingClientRect = jest.fn(() => {
            return {
                width: 120,
                height: 120,
                top: 0,
                left: 0,
                bottom: 0,
                right: 0,
            }
        });
    });
    it('should mock `getBoundingClientRect`', () => {
        const element = document.createElement('span');
        const rect = element.getBoundingClientRect();
        expect(rect.width).toEqual(120);
    });

});

Sign up to request clarification or add additional context in comments.

3 Comments

thanks for the answer. Just wondering, where is the "Element" came from?
@WayneChiu AFAIK, jest uses jsdom to mock DOM classes (such as Element, etc) - github.com/tmpvar/jsdom
N.B. If you have multiple describes that have specific cases for getBoundingClientRect, you'll need to set this mock again for that particular describe, since the global objects prototype is being mutated
2

Don't forget to put the original value of getBoundingClientRect back, because changing it might affect other tests.

Also, no need to do it in beforeEach: beforeAll will do.

describe("Mock `getBoundingClientRect`", () => {
  let boundingClientRect;

  const originalGetBoundingClientRect = Element.prototype.getBoundingClientRect;

  beforeAll(() => {
    Element.prototype.getBoundingClientRect = () => boundingClientRect;
  });

  afterAll(() => {
    Element.prototype.getBoundingClientRect = originalGetBoundingClientRect;
  });

  it("should mock `getBoundingClientRect`", () => {
    const element = document.createElement("div");
    boundingClientRect = new DOMRect(0, 0, 120, 120);
    const rect = element.getBoundingClientRect();
    expect(rect.width).toEqual(120);
  });
});


I took the idea from this answer

Comments

0

The existing answers mock Element.prototype.getBoundingClientRect. This will affect the apparent size of all DOM elements in your tests.

If you know what element you care about in advance, you can mock getBoundingClientRect on a single element. This does not affect the apparent size of other elements. If you want two elements to have different sizes in the same test, this is the way you need to do it.

describe("Mock `getBoundingClientRect` on a single element", () => {
  it("should mock `getBoundingClientRect`", () => {
    const myElement = document.createElement("div");
    myElement.getBoundingClientRect = jest.fn(() => 
      new DOMRect(0, 0, 120, 120);
    );
    const rect = element.getBoundingClientRect();
    expect(rect.width).toEqual(120);
  });
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.