blob: bc07d84044c1d80e5de554554ad3ca4c1cadb495 [file] [log] [blame]
/**
* @license
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '../../../test/common-test-setup-karma.js';
import './gr-cursor-manager.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
const basicTestFixutre = fixtureFromTemplate(html`
<gr-cursor-manager cursor-target-class="targeted"></gr-cursor-manager>
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
`);
suite('gr-cursor-manager tests', () => {
let element;
let list;
setup(() => {
const fixtureElements = basicTestFixutre.instantiate();
element = fixtureElements[0];
list = fixtureElements[1];
});
test('core cursor functionality', () => {
// The element is initialized into the proper state.
assert.isArray(element.stops);
assert.equal(element.stops.length, 0);
assert.equal(element.index, -1);
assert.isNotOk(element.target);
// Initialize the cursor with its stops.
element.stops = list.querySelectorAll('li');
// It should have the stops but it should not be targeting any of them.
assert.isNotNull(element.stops);
assert.equal(element.stops.length, 4);
assert.equal(element.index, -1);
assert.isNotOk(element.target);
// Select the third stop.
element.setCursor(list.children[2]);
// It should update its internal state and update the element's class.
assert.equal(element.index, 2);
assert.equal(element.target, list.children[2]);
assert.isTrue(list.children[2].classList.contains('targeted'));
assert.isFalse(element.isAtStart());
assert.isFalse(element.isAtEnd());
// Progress the cursor.
element.next();
// Confirm that the next stop is selected and that the previous stop is
// unselected.
assert.equal(element.index, 3);
assert.equal(element.target, list.children[3]);
assert.isTrue(element.isAtEnd());
assert.isFalse(list.children[2].classList.contains('targeted'));
assert.isTrue(list.children[3].classList.contains('targeted'));
// Progress the cursor.
element.next();
// We should still be at the end.
assert.equal(element.index, 3);
assert.equal(element.target, list.children[3]);
assert.isTrue(element.isAtEnd());
// Wind the cursor all the way back to the first stop.
element.previous();
element.previous();
element.previous();
// The element state should reflect the end of the list.
assert.equal(element.index, 0);
assert.equal(element.target, list.children[0]);
assert.isTrue(element.isAtStart());
assert.isTrue(list.children[0].classList.contains('targeted'));
const newLi = document.createElement('li');
newLi.textContent = 'Z';
list.insertBefore(newLi, list.children[0]);
element.stops = list.querySelectorAll('li');
assert.equal(element.index, 1);
// De-select all targets.
element.unsetCursor();
// There should now be no cursor target.
assert.isFalse(list.children[1].classList.contains('targeted'));
assert.isNotOk(element.target);
assert.equal(element.index, -1);
});
test('next() goes to first element when no cursor is set', () => {
element.stops = list.querySelectorAll('li');
element.next();
assert.equal(element.index, 0);
assert.equal(element.target, list.children[0]);
assert.isTrue(list.children[0].classList.contains('targeted'));
assert.isTrue(element.isAtStart());
assert.isFalse(element.isAtEnd());
});
test('next() goes to first element when no cursor is set', () => {
element.stops = list.querySelectorAll('li');
element.previous();
const lastIndex = list.children.length - 1;
assert.equal(element.index, lastIndex);
assert.equal(element.target, list.children[lastIndex]);
assert.isTrue(list.children[lastIndex].classList.contains('targeted'));
assert.isFalse(element.isAtStart());
assert.isTrue(element.isAtEnd());
});
test('_moveCursor', () => {
// Initialize the cursor with its stops.
element.stops = list.querySelectorAll('li');
// Select the first stop.
element.setCursor(list.children[0]);
const getTargetHeight = sinon.stub();
// Move the cursor without an optional get target height function.
element._moveCursor(1);
assert.isFalse(getTargetHeight.called);
// Move the cursor with an optional get target height function.
element._moveCursor(1, null, getTargetHeight);
assert.isTrue(getTargetHeight.called);
});
test('_moveCursor from for invalid index does not check height', () => {
element.stops = [];
const getTargetHeight = sinon.stub();
element._moveCursor(1, () => false, getTargetHeight);
assert.isFalse(getTargetHeight.called);
});
test('opt_noScroll', () => {
sinon.stub(element, '_targetIsVisible').callsFake(() => false);
const scrollStub = sinon.stub(window, 'scrollTo');
element.stops = list.querySelectorAll('li');
element.scrollMode = 'keep-visible';
element.setCursorAtIndex(1, true);
assert.isFalse(scrollStub.called);
element.setCursorAtIndex(2);
assert.isTrue(scrollStub.called);
});
test('_getNextindex', () => {
const isLetterB = function(row) {
return row.textContent === 'B';
};
element.stops = list.querySelectorAll('li');
// Start cursor at the first stop.
element.setCursor(list.children[0]);
// Move forward to meet the next condition.
assert.equal(element._getNextindex(1, isLetterB), 1);
element.index = 1;
// Nothing else meets the condition, should be at last stop.
assert.equal(element._getNextindex(1, isLetterB), 3);
element.index = 3;
// Should stay at last stop if try to proceed.
assert.equal(element._getNextindex(1, isLetterB), 3);
// Go back to the previous condition met. Should be back at.
// stop 1.
assert.equal(element._getNextindex(-1, isLetterB), 1);
element.index = 1;
// Go back. No more meet the condition. Should be at stop 0.
assert.equal(element._getNextindex(-1, isLetterB), 0);
});
test('focusOnMove prop', () => {
const listEls = list.querySelectorAll('li');
for (let i = 0; i < listEls.length; i++) {
sinon.spy(listEls[i], 'focus');
}
element.stops = listEls;
element.setCursor(list.children[0]);
element.focusOnMove = false;
element.next();
assert.isFalse(element.target.focus.called);
element.focusOnMove = true;
element.next();
assert.isTrue(element.target.focus.called);
});
suite('_scrollToTarget', () => {
let scrollStub;
setup(() => {
element.stops = list.querySelectorAll('li');
element.scrollMode = 'keep-visible';
// There is a target which has a targetNext
element.setCursor(list.children[0]);
element._moveCursor(1);
scrollStub = sinon.stub(window, 'scrollTo');
window.innerHeight = 60;
});
test('Called when top and bottom not visible', () => {
sinon.stub(element, '_targetIsVisible').returns(false);
element._scrollToTarget();
assert.isTrue(scrollStub.called);
});
test('Not called when top and bottom visible', () => {
sinon.stub(element, '_targetIsVisible').returns(true);
element._scrollToTarget();
assert.isFalse(scrollStub.called);
});
test('Called when top is visible, bottom is not, scroll is lower', () => {
const visibleStub = sinon.stub(element, '_targetIsVisible').callsFake(
() => visibleStub.callCount === 2);
sinon.stub(element, '_getWindowDims').returns({
scrollX: 123,
scrollY: 15,
innerHeight: 1000,
pageYOffset: 0,
});
sinon.stub(element, '_calculateScrollToValue').returns(20);
element._scrollToTarget();
assert.isTrue(scrollStub.called);
assert.isTrue(scrollStub.calledWithExactly(123, 20));
assert.equal(visibleStub.callCount, 2);
});
test('Called when top is visible, bottom not, scroll is higher', () => {
const visibleStub = sinon.stub(element, '_targetIsVisible').callsFake(
() => visibleStub.callCount === 2);
sinon.stub(element, '_getWindowDims').returns({
scrollX: 123,
scrollY: 25,
innerHeight: 1000,
pageYOffset: 0,
});
sinon.stub(element, '_calculateScrollToValue').returns(20);
element._scrollToTarget();
assert.isFalse(scrollStub.called);
assert.equal(visibleStub.callCount, 2);
});
test('_calculateScrollToValue', () => {
sinon.stub(element, '_getWindowDims').returns({
scrollX: 123,
scrollY: 25,
innerHeight: 300,
pageYOffset: 0,
});
assert.equal(element._calculateScrollToValue(1000, {offsetHeight: 10}),
905);
});
});
});