2012-07-11 68 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延期链来解决我的单元测试问题。我对此并不特别高兴,但你能做什么?