簡體   English   中英

如何斷言 HTML 元素在包含樣式表后不會改變其外觀?

[英]How can I assert that a HTML element does not change its appearance after a stylesheet has been included?

環境

我正在為網站編寫插件。 它將通過插件的 CSS 將元素添加到 DOM 中。 我希望樣式僅限於插件,即一旦插件被包含在網頁上,插件之外的任何元素都不應該改變它們的外觀。

我正在使用 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
    });
}

問題

CSSStyleDeclaration 中的數字鍵

expect(newStyle).to.equal(oldStyles[i])失敗,因為oldStyles[i]包含僅列出屬性名稱的數字鍵。 例如,

// 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 鍵並檢查鍵是否為數字來解決此問題。 但是,這些數字鍵只出現在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事件。

賽普拉斯文檔

cy.visit()在遠程頁面觸發load事件時解析。

但是,使用上述解決方法后,我在oldStyles得到了一個空字符串用於 CSS 規則。 例如:

//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)

getStyles()開頭的cy.wait(15000)也沒有:

function getStyles() {
    cy.wait(15000); // The page has definitely loaded and applied all styles by now
    cy.get('.el-on-the-page *').then((elements) => {
...

我無法回答有關空屬性值的問題,解決方法應該不會影響事情。 如果我理解正確,您會在不使用變通方法時獲得屬性值嗎?

數字鍵

這些幾乎可以肯定是內聯樣式cssText樣式的索引。

有相同數量的數字鍵,因為在條目cssText ,和值匹配在鍵值對的LHS cssText

第二個 getStyles() 上缺少數字鍵

你確定嗎?

如果我在沒有插件安裝的情況下運行你的代碼,我會失敗,因為它比較了對象引用,

getStyles().then(oldStyles => {
  // no plugin mounted
  getStyles().then(newStyles => {                
    newStyles.forEach((newStyle, i) =>           
      expect(newStyle).to.equal(oldStyles[i])
    );
 });

但如果我使用.to.deep.equal它會成功

getStyles().then(oldStyles => {
  // no plugin mounted
  getStyles().then(newStyles => {                
    newStyles.forEach((newStyle, i) =>           
      expect(newStyle).to.deep.equal(oldStyles[i])
    );
 });

getComputedStyle() 返回一個活動對象

MDN Window.getComputedStyle()

返回的樣式是一個實時的 CSSStyleDeclaration 對象,它會在元素的樣式更改時自動更新。

因此您需要在比較之前克隆結果,即使插件在您比較時更改了某些內容,它們也是相同的。

我建議將JSON/stringify()應用於結果並比較字符串,它非常快,也消除了深度相等的需要。

function getStyles() {
  return cy.get('.el-on-the-page *').then((elements) => {
    const styles = []
    elements.each((_, el) => {
      styles.push(window.getComputedStyle(el));
    });
    return JSON.stringify(styles);    
  });
}

getStyles().then(oldStyles => {         
  mountPlugin();       
  getStyles().then(newStyles => {         
    expect(newStyles).to.equal(oldStyles);
  });
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM