|  | // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | library swarm_tests; | 
|  |  | 
|  | import 'dart:html'; | 
|  | import 'dart:async'; | 
|  | import 'package:expect/expect.dart'; | 
|  | import 'package:unittest/html_config.dart'; | 
|  | import 'package:unittest/unittest.dart'; | 
|  | import '../swarmlib.dart'; | 
|  | import '../swarm_ui_lib/base/base.dart'; | 
|  | import '../swarm_ui_lib/util/utilslib.dart'; | 
|  |  | 
|  | // TODO(jmesserly): these would probably be easier to debug if they were written | 
|  | // in the WebKit layout test style, so we could easy compare that the DOM is | 
|  | // what we expect it to be after performing some simulated user actions. | 
|  |  | 
|  | void main() { | 
|  | useHtmlConfiguration(); | 
|  | Swarm swarm = new Swarm(useCannedData: true); | 
|  | UIStateProxy state = new UIStateProxy(swarm.sections); | 
|  | swarm.state = state; | 
|  | swarm.run(); | 
|  | // TODO(jmesserly): should be adding the full stylesheet here | 
|  | Dom.addStyle(''' | 
|  | .story-content { | 
|  | -webkit-column-width: 300px; | 
|  | -webkit-column-gap: 26px; /* 2em */ | 
|  | }'''); | 
|  |  | 
|  | getStoryNode() => swarm.frontView.storyView.node; | 
|  |  | 
|  | getView(Section section) { | 
|  | return CollectionUtils.find( | 
|  | swarm.frontView.sections.childViews, (view) => view.section == section); | 
|  | } | 
|  |  | 
|  | getHistory(Article article) { | 
|  | final feed = article.dataSource; | 
|  | return { | 
|  | 'section': CollectionUtils | 
|  | .find(swarm.sections, (s) => s.feeds.indexOf(feed, 0) >= 0) | 
|  | .id, | 
|  | 'feed': feed.id, | 
|  | 'article': article.id | 
|  | }; | 
|  | } | 
|  |  | 
|  | test('BackButton', () { | 
|  | _serialInvokeAsync([ | 
|  | () { | 
|  | Expect.equals(null, swarm.frontView.storyView); // verify initial state | 
|  |  | 
|  | // Make sure we've transitioned to the section | 
|  | // In the real app, this isn't needed because ConveyorView fires the | 
|  | // transition end event before we can click a story. | 
|  | SectionView section = getView(swarm.sections[0]); | 
|  | section.showSources(); | 
|  | }, | 
|  | () { | 
|  | final item = swarm.sections[0].feeds[2].articles[1]; | 
|  | state.loadFromHistory(getHistory(item)); | 
|  |  | 
|  | Expect.equals(item, state.currentArticle.value); | 
|  |  | 
|  | Expect.isFalse(getStoryNode().classes.contains(CSS.HIDDEN_STORY)); | 
|  |  | 
|  | state.loadFromHistory({}); | 
|  |  | 
|  | Expect.equals(null, state.currentArticle.value); | 
|  | Expect.isTrue(getStoryNode().classes.contains(CSS.HIDDEN_STORY)); | 
|  | } | 
|  | ]); | 
|  | }); | 
|  |  | 
|  | test('StoryView', () { | 
|  | state.clearHistory(); | 
|  |  | 
|  | Expect.isTrue(getStoryNode().classes.contains(CSS.HIDDEN_STORY)); | 
|  |  | 
|  | final dataSourceView = | 
|  | swarm.frontView.currentSection.dataSourceView.getSubview(0); | 
|  | final itemView = dataSourceView.itemsView.getSubview(0); | 
|  | // TODO(jacobr): remove  this null check. This is likely due to tests | 
|  | // running without the correct CSS to size the window so that some items | 
|  | // are visible. | 
|  | if (itemView != null) { | 
|  | click(itemView.node); | 
|  | state.expectHistory([getHistory(itemView.item)]); | 
|  | } | 
|  | }); | 
|  |  | 
|  | test('SliderMenu', () { | 
|  | Expect.equals(getView(swarm.sections[0]), swarm.frontView.currentSection); | 
|  |  | 
|  | // Find the first slider menu item, and click on the one next after it. | 
|  | click(document.querySelectorAll('.${CSS.SM_ITEM}')[1]); | 
|  |  | 
|  | Expect.equals(getView(swarm.sections[1]), swarm.frontView.currentSection); | 
|  |  | 
|  | // Find the first menu item again and click on it. | 
|  | click(document.querySelector('.${CSS.SM_ITEM}')); | 
|  |  | 
|  | Expect.equals(getView(swarm.sections[0]), swarm.frontView.currentSection); | 
|  | }); | 
|  | } | 
|  |  | 
|  | /** Triggers the click event, like [http://api.jquery.com/click/] */ | 
|  | click(Element element) { | 
|  | // TODO(rnystrom): This should be on the DOM API somewhere. | 
|  | MouseEvent event = new MouseEvent('click'); | 
|  | element.dispatchEvent(event); | 
|  | } | 
|  |  | 
|  | /** A proxy so we can intercept history calls */ | 
|  | class UIStateProxy extends SwarmState { | 
|  | List<Map<String, String>> history; | 
|  |  | 
|  | UIStateProxy(Sections dataModel) : super(dataModel) { | 
|  | clearHistory(); | 
|  | } | 
|  |  | 
|  | void pushToHistory() { | 
|  | history.add(toHistory()); | 
|  | super.pushToHistory(); | 
|  | } | 
|  |  | 
|  | void clearHistory() { | 
|  | history = new List<Map<String, String>>(); | 
|  | } | 
|  |  | 
|  | void expectHistory(List<Map<String, String>> entries) { | 
|  | Expect.equals(entries.length, history.length); | 
|  | for (int i = 0; i < entries.length; i++) { | 
|  | Map e = entries[i]; | 
|  | Map h = history[i]; | 
|  | Expect.equals(e['article'], h['article']); | 
|  | } | 
|  | clearHistory(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void _serialInvokeAsync(List closures) { | 
|  | final length = closures.length; | 
|  | if (length > 0) { | 
|  | int i = 0; | 
|  | void invokeNext() { | 
|  | closures[i](); | 
|  | i++; | 
|  | if (i < length) { | 
|  | Timer.run(expectAsync(invokeNext)); | 
|  | } | 
|  | } | 
|  |  | 
|  | Timer.run(expectAsync(invokeNext)); | 
|  | } | 
|  | } |