Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4267)

Unified Diff: chrome/test/data/webui/settings/settings_transitions_browsertest.js

Issue 2198203002: MD Settings: Test for section expand/collapse navigation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@RefactorSettingsAnimatedPages
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/test/data/webui/settings/settings_page_browsertest.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/test/data/webui/settings/settings_transitions_browsertest.js
diff --git a/chrome/test/data/webui/settings/settings_transitions_browsertest.js b/chrome/test/data/webui/settings/settings_transitions_browsertest.js
new file mode 100644
index 0000000000000000000000000000000000000000..af2e65d728229ed353169c8b8121de02ac996d58
--- /dev/null
+++ b/chrome/test/data/webui/settings/settings_transitions_browsertest.js
@@ -0,0 +1,392 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Suite of tests for Settings navigational transitions. */
+
+GEN_INCLUDE(['settings_page_browsertest.js']);
+
+/**
+ * @constructor
+ * @extends {SettingsPageBrowserTest}
+*/
+function SettingsTransitionsBrowserTest() {}
+
+/**
+ * @typedef {{
+ * duration: Number,
+ * hasStarted: function(): bool,
+ * testIntermediateState: function(),
+ * testAfter: function()
tommycli 2016/08/01 22:56:10 Was this supposed to be testEndState?
michaelpg 2016/08/04 00:56:48 Done.
+ * }}
+ */
+var TransitionTest;
+
+/** @const {number} Default animation timing for neon-animated-pages. */
+var kNeonAnimationsDuration = 500;
+
+SettingsTransitionsBrowserTest.prototype = {
+ __proto__: SettingsPageBrowserTest.prototype,
+
+ /** @override */
+ browsePreload: 'chrome://md-settings/',
+
+ /**
+ * Tests a transition by waiting for it to start, running tests during its
+ * execution, and running tests after its duration is reached, all using
+ * callbacks -- no access to underlying animations.
+ * @param {!TransitionTest} transitionTest
+ * @return {!Promise} Resolved once the tests have finished.
+ */
+ testTransition: function(transitionTest) {
+ // We approximate the time when the transition started.
+ var startedNoEarlierThan = window.performance.now();
+ var startedNoLaterThan;
+ return new Promise(function(resolve, reject) {
+ // Figure out when the transition has started with a rAF loop. Even if we
+ // required access to underlying animation(s), there's no good way to
+ // force a transition to start or know when it starts without spinning.
+ (function checkIfStarted() {
+ if (transitionTest.hasStarted()) {
+ startedNoLaterThan = window.performance.now();
+ resolve();
+ } else {
+ // Update the latest known time the animation wasn't running, then
+ // check again.
+ startedNoEarlierThan = window.performance.now();
+ requestAnimationFrame(checkIfStarted);
+ }
+ })();
tommycli 2016/08/01 22:56:10 Wow that block above is exotic.
michaelpg 2016/08/04 00:56:48 Well the recursive function to check for a conditi
+ }).then(function() {
+ // Hopefully, the transition hasn't finished yet.
+ var minDuration = window.performance.now() - startedNoLaterThan;
+ var maxDuration = window.performance.now() - startedNoEarlierThan;
+ assertLE(minDuration, transitionTest.duration);
+ if (maxDuration < transitionTest.duration) {
+ transitionTest.testIntermediateState();
+ } else {
+ // We ran quite late. Don't run testIntermediateState().
+ console.warn('testIntermediateState() was not called because the ' +
+ 'transition may have already ended.');
+ }
+ // Wait until the transition should have completed.
+ var maxTimeToEnd = transitionTest.duration - minDuration;
+ var BUFFER = 10;
tommycli 2016/08/01 22:56:10 Is this leftover?
michaelpg 2016/08/04 00:56:48 I'm now seeing occasional flakes with any kind of
+ return new Promise(function(resolve, reject) {
+ setTimeout(function() {
+ transitionTest.testEndState();
+ resolve();
+ }, maxTimeToEnd + BUFFER);
+ });
+ });
+ },
+
+ /**
+ * Checks whether the subpage header (back button and title) is visible.
+ * @param {!SettingsSubpageElement} subpage
+ * @return {boolean}
+ */
+ checkSubpageHeaderVisible: function(subpage) {
+ var backButton = subpage.$$('[icon="settings:arrow-back"]');
+ assertNotEquals(null, backButton);
+ assertGT(backButton.clientHeight, 0);
+ var title = subpage.$$('h2');
+ assertNotEquals(null, title);
+ assertGT(title.clientHeight, 0);
+ assertGT(title.innerText.trim().length, 0);
+ },
+
+ /**
+ * @param {!HTMLElement} newNode The node to fade to.
+ * @param {!HTMLElement} oldNode The node to fade from.
+ * @return {!TransitionTest}
+ */
+ getFadeTransitionTest: function(newNode, oldNode) {
+ var newNodeStyle = getComputedStyle(newNode);
+ var oldNodeStyle = getComputedStyle(oldNode);
+ return {
+ duration: kNeonAnimationsDuration,
+
+ hasStarted: function() {
+ return newNodeStyle.opacity != '0' &&
+ oldNodeStyle.opacity != '1';
+ },
+
+ testIntermediateState: function() {
+ assertGT(oldNode.clientHeight, 0);
+ assertGT(newNode.clientHeight, 0);
+
+ var oldNodeOpacity = parseFloat(oldNodeStyle.opacity);
+ assertLT(oldNodeOpacity, 1);
+ assertGT(oldNodeOpacity, 0);
+ var newNodeOpacity = parseFloat(newNodeStyle.opacity);
+ assertLT(newNodeOpacity, 1);
+ assertGT(newNodeOpacity, 0);
+ },
+
+ testEndState: function() {
+ assertEquals('none', oldNodeStyle.display);
+ assertEquals('1', newNodeStyle.opacity);
+ },
+ };
+ },
+
+ /**
+ * Tests the transition to open a subpage from the main animatable.
+ * @param {!SettingsSectionElement} section
+ * @param {string} subpageId
+ * @param {!settings.Route} subpageRoute
+ * @return {!Promise<!SettingsSubpageElement>} Resolved with the opened
+ * subpage once the transition completes.
+ */
+ testOpenSubpage: function(section, subpageId, subpageRoute) {
+ var page = section.domHost;
+
+ var sectionStyle = getComputedStyle(section);
+ var cardStyle = getComputedStyle(section.$.card);
+
+ // Some sanity checks of starting conditions.
+ var sectionHeightStart = section.clientHeight;
+ var cardHeightStart = section.$.card.clientHeight;
+ assertGT(cardHeightStart, 10);
+ assertGT(sectionHeightStart, cardHeightStart);
+
+ var mainAnimatable = this.getSectionMainAnimatable(section);
+ assertNotEquals(null, mainAnimatable);
+ assertGT(mainAnimatable.clientHeight, 0);
+ var mainAnimatableStyle = getComputedStyle(mainAnimatable);
+
+ this.verifySubpagesHidden(section);
+
+ var otherSections = this.getSections(section.domHost);
+ otherSections.splice(otherSections.indexOf(section), 1);
+ assertGT(otherSections.length, 0);
+
+ for (var otherSection of otherSections)
+ assertGT(otherSection.clientHeight, 0);
+
+ // Play the transition.
+ settings.navigateTo(subpageRoute);
+ assertEquals(subpageRoute, page.currentRoute);
+
+ // The section and the card should not have changed height yet.
+ assertEquals(section.clientHeight, sectionHeightStart);
+ assertEquals(section.$.card.clientHeight, cardHeightStart);
+
+ // The main animatable is still fully visible.
+ assertEquals('1', mainAnimatableStyle.opacity);
+
+ // The subpage should be stamped but not faded in yet.
+ var subpages = this.getSectionSubpages(section);
+ assertTrue(subpages.has(subpageId));
+ var subpage = subpages.get(subpageId);
+ this.checkSubpageHeaderVisible(subpage);
+ var subpageStyle = getComputedStyle(subpage);
+ assertEquals('0', subpageStyle.opacity);
+
+ var container = page.offsetParent;
+
+ // Test stages of the section/card expand transition.
+ var expandTransitionTest = {
+ duration: EXPAND_DURATION,
+
+ hasStarted: function() {
+ // Transition starts by expanding card.
+ return section.$.card.clientHeight > cardHeightStart;
+ },
+
+ testIntermediateState: function() {
+ // The card must be fixed in the viewport while expanding.
+ assertEquals('fixed', cardStyle.position);
+
+ // The card is offset to be below the toolbar.
+ assertGT(section.$.card.offsetTop,
+ container.getBoundingClientRect().top);
+
+ // All sections retain their dimensions while the expanding section's
+ // card expands.
+ assertEquals(sectionHeightStart, section.clientHeight);
+ for (var otherSection of otherSections)
+ assertGT(otherSection.clientHeight, 0);
+ },
+
+ testEndState: function() {
+ // Sanity check.
+ assertGT(section.clientHeight, sectionHeightStart);
+
+ // Transition ends with the expanded section spanning the
+ // container height at a minimum.
+ assertEquals(sectionStyle.minHeight, '100%');
+ assertGE(section.clientHeight, container.clientHeight);
+
+ // All other sections are hidden.
+ for (var otherSection of otherSections)
+ assertEquals(0, otherSection.clientHeight);
+ },
+ };
+
+ // Test stages of the animatable/subpage fade transition.
+ var fadeTransitionTest =
+ this.getFadeTransitionTest(subpage, mainAnimatable);
+
+ return Promise.all([
+ this.testTransition(expandTransitionTest),
+ this.testTransition(fadeTransitionTest),
+ ]).then(function() {
+ return subpage;
+ });
+ },
+
+ /**
+ * Tests the transition to close a subpage and return to the main animatable.
+ * @return {!Promise} Resolved once the transition
+ * completes.
+ */
+ testCloseSubpage: function(section, subpage) {
+ var page = section.domHost;
+ var container = page.offsetParent;
+
+ var sectionStyle = getComputedStyle(section);
+ var cardStyle = getComputedStyle(section.$.card);
+ var subpageStyle = getComputedStyle(subpage);
+
+ var sectionHeightStart = section.clientHeight;
+ var cardHeightStart = section.$.card.clientHeight;
+
+ var mainAnimatable = this.getSectionMainAnimatable(section);
+ assertTrue(!!mainAnimatable);
+ assertEquals(mainAnimatable.clientHeight, 0);
+ var mainAnimatableStyle = getComputedStyle(mainAnimatable);
+
+ var otherSections = this.getSections(section.domHost);
+ otherSections.splice(otherSections.indexOf(section), 1);
+ assertGT(otherSections.length, 0);
+
+ for (var otherSection of otherSections)
+ assertEquals(otherSection.clientHeight, 0);
+
+ // Find the 2nd-highest route (the section itself).
+ var route = page.currentRoute;
+ while (route.parent.parent)
+ route = route.parent;
+
+ // Play the transition.
+ settings.navigateTo(route);
+ assertEquals(route, page.currentRoute);
+
+ // Depending on the browser height, the card may have been scrollable.
+ if (container.clientHeight == cardHeightStart) {
+ // The card was not scrollable, so the height should not have changed.
+ assertEquals(cardHeightStart, section.$.card.clientHeight);
+ } else {
+ // The card was scrollable (larger than the container), so it should have
+ // been resized to the container height.
+ assertEquals(section.$.card.clientHeight, container.clientHeight);
+ }
+
+ // The subpage is still fully visible.
+ assertEquals('1', subpageStyle.opacity);
+ this.checkSubpageHeaderVisible(subpage);
+
+ // Test stages of the section/card collapse transition.
+ var collapseTransitionTest = {
+ duration: EXPAND_DURATION,
+
+ hasStarted: function() {
+ // Transition starts by collapsing card.
+ return section.$.card.clientHeight < cardHeightStart;
+ },
+
+ testIntermediateState: function() {
+ // The card must be fixed in the viewport while collapsing.
+ assertEquals('fixed', cardStyle.position);
+
+ // All sections are now visible.
+ for (var otherSection of otherSections)
+ assertGT(otherSection.clientHeight, 0);
+
+ // TODO(michaelpg): The card should be offset to be below the toolbar,
+ // but scroll position breaks on closing the subpage: crbug.com/537359.
+ },
+
+ testEndState: function() {
+ // Sanity check.
+ assertLT(section.clientHeight, sectionHeightStart);
+ assertEquals('0px', sectionStyle.minHeight);
+ },
+ };
+
+ // Test stages of the animatable/subpage fade transition.
+ var fadeTransitionTest =
+ this.getFadeTransitionTest(mainAnimatable, subpage);
+
+ return Promise.all([
+ this.testTransition(collapseTransitionTest),
+ this.testTransition(fadeTransitionTest),
+ ]).then(function() {
+ return subpage;
+ });
+ },
+};
+
+TEST_F('SettingsTransitionsBrowserTest', 'Subpages', function() {
+ var self = this;
+
+ suite('Subpages', function() {
+ suiteSetup(function() {
+ var settingsUI = document.querySelector('* /deep/ settings-ui');
+ MockInteractions.tap(settingsUI.$.close);
+ });
+
+ test('open and close a sub-page', function() {
+ var page = self.getPage('basic');
+ assertEquals(settings.Route.BASIC, page.currentRoute);
+
+ var section = self.getSection(page, 'search');
+
+ // Make the section's main page 100px shorter than the page container to
+ // test a normal expand animation.
+ var container = page.offsetParent;
+ assertGT(container.clientHeight, 200,
+ 'Browser window too short to test WebUI!');
+ var mainAnimatable = self.getSectionMainAnimatable(section);
+ mainAnimatable.style.height = container.clientHeight - 100 + 'px';
+ section.scrollIntoView();
+
+ return self.testOpenSubpage(
+ section, 'search-engines', settings.Route.SEARCH_ENGINES
+ ).then(function(subpage) {
+ // Change the subpage's height to test scrolling.
+ subpage.style.height = '100px';
+ // Everything is taller than the subpage, since the section's min-height
+ // is 100% of the container.
+ assertGT(section.$.card.clientHeight, subpage.clientHeight);
+ assertEquals(section.$.card.clientHeight, section.clientHeight);
+ // The container shouldn't scroll vertically. Check the offsetHeight in
+ // case the container has a horizontal scrollbar (small window).
+ // TODO(michaelpg): Why is this necessary?
+ assertEquals(container.offsetHeight, section.clientHeight);
+ assertEquals(container.offsetHeight, container.scrollHeight);
+
+ // Make sure the section and its card stretch with the content.
+ subpage.style.height = '10000px';
+ assertEquals(subpage.clientHeight, section.clientHeight);
+ assertEquals(subpage.clientHeight, section.$.card.clientHeight);
+
+ // The card is now larger than the container, so the container should
+ // scroll.
+ assertGT(section.$.card.clientHeight, container.clientHeight);
+ assertGT(container.scrollHeight, container.clientHeight);
+ assertEquals(10000, container.scrollHeight);
+
+ subpage.style.height = '';
+ return subpage;
+ }).then(function(subpage) {
+ // Close the subpage.
+ return self.testCloseSubpage(section, subpage);
+ });
+ });
+ });
+
+ mocha.run();
+});
« no previous file with comments | « chrome/test/data/webui/settings/settings_page_browsertest.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698