-
Notifications
You must be signed in to change notification settings - Fork 879
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
0b67553
commit 393e30c
Showing
5 changed files
with
183 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@lit-labs/virtualizer': patch | ||
--- | ||
|
||
Fix [#3481: Error when immediately re-rendering](https://github.com/lit/lit/issues/3481) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@lit-labs/virtualizer': patch | ||
--- | ||
|
||
Fix [#3518: New layoutComplete promise created instead of using existing one](https://github.com/lit/lit/issues/3518) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
packages/labs/virtualizer/src/test/scenarios/immediate-rerender.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/** | ||
* @license | ||
* Copyright 2022 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
import {ignoreBenignErrors} from '../helpers.js'; | ||
import {html, LitElement} from 'lit'; | ||
import {customElement} from 'lit/decorators.js'; | ||
import {LitVirtualizer} from '../../lit-virtualizer.js'; | ||
import '../../lit-virtualizer.js'; | ||
import {expect, html as testingHtml, fixture} from '@open-wc/testing'; | ||
|
||
interface ExampleItem { | ||
text: string; | ||
} | ||
|
||
@customElement('my-example') | ||
export class MyExample extends LitElement { | ||
items: ExampleItem[] = new Array(100) | ||
.fill('') | ||
.map((_, i) => ({text: `Item ${i}`})); | ||
|
||
render() { | ||
return html` | ||
<slot @slotchange=${this.#onSlotChange} style="display: none;"></slot> | ||
<lit-virtualizer | ||
.items=${this.items} | ||
.renderItem=${(item: ExampleItem) => html`<p>${item.text}</p>`} | ||
></lit-virtualizer> | ||
`; | ||
} | ||
|
||
#onSlotChange() { | ||
this.requestUpdate(); | ||
} | ||
} | ||
|
||
// This is one minimal repro case for https://github.com/lit/lit/issues/3481. | ||
// This issue occurs when something triggers an immediate re-render of virtualizer | ||
// and an attempt to tear down some internal state before the async initialization | ||
// code for that state had run. In this repro, a slotchange event triggers | ||
// the re-render, but other minimal repro cases are probably possible. The | ||
// fix we've identified is some straightforward guard code to ensure that we | ||
// don't try to tear down state that hasn't yet been set up. It's possible | ||
// we'll end up wanting to short-circuit immediate re-renders earlier (before | ||
// they reach this guard code), but for now this fix seems sufficient. | ||
describe("Don't fail when rerendering before initialization is complete", () => { | ||
ignoreBenignErrors(beforeEach, afterEach); | ||
|
||
let errorOccurred = false; | ||
|
||
function recordError(err: PromiseRejectionEvent) { | ||
if (err.reason.stack.indexOf('Virtualizer') > -1) { | ||
errorOccurred = true; | ||
} | ||
} | ||
|
||
addEventListener('unhandledrejection', recordError); | ||
|
||
it('should render without throwing an error', async () => { | ||
const example = await fixture( | ||
testingHtml`<my-example>Slot me!</my-example>` | ||
); | ||
await customElements.whenDefined('lit-virtualizer'); | ||
const virtualizer = example.shadowRoot!.querySelector('lit-virtualizer')!; | ||
expect(virtualizer).to.be.instanceOf(LitVirtualizer); | ||
await virtualizer.layoutComplete; | ||
removeEventListener('unhandledrejection', recordError); | ||
expect(errorOccurred).to.equal(false); | ||
}); | ||
}); |
69 changes: 69 additions & 0 deletions
69
packages/labs/virtualizer/src/test/scenarios/layout-complete.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/** | ||
* @license | ||
* Copyright 2022 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
import {ignoreBenignErrors} from '../helpers.js'; | ||
import {html, LitElement} from 'lit'; | ||
import {customElement} from 'lit/decorators.js'; | ||
import {LitVirtualizer} from '../../lit-virtualizer.js'; | ||
import '../../lit-virtualizer.js'; | ||
import {expect, html as testingHtml, fixture} from '@open-wc/testing'; | ||
|
||
interface ExampleItem { | ||
text: string; | ||
} | ||
|
||
@customElement('my-example') | ||
export class MyExample extends LitElement { | ||
items: ExampleItem[] = new Array(100) | ||
.fill('') | ||
.map((_, i) => ({text: `Item ${i}`})); | ||
|
||
render() { | ||
return html` | ||
<lit-virtualizer | ||
.items=${this.items} | ||
.renderItem=${(item: ExampleItem) => html`<p>${item.text}</p>`} | ||
></lit-virtualizer> | ||
`; | ||
} | ||
} | ||
|
||
describe('Basic layoutComplete functionality works', () => { | ||
ignoreBenignErrors(beforeEach, afterEach); | ||
|
||
it('resolves as soon as virtualizer has rendered, not before', async () => { | ||
const example = await fixture(testingHtml`<my-example></my-example>`); | ||
await customElements.whenDefined('lit-virtualizer'); | ||
const virtualizer = example.shadowRoot!.querySelector('lit-virtualizer')!; | ||
expect(virtualizer).to.be.instanceOf(LitVirtualizer); | ||
// Before layoutComplete, we shouldn't have rendered | ||
expect(virtualizer.children.length).to.equal(0); | ||
await virtualizer.layoutComplete; | ||
// After layoutComplete, we should have rendered children | ||
expect(virtualizer.children.length).to.be.greaterThan(0); | ||
// And our children should have been explicitly positioned. | ||
// This test depends on an implementation detail; will need to be | ||
// updated if we ever change the way we position children in the DOM. | ||
expect( | ||
(virtualizer.children[0] as HTMLElement).style.transform.indexOf( | ||
'translate' | ||
) | ||
).to.be.greaterThan(-1); | ||
}); | ||
|
||
it('returns the same promise when layoutComplete is accessed repeatedly during a single cycle', async () => { | ||
const example = await fixture(testingHtml`<my-example></my-example>`); | ||
await customElements.whenDefined('lit-virtualizer'); | ||
const virtualizer = example.shadowRoot!.querySelector('lit-virtualizer')!; | ||
const lc1 = virtualizer.layoutComplete; | ||
const lc2 = virtualizer.layoutComplete; | ||
await Promise.resolve(); | ||
const lc3 = virtualizer.layoutComplete; | ||
await new Promise((resolve) => setTimeout(resolve, 0)); | ||
const lc4 = virtualizer.layoutComplete; | ||
expect(lc1 === lc2 && lc2 === lc3 && lc3 === lc4).to.equal(true); | ||
}); | ||
}); |