Настройка
Я пишу плагин для сайта. Он собирается добавить в DOM элементы, стилизованные через плагин CSS. Я ожидаю, что стилизация будет ограничена плагином, то есть никакие элементы вне плагина не должны изменять свой внешний вид после того, как плагин включен на веб-странице.
Я запускаю интеграционные тесты с использованием Cypress. Как я могу утверждать, что стили всех существующих элементов остаются неизменными, когда плагин включен на страницу? У меня есть доступ к странице до и после загрузки плагина.
Подход
Я думаю, что это должно работать:
cy.visit('theURL');
getStyles().then(oldStyles => { // Get the styles of the elements
mountPlugin(); // Mount the plugin (including CSS)
getStyles().then(newStyles => { // Get the (possibly changed) styles
newStyles.forEach((newStyle, i) => // Compare each element’s style after
expect(newStyle).to.equal(oldStyles[i]) //+ mounting to the state before mounting
);
});
});
function getStyles() {
return cy.get('.el-on-the-page *').then((elements) => { // Get all elements below a certain root
const styles: CSSStyleDeclaration[] = []
elements.each((_, el) => { // Get each element’s style
styles.push(window.getComputedStyle(el)); //+ and put them it an array
});
return styles; // Return the styles
});
}
Проблемы
Числа c ключи в CSSStyleDeclaration
Строка expect(newStyle).to.equal(oldStyles[i])
завершается ошибкой, поскольку oldStyles[i]
содержит цифры c ключи, которые содержат только имена свойств. Например,
// oldStyles[i] for some i
{
cssText: "animation-delay: 0s; animation-direction: normal; […more]"
length: 281
parentRule: null
cssFloat: "none"
0: "animation-delay" // <-- These elements only list property names, not values
... //+
280: "line-break" //+
alignContent: "normal" // <-- Only here there are actual property values
... //+
zoom: "1" //+
...
}
Обходной путь
Я исправляю это, вручную обходя клавиши CSS и проверяя, является ли ключ числом. Однако эти цифры c отображаются только в oldStyles
, а не в newStyles
. Я пишу это, потому что это выглядит подозрительно для меня, и я предполагаю, что ошибка уже может быть там.
// Instead of newStyles.foreach(…) in the first snippet
newStyles.forEach((newStyle, i) => {
for (const key in newStyle) {
if(isNaN(Number(key))) {
expect(newStyle[key]).to.equal(oldStyles[i][key]);
}
}
});
Пустые значения свойств
Я делаю неявное предположение, что здесь DOM фактически загружен и применяет стили. Насколько я понимаю, вызов getLinkListStyles
на cy.get
должен быть запланирован на выполнение только после того, как cy.visit
дождался, пока окно не запустит событие load
.
Из документации Cypress :
cy.visit()
разрешается, когда на удаленной странице запускается событие load
.
Однако, с использованием вышеупомянутого временного решения, я получаю пустую строку для CSS правила в oldStyles
. Например:
//oldStyles[i] for some i
{
cssText: "animation-delay: ; animation-direction: ; animation-duration: ; […more]"
length: 0
parentRule: null
cssFloat: ""
alignContent: ""
...
}
Попытки решения
Обратите внимание, что это поведение не меняется, когда я явно использую обратный вызов с cy.visit
, то есть:
cy.visit(Cypress.env('theURL')).then(()=>{
getStyles().then((oldStyles) => {
// (rest as above)
Ни то, ни другое cy.wait(15000)
в начале getStyles()
:
function getStyles() {
cy.wait(15000); // The page has definitely loaded and applied all styles by now
cy.get('.el-on-the-page *').then((elements) => {
...