2012-07-11 77 views
4

這不是一個問題,而是一個有趣問題的發現。這也是一種「從我的失敗中學習」.back和.pushState - 兩個歷史故事

我正在嘗試爲IE瀏覽器(使用window.hash作爲狀態維護的替代品)爲HTML5歷史鴨子打孔編寫單元測試。 duckpunch按預期工作,在用戶測試期間,我在IE,Chrome和Firefox中獲得一致的結果。

問題出在哪裏就是單元測試。在他們中,我做了各種各樣的history.pushState(),.replaceState,.back()和.forward()組合。這些在Firefox和IE中運行良好,但Chrome給了我完全不一致的結果。以下答案解釋了原因。

回答

2

爲了處理單元測試中的異步返回事件,我使用了HistoryJSJasmine。這是在歷史事件更新計數器來跟蹤,當鍍鉻處理的事件和茉莉花的異步支持,以阻止單元測試,直到我們看到一個事件改變的情況下:

增加計數器:

History.Adapter.bind(window, 'statechange', function() { 

    // Increment the counter 
    window.historyEventCounter++; 

}); 

茉莉花異步單元測試。 waitsFor將阻止,直到發生歷史事件:

describe('back navigation', function() { 
    it('should change url', function() { 

     var initialHistoryEventCount; 

     // Cache the initial count 

     runs(function() { 
      initialHistoryEventCount = window.historyEventCounter; 
      History.back(); 
     }); 

     // Block until the event counter changes 

     waitsFor(function() { 
      return (initialHistoryEventCount !== app.historyEventCounter); 
     }, "The page should be navigated back", 1000); 

     // Now confirm the expected back behaviour. Event failures will time-out. 

     runs(function() { 
      expect(window.location.href).toEqual("http:// my back url"); 

      // ... more tests about the page state 
     }); 
    } 
} 
8

考慮以下幾點:

var originalPath = window.location.pathname.toString(); 
history.pushState({ value: 'Foo' }, '', 'state-1'); 
history.pushState({ value: 'Bar' }, '', 'state-2'); 

history.pushState({ value: 'Baz' }, '', 'state-3'); 
history.back(); 
history.back(); 
console.log(history.state.value); 
//So we can hit refresh and see the results again... 
setTimeout(function() { 
    history.replaceState(null, '', originalPath); 
}, 250); 

人們期望這個代碼塊返回「富」 - 在Firefox和我的IE鴨拳,這正是它 - 但是在Chrome中,它迴應'巴茲'。

經過一番調查,我發現問題:IE和Firefox同步更新歷史記錄,然後在需要加載任何頁面的情況下進行異步。 Chrome似乎立即發生異步。

證據:

window.onpopstate = function() { 
    console.log('ping'); 
} 
history.pushState({ value: 'Foo' }, '', 'state-1'); 
history.back(); 
console.log('pong'); 

在Firefox中,這將返回 '平'; 'pong' - 表示該事件作爲history.back()調用的一部分進行調度。在Chrome中,這返回'pong'; 'ping' - 表示該事件被放入隊列中用於分派。

如果這個事件調度模型沒有被用來管理歷史和位置對象的狀態 - 但顯然是這樣的,這並不會那麼糟糕。

window.onpopstate = function() { 
    console.log('Event...', history.state, window.location.pathname.toString()); 
} 
history.pushState({ value: 'Foo' }, '', 'state-1'); 
history.back(); 
console.log('Inline...', history.state, window.location.pathname.toString()); 

這是一個有趣的怪癖,需要使用jQuery延期鏈來解決我的單元測試問題。我對此並不特別高興,但你能做什麼?