JSDom can't set and retrieve CSS styles
Basic info:
- Node.js version: v10
- jsdom version: v11.10
Minimal reproduction case
As the title says, I can't set css styles, and get them later. It's sad since it means you can't use JSDom to inline your CSS.
At least its easy to reproduce:
const { JSDOM } = require("jsdom");
const options = {
url: "http://localhost/",
referrer: "http://aggressive.se",
contentType: "text/html",
userAgent: "AggressiveDev",
includeNodeLocations: false,
resources: "usable",
pretendToBeVisual: true,
runScripts: "dangerously",
};
const dom = new JSDOM(`<body></body>`, options);
window = dom.window
document = window.document;
var styleSheet = document.createElement("style");
styleSheet.setAttribute('type', 'text/css');
var head = document.getElementsByTagName("head")[0];
head.appendChild(styleSheet);
styleSheet = document.styleSheets[document.styleSheets.length - 1];
styleSheet.insertRule(".workingClass { dontAddThis }", 0);
var rule = styleSheet.cssRules[0];
var style = rule.style;
style.borderColor = "green";
console.log("rule.cssText gets selector but no css");
console.log(rule.cssText);
console.log("should be:\n.workingClass {border-color: green;}");
console.log("but using setProperty works (almost)");
style.setProperty("borderColor", "green")
console.log(rule.cssText);
console.log("cssText is wrong (still js keys)");
How does similar code behave in browsers?
(can be copy/pasted into browser after removing "window = dom.window") or jsbin: https://jsbin.com/sumadul/edit?js,console
I have a similar problem, insertRule can't be modified:
const $style = document.createElement('style');
document.head.appendChild($style);
const sheet = $style.sheet!;
const style = {
color: 'red'
};
const index = sheet.cssRules.length;
sheet.insertRule(`body { }`, index);
const rule = sheet.cssRules[index];
if (rule instanceof CSSStyleRule) {
Object.assign(rule.style, style);
}
console.log(rule.cssText);
// prints body {}
// should be body { color: red; }
This is open for almost 6 years. Will you accept a PR if I can implement the missing feature of updating rule.cssText?
I was investigating and it seems that the problem is that when the CSS property is not present in the rule when inserting you can't change it afterwards:
it('should not introduce CSS and className without debug option', () => {
const $style = document.createElement('style');
document.head.appendChild($style);
const sheet = $style.sheet!;
const index = sheet.cssRules.length;
sheet.insertRule(`body { color: blue }`, index);
const style = {
color: 'red',
background: 'green'
};
const rule = sheet.cssRules[index];
console.log({XXXX: rule.cssText});
console.log(rule);
if (rule instanceof CSSStyleRule) {
Object.assign(rule.style, style);
}
console.log({YYY: rule.cssText});
// body { color: red; }
});
I'm using version 20.0.3 with Jest 29.7.0
I've found a workaround that works and the good thing is that it will also work with CSS variables as a bonus:
const style = {
color: 'red',
background: 'black'
};
if (rule instanceof CSSStyleRule) {
const _style = rule.style; // this is needed to fix TypeScript bug
Object.entries(style).forEach(([prop, value]) => {
_style.setProperty(prop, value as any);
});
}
style.setProperty is a method that adds the style properly according to an implementation.