Commit f2f67968 authored by Esmael El-Moslimany's avatar Esmael El-Moslimany Committed by Commit Bot

WebUI NTP: move scroll border code into utils

Moving the scroll border code out of the customize dialog makes it
easier to test. If there is a flake, it will also be easier to diagnose.

This CL enables the ntp-customize-dialog unit tests which was previously
disabled due to flakiness (due to the scroll borders tests).

Bug: 1056688
Change-Id: Ic74f4b79c33c578f9a9d759d80ed569c93f12550
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2082901
Commit-Queue: Esmael Elmoslimany <aee@chromium.org>
Reviewed-by: default avatarTibor Goldschwendt <tiborg@chromium.org>
Auto-Submit: Esmael Elmoslimany <aee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#746221}
parent 76d3d815
...@@ -55,6 +55,7 @@ js_library("customize_dialog") { ...@@ -55,6 +55,7 @@ js_library("customize_dialog") {
":customize_backgrounds", ":customize_backgrounds",
":customize_shortcuts", ":customize_shortcuts",
":customize_themes", ":customize_themes",
":utils",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_elements/cr_button:cr_button.m", "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
"//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m", "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
......
...@@ -13,6 +13,7 @@ import './customize_themes.js'; ...@@ -13,6 +13,7 @@ import './customize_themes.js';
import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {BrowserProxy} from './browser_proxy.js'; import {BrowserProxy} from './browser_proxy.js';
import {createScrollBorders} from './utils.js';
/** /**
* Dialog that lets the user customize the NTP such as the background color or * Dialog that lets the user customize the NTP such as the background color or
...@@ -61,33 +62,10 @@ class CustomizeDialogElement extends PolymerElement { ...@@ -61,33 +62,10 @@ class CustomizeDialogElement extends PolymerElement {
/** @override */ /** @override */
ready() { ready() {
super.ready(); super.ready();
this.intersectionObservers_ = [
['menu', 'pages'].forEach(id => { this.$.menu,
const container = this.$[id]; this.$.pages,
const topProbe = document.createElement('div'); ].map(createScrollBorders);
container.prepend(topProbe);
const bottomProbe = document.createElement('div');
container.append(bottomProbe);
const topBorder = document.createElement('div');
topBorder.toggleAttribute('scroll-border', true);
container.parentNode.insertBefore(topBorder, container);
const bottomBorder = document.createElement('div');
bottomBorder.toggleAttribute('scroll-border', true);
container.parentNode.insertBefore(bottomBorder, container.nextSibling);
const observer = new IntersectionObserver(entries => {
entries.forEach(({target, intersectionRatio}) => {
const show = intersectionRatio === 0;
if (target === topProbe) {
topBorder.toggleAttribute('show', show);
} else if (target === bottomProbe) {
bottomBorder.toggleAttribute('show', show);
}
});
}, {root: container});
observer.observe(topProbe);
observer.observe(bottomProbe);
this.intersectionObservers_.push(observer);
});
} }
/** @private */ /** @private */
......
...@@ -34,3 +34,40 @@ export function hexColorToSkColor(hexColor) { ...@@ -34,3 +34,40 @@ export function hexColorToSkColor(hexColor) {
const b = parseInt(hexColor.substring(5, 7), 16); const b = parseInt(hexColor.substring(5, 7), 16);
return {value: 0xff000000 + (r << 16) + (g << 8) + b}; return {value: 0xff000000 + (r << 16) + (g << 8) + b};
} }
/**
* Given a |container| that has scrollable content, <div>'s before and after the
* |container| are created with an attribute "scroll-border". These <div>'s are
* updated to have an attribute "show" when there is more content in the
* direction of the "scroll-border". Styling is left to the caller.
*
* Returns an |IntersectionObserver| so the caller can disconnect the observer
* when needed.
* @param {!HTMLElement} container
* @return {!IntersectionObserver}
*/
export function createScrollBorders(container) {
const topProbe = document.createElement('div');
container.prepend(topProbe);
const bottomProbe = document.createElement('div');
container.append(bottomProbe);
const topBorder = document.createElement('div');
topBorder.toggleAttribute('scroll-border', true);
container.parentNode.insertBefore(topBorder, container);
const bottomBorder = document.createElement('div');
bottomBorder.toggleAttribute('scroll-border', true);
container.parentNode.insertBefore(bottomBorder, container.nextSibling);
const observer = new IntersectionObserver(entries => {
entries.forEach(({target, intersectionRatio}) => {
const show = intersectionRatio === 0;
if (target === topProbe) {
topBorder.toggleAttribute('show', show);
} else if (target === bottomProbe) {
bottomBorder.toggleAttribute('show', show);
}
});
}, {root: container});
observer.observe(topProbe);
observer.observe(bottomProbe);
return observer;
}
...@@ -53,46 +53,4 @@ suite('NewTabPageCustomizeDialogTest', () => { ...@@ -53,46 +53,4 @@ suite('NewTabPageCustomizeDialogTest', () => {
assertEquals(shownPages.length, 1); assertEquals(shownPages.length, 1);
assertEquals(shownPages[0].getAttribute('page-name'), 'themes'); assertEquals(shownPages[0].getAttribute('page-name'), 'themes');
}); });
suite('scroll borders', () => {
/**
* @param {!HTMLElement} container
* @private
*/
async function testScrollBorders(container) {
const assertHidden = el => {
assertTrue(el.matches('[scroll-border]:not([show])'));
};
const assertShown = el => {
assertTrue(el.matches('[scroll-border][show]'));
};
const {firstElementChild: top, lastElementChild: bottom} = container;
const scrollableElement = top.nextSibling;
const dialogBody =
customizeDialog.shadowRoot.querySelector('div[slot=body]');
const heightWithBorders = `${scrollableElement.scrollHeight + 2}px`;
dialogBody.style.height = heightWithBorders;
assertHidden(top);
assertHidden(bottom);
dialogBody.style.height = '50px';
await waitAfterNextRender();
assertHidden(top);
assertShown(bottom);
scrollableElement.scrollTop = 1;
await waitAfterNextRender();
assertShown(top);
assertShown(bottom);
scrollableElement.scrollTop = scrollableElement.scrollHeight;
await waitAfterNextRender();
assertShown(top);
assertHidden(bottom);
dialogBody.style.height = heightWithBorders;
await waitAfterNextRender();
assertHidden(top);
assertHidden(bottom);
}
test('menu', () => testScrollBorders(customizeDialog.$.menuContainer));
test('pages', () => testScrollBorders(customizeDialog.$.pagesContainer));
});
}); });
...@@ -59,8 +59,7 @@ var NewTabPageCustomizeDialogTest = class extends NewTabPageBrowserTest { ...@@ -59,8 +59,7 @@ var NewTabPageCustomizeDialogTest = class extends NewTabPageBrowserTest {
} }
}; };
// Test is flaky: crbug.com/1056688. TEST_F('NewTabPageCustomizeDialogTest', 'All', function() {
TEST_F('NewTabPageCustomizeDialogTest', 'DISABLED_All', function() {
mocha.run(); mocha.run();
}); });
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
// So that mojo is defined. // So that mojo is defined.
import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
import {hexColorToSkColor, skColorToRgb} from 'chrome://new-tab-page/utils.js'; import {createScrollBorders, hexColorToSkColor, skColorToRgb} from 'chrome://new-tab-page/utils.js';
import {waitAfterNextRender} from 'chrome://test/test_util.m.js';
suite('NewTabPageUtilsTest', () => { suite('NewTabPageUtilsTest', () => {
test('Can convert simple SkColors to rgb strings', () => { test('Can convert simple SkColors to rgb strings', () => {
...@@ -46,3 +47,70 @@ suite('NewTabPageUtilsTest', () => { ...@@ -46,3 +47,70 @@ suite('NewTabPageUtilsTest', () => {
assertDeepEquals(hexColorToSkColor('ffffff'), {value: 0}); assertDeepEquals(hexColorToSkColor('ffffff'), {value: 0});
}); });
}); });
suite('scroll borders', () => {
/** @type {!HTMLElement} */
let container;
/** @type {!HTMLElement} */
let content;
/** @type {!HTMLElement} */
let top;
/** @type {!HTMLElement} */
let bottom;
/** @type {!IntersectionObserver} */
let observer;
/** @param {!HTMLElement} el */
function assertHidden(el) {
assertTrue(el.matches('[scroll-border]:not([show])'));
}
/** @param {!HTMLElement} el */
function assertShown(el) {
assertTrue(el.matches('[scroll-border][show]'));
}
setup(async () => {
document.body.innerHTML =
'<div id="container"><div id="content"></div></div>';
container = document.querySelector('#container');
container.style.height = '100px';
container.style.overflow = 'auto';
content = document.querySelector('#content');
content.style.height = '200px';
observer = createScrollBorders(container);
top = document.body.firstElementChild;
bottom = document.body.lastElementChild;
await waitAfterNextRender();
});
teardown(() => {
observer.disconnect();
});
test('bottom border show when more content available below', () => {
assertHidden(top);
assertShown(bottom);
});
test('borders shown when content available above and below', async () => {
container.scrollTop = 10;
await waitAfterNextRender();
assertShown(top);
assertShown(bottom);
});
test('bottom border hidden when no content available below', async () => {
container.scrollTop = 200;
await waitAfterNextRender();
assertShown(top);
assertHidden(bottom);
});
test('borders hidden when all content is shown', async () => {
content.style.height = '100px';
await waitAfterNextRender();
assertHidden(top);
assertHidden(bottom);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment