diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index 88cc8f58..1e09da0a 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -3436,6 +3436,69 @@ describe("async rendering", () => { await nextTick(); expect(fixture.innerHTML).toBe("

2c

"); }); + + test("concurrent renderings scenario 9", async () => { + // Here is the global idea of this scenario: + // A + // / \ + // B C + // | + // D + // A state is updated, triggering a whole re-rendering + // B is async, and blocked + // C (and D) are rendered + // C state is updated, producing a re-rendering of C and D + // this last re-rendering of C should be correctly re-mapped to the whole + // re-rendering + const def = makeDeferred(); + let stateC; + class ComponentD extends Component { + static template = xml``; + } + class ComponentC extends Component { + static template = xml`

`; + static components = { ComponentD }; + state = useState({ fromC: "b1" }); + + constructor(parent, props) { + super(parent, props); + stateC = this.state; + } + } + class ComponentB extends Component { + static template = xml``; + willUpdateProps() { + return def; + } + } + class ComponentA extends Component { + static template = xml` +
+ + + +
`; + static components = { ComponentB, ComponentC }; + state = useState({ fromA: "a1" }); + } + + const component = new ComponentA(env); + await component.mount(fixture); + + expect(fixture.innerHTML).toBe("
a1a1

a1b1

"); + + component.state.fromA = "a2"; + await nextTick(); + expect(fixture.innerHTML).toBe("
a1a1

a1b1

"); + + stateC.fromC = "b2"; + await nextTick(); + expect(fixture.innerHTML).toBe("
a1a1

a1b1

"); + + def.resolve(); + await nextTick(); + expect(fixture.innerHTML).toBe("
a2a2

a2b2

"); + }); }); describe("widget and observable state", () => {