Skip to content

Commit

Permalink
test: move undefined size tests to more appropriate suite (#7460)
Browse files Browse the repository at this point in the history
  • Loading branch information
vursen authored May 31, 2024
1 parent 57806ca commit 67fb6dd
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 145 deletions.
2 changes: 2 additions & 0 deletions packages/combo-box/test/dynamic-size-lit.test.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import '@vaadin/text-field/vaadin-lit-text-field.js';
import '../src/vaadin-lit-combo-box.js';
import '../src/vaadin-lit-combo-box-light.js';
import './dynamic-size.common.js';
2 changes: 2 additions & 0 deletions packages/combo-box/test/dynamic-size-polymer.test.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import '@vaadin/text-field/vaadin-text-field.js';
import '../src/vaadin-combo-box.js';
import '../src/vaadin-combo-box-light.js';
import './dynamic-size.common.js';
185 changes: 152 additions & 33 deletions packages/combo-box/test/dynamic-size.common.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,166 @@
import { expect } from '@esm-bundle/chai';
import { fixtureSync, nextFrame, nextRender } from '@vaadin/testing-helpers';
import { flushComboBox, getViewportItems, scrollToIndex } from './helpers.js';
import { ComboBoxPlaceholder } from '../src/vaadin-combo-box-placeholder.js';
import { flushComboBox, getViewportItems, getVisibleItemsCount, makeItems, scrollToIndex } from './helpers.js';

describe('dynamic size change', () => {
describe('reduce size once scrolled to end', () => {
const TEMPLATES = {
'vaadin-combo-box': `
<vaadin-combo-box></vaadin-combo-box>
`,
'vaadin-combo-box-light': `
<vaadin-combo-box-light>
<vaadin-text-field></vaadin-text-field>
</vaadin-combo-box-light>
`,
};

['vaadin-combo-box', 'vaadin-combo-box-light'].forEach((tag) => {
describe(`dynamic size - ${tag}`, () => {
let comboBox;
const INITIAL_SIZE = 600;
const ACTUAL_SIZE = 500;

function dataProvider(params, callback) {
const items = Array(...new Array(params.pageSize)).map((_, i) => {
return {
label: `Item ${params.pageSize * params.page + i}`,
};
});
describe('size is reduced once scrolled to end', () => {
const INITIAL_SIZE = 600;
const ACTUAL_SIZE = 500;

function dataProvider(params, callback) {
const items = Array(...new Array(params.pageSize)).map((_, i) => {
return {
label: `Item ${params.pageSize * params.page + i}`,
};
});

let size = ACTUAL_SIZE;
if (!comboBox.size || comboBox.size === INITIAL_SIZE) {
// Pages may be requested not sequentially.
// Not to change combobox's size, if once changed to actual value
size = params.page > ACTUAL_SIZE / params.pageSize - 1 ? ACTUAL_SIZE : INITIAL_SIZE;
let size = ACTUAL_SIZE;
if (!comboBox.size || comboBox.size === INITIAL_SIZE) {
// Pages may be requested not sequentially.
// Not to change combobox's size, if once changed to actual value
size = params.page > ACTUAL_SIZE / params.pageSize - 1 ? ACTUAL_SIZE : INITIAL_SIZE;
}

callback(items, size);
}

callback(items, size);
}
beforeEach(async () => {
comboBox = fixtureSync(TEMPLATES[tag]);
comboBox.dataProvider = dataProvider;
await nextRender();
});

beforeEach(async () => {
comboBox = fixtureSync('<vaadin-combo-box></vaadin-combo-box>');
comboBox.dataProvider = dataProvider;
await nextRender();
it('should not have item placeholders after size gets reduced', async () => {
comboBox.opened = true;
scrollToIndex(comboBox, comboBox.size - 1);
flushComboBox(comboBox);
await nextFrame();
flushComboBox(comboBox);
await nextFrame();
const items = getViewportItems(comboBox);
expect(items.length).to.be.above(5);
items.forEach((item) => {
expect(item.textContent).to.be.ok;
});
});
});

it('should not have item placeholders after size gets reduced', async () => {
comboBox.opened = true;
scrollToIndex(comboBox, comboBox.size - 1);
flushComboBox(comboBox);
await nextFrame();
flushComboBox(comboBox);
await nextFrame();
const items = getViewportItems(comboBox);
expect(items.length).to.be.above(5);
items.forEach((item) => {
expect(item.textContent).to.be.ok;
describe('undefined size', () => {
beforeEach(async () => {
comboBox = fixtureSync(TEMPLATES[tag]);
await nextRender();
});

it('should restore the scroll position after size update', () => {
const estimatedSize = 1234;
const targetItemIndex = 75;
comboBox.dataProvider = (params, callback) => {
const items = makeItems(estimatedSize);
const offset = params.page * params.pageSize;
callback(items.slice(offset, offset + params.pageSize), items.length);
};
comboBox.opened = true;
comboBox._scrollIntoView(targetItemIndex);
comboBox.size = 300;
// Verify whether the scroller not jumped to 0 pos and restored properly,
// having the item with 'targetItemIndex' in the bottom
// (exact visible items may vary depending of window size),
// and sometimes the 'ironList.scrollToIndex' does not point
// precisely to the given index, so use some margin
const scrollMargin = 5;
const expectedFirstVisibleIndex = targetItemIndex - getVisibleItemsCount(comboBox) - scrollMargin;
expect(getViewportItems(comboBox)[0].index).to.be.greaterThan(expectedFirstVisibleIndex);
expect(getViewportItems(comboBox).pop().index).to.be.lessThan(targetItemIndex + 1);
});

// Verifies https://github.com/vaadin/vaadin-combo-box/issues/957
it('should fetch the items after scrolling to the bottom with scrollbar', async () => {
const realSize = 1234;
let estimatedSize = 200;

// DataProvider for unknown size lazy loading
comboBox.dataProvider = (params, callback) => {
const offset = params.page * params.pageSize;
const items = makeItems(realSize);
const itemsSlice = items.slice(offset, offset + params.pageSize);
if (itemsSlice.size === 0) {
estimatedSize = offset;
} else if (itemsSlice.size < params.pageSize) {
estimatedSize = offset + itemsSlice.size;
} else if (offset + params.pageSize > estimatedSize - params.pageSize) {
estimatedSize += 200;
}
callback(itemsSlice, estimatedSize);
};
comboBox.opened = true;

// Scroll to the end, as though if we drag the scrollbar and move it
// to the bottom
const scrollHeight = comboBox._scroller._scrollHeight;
comboBox._scroller.scrollTop += scrollHeight;

// Flush the pending changes after the scrolling
await nextFrame();

const lastVisibleIndex = getViewportItems(comboBox).pop().index;
// Check if the next few items after the last visible item are not empty
for (let nextIndexIncrement = 0; nextIndexIncrement < 5; nextIndexIncrement++) {
const lastItem = comboBox.filteredItems[lastVisibleIndex + nextIndexIncrement];
expect(lastItem instanceof ComboBoxPlaceholder).is.false;
}
});

it('should not show the loading when exact size is suddenly reached in the middle of requested range', async () => {
const realSize = 294;
const estimatedSize = 400;

let lastPageAlreadyRequested = false;

comboBox.size = estimatedSize;

// Simulates a combo-box server side data provider specifics with
// undefined size
comboBox.dataProvider = (params, callback) => {
const offset = params.page * params.pageSize;
const items = makeItems(realSize);
const itemsSlice = items.slice(offset, offset + params.pageSize);

// Combo box server side always notifies about size change
comboBox.size = params.page < 5 ? estimatedSize : realSize;

if (params.page < 5) {
callback(itemsSlice, estimatedSize);
} else if (params.page === 5) {
// Combo box server side does not update the client with the
// items which were sent recently
if (!lastPageAlreadyRequested) {
callback(itemsSlice, realSize);
lastPageAlreadyRequested = true;
}
}
};
comboBox.open();
// Scroll to last page and verify there is no loading indicator and
// the last page has been fetched and rendered
comboBox._scrollIntoView(274);
await nextFrame();
expect(comboBox.loading).to.be.false;
expect(comboBox.filteredItems).to.contain('item 293');
});
});
});
Expand Down
17 changes: 16 additions & 1 deletion packages/combo-box/test/internal-filtering.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect } from '@esm-bundle/chai';
import { fixtureSync, nextRender, outsideClick } from '@vaadin/testing-helpers';
import sinon from 'sinon';
import { ComboBoxPlaceholder } from '../src/vaadin-combo-box-placeholder.js';
import { getAllItems, getFocusedItemIndex, makeItems, onceOpened, setInputValue } from './helpers.js';
import { getAllItems, getFocusedItemIndex, getViewportItems, makeItems, onceOpened, setInputValue } from './helpers.js';

describe('internal filtering', () => {
let comboBox;
Expand Down Expand Up @@ -242,6 +242,21 @@ describe('internal filtering', () => {
});
});

describe('filtering with many items', () => {
beforeEach(async () => {
comboBox = fixtureSync('<vaadin-combo-box></vaadin-combo-box>');
comboBox.items = makeItems(1000);
await nextRender();
});

it('should reset scroll position to 0 on filter change', () => {
comboBox.opened = true;
comboBox._scrollIntoView(500);
comboBox.filter = '1';
expect(getViewportItems(comboBox)[0].index).to.equal(0);
});
});

describe('setting items when opened', () => {
beforeEach(async () => {
comboBox = fixtureSync('<vaadin-combo-box></vaadin-combo-box>');
Expand Down
111 changes: 0 additions & 111 deletions packages/combo-box/test/lazy-loading.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -1164,117 +1164,6 @@ describe('lazy loading', () => {
});
});

describe('undefined size', () => {
const ESTIMATED_SIZE = 1234;
const allItems = makeItems(ESTIMATED_SIZE);

it('should restore the scroll position after size update', () => {
const targetItemIndex = 75;
comboBox.dataProvider = getDataProvider(allItems);
comboBox.opened = true;
comboBox._scrollIntoView(targetItemIndex);
comboBox.size = 300;
// Verify whether the scroller not jumped to 0 pos and restored properly,
// having the item with 'targetItemIndex' in the bottom
// (exact visible items may vary depending of window size),
// and sometimes the 'ironList.scrollToIndex' does not point
// precisely to the given index, so use some margin
const scrollMargin = 5;
const expectedFirstVisibleIndex = targetItemIndex - getVisibleItemsCount(comboBox) - scrollMargin;
expect(getViewportItems(comboBox)[0].index).to.be.greaterThan(expectedFirstVisibleIndex);
expect(getViewportItems(comboBox).pop().index).to.be.lessThan(targetItemIndex + 1);
});

it('should reset to 0 when filter applied and filtered items size more than page size', () => {
comboBox.items = allItems;
comboBox.opened = true;
comboBox._scrollIntoView(500);
comboBox.filter = '1';
expect(getViewportItems(comboBox)[0].index).to.be.equal(0);
});

// Verifies https://github.com/vaadin/vaadin-combo-box/issues/957
it('should fetch the items after scrolling to the bottom with scrollbar', async () => {
const REAL_SIZE = 1234;
let ESTIMATED_SIZE = 200;
const allItems = makeItems(REAL_SIZE);

// DataProvider for unknown size lazy loading
const getDataProvider = (allItems) => (params, callback) => {
const filteredItems = allItems.filter((item) => item.indexOf(params.filter) > -1);
const offset = params.page * params.pageSize;
const end = offset + params.pageSize;

dataProviderItems = filteredItems.slice(offset, end);

if (dataProviderItems.size === 0) {
ESTIMATED_SIZE = offset;
} else if (dataProviderItems.size < params.pageSize) {
ESTIMATED_SIZE = offset + dataProviderItems.size;
} else if (end > ESTIMATED_SIZE - params.pageSize) {
ESTIMATED_SIZE += 200;
}
callback(dataProviderItems, ESTIMATED_SIZE);
};

comboBox.dataProvider = getDataProvider(allItems);
comboBox.opened = true;

// Scroll to the end, as though if we drag the scrollbar and move it
// to the bottom
const scrollHeight = comboBox._scroller._scrollHeight;
comboBox._scroller.scrollTop += scrollHeight;

// Flush the pending changes after the scrolling
await nextFrame();

const lastVisibleIndex = getViewportItems(comboBox).pop().index;
// Check if the next few items after the last visible item are not empty
for (let nextIndexIncrement = 0; nextIndexIncrement < 5; nextIndexIncrement++) {
const lastItem = comboBox.filteredItems[lastVisibleIndex + nextIndexIncrement];
expect(lastItem instanceof ComboBoxPlaceholder).is.false;
}
});

it('should not show the loading when exact size is suddenly reached in the middle of requested range', async () => {
const REAL_SIZE = 294;
const ESTIMATED_SIZE = 400;

const allItems = makeItems(REAL_SIZE);
let lastPageAlreadyRequested = false;

comboBox.size = ESTIMATED_SIZE;

// Simulates a combo-box server side data provider specifics with
// undefined size
comboBox.dataProvider = (params, callback) => {
const offset = params.page * params.pageSize;
const slice = allItems.slice(offset, offset + params.pageSize);

// Combo box server side always notifies about size change
comboBox.size = params.page < 5 ? ESTIMATED_SIZE : REAL_SIZE;

if (params.page < 5) {
callback(slice, ESTIMATED_SIZE);
} else if (params.page === 5) {
// Combo box server side does not update the client with the
// items which were sent recently
if (!lastPageAlreadyRequested) {
callback(slice, REAL_SIZE);
lastPageAlreadyRequested = true;
}
}
};
comboBox.open();
// Scroll to last page and verify there is no loading indicator and
// the last page has been fetched and rendered
comboBox._scrollIntoView(274);
await nextFrame();
expect(comboBox.loading).to.be.false;
expect(comboBox.filteredItems).to.contain('item 293');
});
});

describe('dropdown behaviour', () => {
let openedSpy;

Expand Down

0 comments on commit 67fb6dd

Please sign in to comment.