Skip to content

Commit

Permalink
fix(tests): adjust tbodies/tr tests, better description
Browse files Browse the repository at this point in the history
  • Loading branch information
bigopon committed Feb 23, 2019
1 parent fe9f433 commit 6d77586
Showing 1 changed file with 240 additions and 2 deletions.
242 changes: 240 additions & 2 deletions test/vr-integration.instance-changed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ describe('VirtualRepeat Integration - Instance Changed', () => {
// validates everything is renderred correctly: number of rows, first index, bot buffer height
// 3. shallow clones existing array, reverses and slice from 0 to 30 then assign to current view model
// validates everything is renderred correctly: number of rows, first index, bot buffer height
fit([
it([
'renders with reducing size collection',
' -- lesser than (repeat._viewsLength)',
' -- greater than (repeat.elementsInView)'
Expand Down Expand Up @@ -221,7 +221,7 @@ describe('VirtualRepeat Integration - Instance Changed', () => {
// validates everything is renderred correctly: number of rows, first index, bot buffer height
// 3. shallow clones existing array, reverses and slice from 0 to 30 then assign to current view model
// validates everything is renderred correctly: number of rows, first index, bot buffer height
fit([
it([
'renders with reducing size collection',
' -- lesser than (repeat.elementsInView)',
].join('\n\t'), async () => {
Expand Down Expand Up @@ -276,6 +276,244 @@ describe('VirtualRepeat Integration - Instance Changed', () => {
});
});

fdescribe('<tbody virtual-repeat.for>', () => {
beforeEach(() => {
view =
`<div style="height: 500px; overflow-y: auto">
<table style="border-spacing: 0">
<tbody virtual-repeat.for="item of items">
<tr style="height: 50px;">
<td>\${item}</td>
</tr>
</tbody>
</table>
</div>`;
});

// In this test, it bootstraps a stage with 100 items
// 1. validates everythng is renderred correctly: number of rows, first index, bot buffer height
// 2. scrolls to bottom
// validates everything is renderred correctly: number of rows, first index, bot buffer height
// 3. shallow clones existing array, reverses then assign to current view model
// validates everything is renderred correctly: number of rows, first index, bot buffer height
it('renders with 100 items', async () => {
const { virtualRepeat, viewModel } = await bootstrapComponent({ items: items });

const table = (component['host'] as HTMLElement).querySelector('table');
expect(virtualRepeat.elementsInView).toBe(Math.ceil(500 / 50) + 1, 'repeat.elementsInView');
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are TR element
expect(table.tBodies.length).toBe(/*no buffer 2 +*/virtualRepeat._viewsLength, 'table.tBodies.length 1'); // 2 buffers + 20 rows based on 50 height

expect(virtualRepeat._first).toBe(0);
expect(virtualRepeat._bottomBufferHeight).toBe(50 * (virtualRepeat.items.length - virtualRepeat._viewsLength));

// start more difficult cases

// 1. mutate scroll state
table.parentElement.scrollTop = table.parentElement.scrollHeight;
await ensureScrolled(50);
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// when scrolling, the first bound row is calculated differently compared to other scenarios
// as it can be known exactly what the last process was
// so it can create views with optimal number (scroll container height / itemHeight)
expect(virtualRepeat._first).toBe(/*items count*/100 - /*views count*/500 / 50 - /*0 based index*/1, 'repeat._first 1');
expect(virtualRepeat._bottomBufferHeight).toBe(0);

viewModel.items = viewModel.items.slice(0).reverse();
await ensureScrolled();

expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are TR elements
expect(table.tBodies.length).toBe(/*no buffer 2 +*/virtualRepeat._viewsLength, 'table.tBodies.length 2'); // 2 buffers + 20 rows based on 50 height
// This check is different from the above:
// after instance changed, it restart the "_first" view based on safe number of views
expect(virtualRepeat._first).toBe(/*items count*/100 - /*views count*/virtualRepeat._viewsLength, 'repeat._first 2');

for (let i = 0, ii = viewModel.items.length - virtualRepeat._first; ii > i; ++i) {
const view = virtualRepeat.view(i);
const currIndex = i + virtualRepeat._first;
expect(view).not.toBeNull(`view-${i} !== null`);
expect(view.bindingContext.item).toBe(`item${viewModel.items.length - currIndex - 1}`);
expect((view.firstChild as Element).firstElementChild.firstElementChild.textContent).toBe(`item${viewModel.items.length - currIndex - 1}`);
}
expect(virtualRepeat._bottomBufferHeight).toBe(0);
});

// In this test, it bootstraps a stage with 100 items
// 1. validates everythng is renderred correctly: number of rows, first index, bot buffer height
// 2. scrolls to bottom
// validates everything is renderred correctly: number of rows, first index, bot buffer height
// 3. shallow clones existing array, reverses and slice from 0 to 30 then assign to current view model
// validates everything is renderred correctly: number of rows, first index, bot buffer height
it([
'renders with 100 items',
' -- reduces to 30',
' -- greater than (repeat._viewsLength)',
].join('\n\t'), async () => {
const { virtualRepeat, viewModel } = await bootstrapComponent({ items: items });

const table = (component['host'] as HTMLElement).querySelector('table');
expect(virtualRepeat.elementsInView).toBe(Math.ceil(500 / 50) + 1, 'repeat.elementsInView');
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are TR elements
expect(table.tBodies.length).toBe(/*no buffer 2 +*/virtualRepeat._viewsLength, 'table.tBodies.length 1'); // 2 buffers + 20 rows based on 50 height

expect(virtualRepeat._first).toBe(0);
expect(virtualRepeat._bottomBufferHeight).toBe(50 * (virtualRepeat.items.length - virtualRepeat._viewsLength), 'repeat._bottomBufferHeight');

// start more difficult cases

// 1. mutate scroll state
table.parentElement.scrollTop = table.parentElement.scrollHeight;
await ensureScrolled(50);
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// when scrolling, the first bound row is calculated differently compared to other scenarios
// as it can be known exactly what the last process was
// so it can create views with optimal number (scroll container height / itemHeight)
expect(virtualRepeat._first).toBe(/*items count*/100 - /*views count*/500 / 50 - /*0 based index*/1, 'repeat._first 1');
expect(virtualRepeat._bottomBufferHeight).toBe(0);

viewModel.items = viewModel.items.slice(0).reverse().slice(0, 30);
await ensureScrolled(50);

expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are TR elements
expect(table.tBodies.length).toBe(/*no buffer 2 +*/virtualRepeat._viewsLength, 'table.tBodies.length 2'); // 2 buffers + 20 rows based on 50 height

// This check is different from the above:
// after instance changed, it restart the "_first" view based on safe number of views
// this safe number of views is different with the case of no collection size changes
// this case triggers a scroll event
expect(virtualRepeat._first).toBe(/*items count*/30 - /*element in views*/11, 'repeat._first 2');

// the following check is based on subtraction of total items count and total views count
// as total number of views hasn't been changed, and their binding contexts created by [repeat]
// haven't been changed either, despite scroll event happened
for (let i = 0, ii = viewModel.items.length - virtualRepeat._viewsLength; ii > i; ++i) {
const view = virtualRepeat.view(i);
const currIndex = i + (viewModel.items.length - virtualRepeat._viewsLength);
expect(view).not.toBeNull(`view-${i} !== null`);
expect(view.bindingContext.item).toBe(`item${100 - currIndex - 1}`, 'bindingContext.item');
expect((view.firstChild as Element).firstElementChild.firstElementChild.textContent).toBe(`item${100 - currIndex - 1}`, 'row.textContent');
}
expect(virtualRepeat._bottomBufferHeight).toBe(0);
});

it([
'renders with 100 items',
' -- reduces to 16',
' -- lesser than (repeat._viewsLength)',
' -- greater than (repeat.elementsInView)'
].join('\n\t'), async () => {
const { virtualRepeat, viewModel } = await bootstrapComponent({ items: items });

const table = (component['host'] as HTMLElement).querySelector('table');
expect(virtualRepeat.elementsInView).toBe(Math.ceil(500 / 50) + 1, 'repeat.elementsInView');
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are TR elements
expect(table.tBodies.length).toBe(/*no buffer 2 +*/virtualRepeat._viewsLength, 'table.tBodies.length'); // 2 buffers + 20 rows based on 50 height

expect(virtualRepeat._first).toBe(0);
expect(virtualRepeat._bottomBufferHeight).toBe(50 * (virtualRepeat.items.length - virtualRepeat._viewsLength));

// start more difficult cases

// 1. mutate scroll state
table.parentElement.scrollTop = table.parentElement.scrollHeight;
await ensureScrolled(50);
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// when scrolling, the first bound row is calculated differently compared to other scenarios
// as it can be known exactly what the last process was
// so it can create views with optimal number (scroll container height / itemHeight)
expect(virtualRepeat._first).toBe(/*items count*/100 - /*views count*/500 / 50 - /*0 based index*/1, 'repeat._first 1');
expect(virtualRepeat._bottomBufferHeight).toBe(0, 'repeat._bottomBufferHeight');

viewModel.items = viewModel.items.slice(0).reverse().slice(0, 16);
await ensureScrolled(50);

expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are TR elements
expect(table.tBodies.length).toBe(/*no buffer 2 +*/16, 'table.tBodies.length'); // 2 buffers + 20 rows based on 50 height

// This check is different from the above:
// after instance changed, it restart the "_first" view based on safe number of views
// this safe number of views is different with the case of no collection size changes
// this case triggers a scroll event
expect(virtualRepeat._first).toBe(/*items count*/16 - /*element in views*/11, 'repeat._first 2');

// the following check is based on subtraction of total items count and total views count
// as total number of views hasn't been changed, and their binding contexts created by [repeat]
// haven't been changed either, despite scroll event happened
for (let i = 0, ii = viewModel.items.length - virtualRepeat._viewsLength; ii > i; ++i) {
const view = virtualRepeat.view(i);
const currIndex = i + (viewModel.items.length - virtualRepeat._viewsLength);
expect(view).not.toBeNull(`view-${i} !== null`);
expect(view.bindingContext.item).toBe(`item${100 - currIndex - 1}`, 'bindingContext.item');
expect((view.firstChild as Element).firstElementChild.firstElementChild.textContent).toBe(`item${100 - currIndex - 1}`, 'row.textContent');
}
expect(virtualRepeat._bottomBufferHeight).toBe(0);
});

it([
'renders with 100 items',
' -- reduces to 8',
' -- lesser than (repeat.elementsInView)',
].join('\n\t'), async () => {
const { virtualRepeat, viewModel } = await bootstrapComponent({ items: items });

const table = (component['host'] as HTMLElement).querySelector('table');
expect(virtualRepeat.elementsInView).toBe(Math.ceil(500 / 50) + 1, 'repeat.elementsInView');
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are tr elements
expect(table.tBodies.length).toBe(/*no buffer 2 +*/virtualRepeat._viewsLength, 'table.tBodies.length 1'); // 2 buffers + 20 rows based on 50 height

expect(virtualRepeat._first).toBe(0);
expect(virtualRepeat._bottomBufferHeight).toBe(50 * (virtualRepeat.items.length - virtualRepeat._viewsLength));

// start more difficult cases

// 1. mutate scroll state
table.parentElement.scrollTop = table.parentElement.scrollHeight;
await ensureScrolled(50);
expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// when scrolling, the first bound row is calculated differently compared to other scenarios
// as it can be known exactly what the last process was
// so it can create views with optimal number (scroll container height / itemHeight)
expect(virtualRepeat._first).toBe(/*items count*/100 - /*views count*/500 / 50 - /*0 based index*/1, 'repeat._first 1');
expect(virtualRepeat._bottomBufferHeight).toBe(0);

viewModel.items = viewModel.items.slice(0).reverse().slice(0, 8);
await ensureScrolled(50);

expect(virtualRepeat._viewsLength).toBe(22, 'repeat._viewsLength');
// buffers are tr elements
expect(table.tBodies.length).toBe(/*no buffer 2 +*/8, 'table.tBodies.length 2'); // 2 buffers + 20 rows based on 50 height

// This check is different from the above:
// after instance changed, it restart the "_first" view based on safe number of views
// this safe number of views is different with the case of no collection size changes
// this case triggers a scroll event
expect(virtualRepeat._first).toBe(0, 'repeat._first 2');

// the following check is based on subtraction of total items count and total views count
// as total number of views hasn't been changed, and their binding contexts created by [repeat]
// haven't been changed either, despite scroll event happened
for (let i = 0, ii = viewModel.items.length - virtualRepeat._viewsLength; ii > i; ++i) {
const view = virtualRepeat.view(i);
const currIndex = i + (viewModel.items.length - virtualRepeat._viewsLength);
expect(view).not.toBeNull(`view-${i} !== null`);
expect(view.bindingContext.item).toBe(`item${100 - currIndex - 1}`, 'bindingContext.item');
expect((view.firstChild as Element).firstElementChild.firstElementChild.textContent).toBe(`item${100 - currIndex - 1}`, 'row.textContent');
}
expect(virtualRepeat._topBufferHeight).toBe(0);
expect(virtualRepeat._bottomBufferHeight).toBe(0);
expect(virtualRepeat.topBufferEl.getBoundingClientRect().height).toBe(0);
expect(virtualRepeat.bottomBufferEl.getBoundingClientRect().height).toBe(0);
});
});


async function bootstrapComponent<T>($viewModel?: ITestAppInterface<T>) {
component = StageComponent
.withResources(resources)
Expand Down

0 comments on commit 6d77586

Please sign in to comment.