I try to test a function recordItemColor
but no matter what I try, the checks for instanceof
don't recognize the Object.prototype
type.
I tried a lot, but nothing works. Maybe it is something about jsdom? I would be even happy for other suggestions how to check if the pass target is an HTMLElment or an SVGElement.
Here is the function:
import { type StepType } from './handleClickableElement';
const pushStep = (steps: StepType[], step: StepType): void => {
steps.push(step);
};
export const recordItemColor = (steps: StepType[], target: Element): void => {
if (target instanceof HTMLElement) {
const computedStyle = window.getComputedStyle(target);
pushStep(steps, {
target: target.id,
color: computedStyle.backgroundColor,
});
}
if (target instanceof SVGElement) {
const computedStyle = window.getComputedStyle(target);
pushStep(steps, {
target: target.id,
color: computedStyle.fill,
});
}
};
Here is the test:
import { expect } from 'chai';
import { recordItemColor } from './recordItemColor';
import { StepType } from './handleClickableElement';
import { JSDOM } from 'jsdom';
const { window } = new JSDOM();
const { document } = window;
(global as any).document = document;
(global as any).window = window;
describe('recordItemColor', () => {
beforeEach(() => {
const div = document.createElement('div');
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
div.id = 'test-div';
path.id = 'test-svg';
div.style.backgroundColor = 'red';
path.setAttribute('fill', 'blue');
document.body.appendChild(div);
document.body.appendChild(path);
});
afterEach(() => {
const div = document.getElementById('test-div');
const path = document.getElementById('test-svg');
if (div) div.remove();
if (path) path.remove();
});
it('records item color for HTMLElement', () => {
const steps: StepType[] = [];
const target = document.getElementById('test-div');
recordItemColor(steps, target!);
expect(steps).to.deep.equal([{ target: 'test-div', color: 'red' }]);
});
it('records item color for SVGElement', () => {
const steps: StepType[] = [];
const target = document.getElementById('test-svg');
expect(target).to.exist;
recordItemColor(steps, target!);
expect(steps).to.deep.equal([{ target: 'test-svg', color: 'blue' }]);
});
});
My jsdom setup:
import { JSDOM } from 'jsdom';
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
const { window } = dom;
(global as any).HTMLElement = window.HTMLElement;
(global as any).SVGElement = window.SVGElement;
(global as any).document = dom.window.document;
(global as any).window = dom.window;
(global as any).navigator = dom.window.navigator;
When I log the target at the start of the function, it is not null
. The node name appears to be DIV
or SVG
as expected and when I use console.log(Object.prototype.toString.call(target))
it logs the correct type which is a HTMLDivElement
or SVGElement
.
I set the type in the jsdom setup.ts
, which I provide above. Otherwise, the code throws an exception at the check with the error: Includes HTMLElement.prototype: false
. I found this solution in an issue on the repository of jsdom.
instanceof
checks to see if an object is an instance of a particular constructor function. AnHTMLElement
constructor in one realm is not the same as the same-named constructor in another realm.target
you could use to determine its type? target.tagName?