Reputation: 33
I have a function attached to an even listener that checks if you've clicked off of a pop up or in it, and closes it if you've clicked off it. It uses various properties on the window and document object to check these things, as well as getBoundingClientRect()
to get the popup's position.
The issue I'm running into is I can't figure out how to simulate all of that in a test. I've seen that in Jest you use the global object as the window object when mocking things?
Here's my function that checks the positioning & click:
popoverEscape = e => {
const popover = this.panelEl.nativeElement.getBoundingClientRect();
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const left = popover.left + scrollLeft
const right = popover.left + scrollLeft + popover.width
const top = popover.top + scrollTop
const bottom = popover.top + scrollTop + popover.height
if(!this.isBetween(e.clientX, left, right) || !this.isBetween(e.clientY, top, bottom)){
this.closePopover()
}
};
isBetween(n, a, b) {
return (n - a) * (n - b) <= 0
}
Upvotes: 3
Views: 2047
Reputation: 102457
Here is the unit test solution:
index.ts
:
export class SomeComponent {
panelEl = {
nativeElement: document.createElement('div'),
};
popoverEscape = (e) => {
const popover = this.panelEl.nativeElement.getBoundingClientRect();
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const left = popover.left + scrollLeft;
const right = popover.left + scrollLeft + popover.width;
const top = popover.top + scrollTop;
const bottom = popover.top + scrollTop + popover.height;
if (!this.isBetween(e.clientX, left, right) || !this.isBetween(e.clientY, top, bottom)) {
this.closePopover();
}
};
isBetween(n, a, b) {
return (n - a) * (n - b) <= 0;
}
closePopover() {}
}
index.test.ts
:
import { SomeComponent } from './';
describe('59737707', () => {
afterEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});
describe('#popoverEscape', () => {
it('should close popover if first isBetween return falsy', () => {
Object.defineProperty(window, 'pageXOffset', { value: 100 });
document.documentElement.scrollTop = 200;
const comp = new SomeComponent();
const rect = { left: 10, width: 20, top: 10, height: 50 };
jest.spyOn(comp.panelEl.nativeElement, 'getBoundingClientRect').mockReturnValueOnce(rect as DOMRect);
jest.spyOn(comp, 'isBetween').mockReturnValueOnce(false);
comp.closePopover = jest.fn();
const mEvent = { clientX: 100, clientY: 200 };
comp.popoverEscape(mEvent);
expect(comp.panelEl.nativeElement.getBoundingClientRect).toBeCalledTimes(1);
expect(comp.closePopover).toBeCalledTimes(1);
expect(comp.isBetween).toBeCalledTimes(1);
});
it('should close popover if second isBetween return falsy', () => {
Object.defineProperty(window, 'pageXOffset', { value: 100 });
document.documentElement.scrollTop = 200;
const comp = new SomeComponent();
const rect = { left: 10, width: 20, top: 10, height: 50 };
jest.spyOn(comp.panelEl.nativeElement, 'getBoundingClientRect').mockReturnValueOnce(rect as DOMRect);
jest
.spyOn(comp, 'isBetween')
.mockReturnValueOnce(true)
.mockReturnValueOnce(false);
comp.closePopover = jest.fn();
const mEvent = { clientX: 100, clientY: 200 };
comp.popoverEscape(mEvent);
expect(comp.panelEl.nativeElement.getBoundingClientRect).toBeCalledTimes(1);
expect(comp.closePopover).toBeCalledTimes(1);
expect(comp.isBetween).toBeCalledTimes(2);
});
});
});
Unit test results with coverage report:
PASS src/stackoverflow/59737707/index.test.ts (14.308s)
59737707
#popoverEscape
✓ should close popover if first isBetween return falsy (12ms)
✓ should close popover if second isBetween return falsy (3ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 94.12 | 75 | 50 | 93.75 | |
index.ts | 94.12 | 75 | 50 | 93.75 | 21 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 16.602s
You can do the same way for the uncovered branch and function and improve the test coverage to 100%.
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59737707
Upvotes: 1