Skip to content

Commit

Permalink
Add some tests for nested effects (#371)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewiggins committed Jun 15, 2023
1 parent d38fd8a commit 145bcb3
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 0 deletions.
26 changes: 26 additions & 0 deletions packages/core/test/signal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,32 @@ describe("effect()", () => {
expect(spy).not.to.be.called;
});

it("should not rerun parent effect if a nested child effect's signal's value changes", () => {
const parentSignal = signal(0);
const childSignal = signal(0);

const parentEffect = sinon.spy(() => parentSignal.value);
const childEffect = sinon.spy(() => childSignal.value);

effect(() => {
parentEffect();
effect(childEffect);
});

expect(parentEffect).to.be.calledOnce;
expect(childEffect).to.be.calledOnce;

childSignal.value = 1;

expect(parentEffect).to.be.calledOnce;
expect(childEffect).to.be.calledTwice;

parentSignal.value = 1;

expect(parentEffect).to.be.calledTwice;
expect(childEffect).to.be.calledThrice;
});

// Test internal behavior depended on by Preact & React integrations
describe("internals", () => {
it("should pass in the effect instance in callback's `this`", () => {
Expand Down
64 changes: 64 additions & 0 deletions packages/preact/test/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,70 @@ describe("@preact/signals", () => {
rerender();
expect(spy).to.be.calledOnce;
});

it("should not subscribe to computed signals only created and not used", () => {
const sig = signal(0);
const childSpy = sinon.spy();
const parentSpy = sinon.spy();

function Child({ num }: { num: Signal<number> }) {
childSpy();
return <p>{num.value}</p>;
}

function Parent({ num }: { num: Signal<number> }) {
parentSpy();
const sig2 = useComputed(() => num.value + 1);
return <Child num={sig2} />;
}

render(<Parent num={sig} />, scratch);
expect(scratch.innerHTML).to.equal("<p>1</p>");
expect(parentSpy).to.be.calledOnce;
expect(childSpy).to.be.calledOnce;

sig.value += 1;
rerender();
expect(scratch.innerHTML).to.equal("<p>2</p>");
expect(parentSpy).to.be.calledOnce;
expect(childSpy).to.be.calledTwice;
});

it("should properly subscribe and unsubscribe to conditionally rendered computed signals ", () => {
const computedDep = signal(0);
const renderComputed = signal(true);
const renderSpy = sinon.spy();
const computer = sinon.spy(() => computedDep.value + 1);

function App() {
renderSpy();
const computed = useComputed(computer);
return renderComputed.value ? <p>{computed.value}</p> : null;
}

render(<App />, scratch);
expect(scratch.innerHTML).to.equal("<p>1</p>");
expect(renderSpy).to.be.calledOnce;
expect(computer).to.be.calledOnce;

computedDep.value += 1;
rerender();
expect(scratch.innerHTML).to.equal("<p>2</p>");
expect(renderSpy).to.be.calledTwice;
expect(computer).to.be.calledTwice;

renderComputed.value = false;
rerender();
expect(scratch.innerHTML).to.equal("");
expect(renderSpy).to.be.calledThrice;
expect(computer).to.be.calledTwice;

computedDep.value += 1;
rerender();
expect(scratch.innerHTML).to.equal("");
expect(renderSpy).to.be.calledThrice; // Should not be called again
expect(computer).to.be.calledTwice; // Should not be called again
});
});

describe("prop bindings", () => {
Expand Down
64 changes: 64 additions & 0 deletions packages/react/test/browser/updates.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
useComputed,
useSignalEffect,
useSignal,
Signal,
} from "@preact/signals-react";
import {
createElement,
Expand Down Expand Up @@ -452,6 +453,69 @@ describe("@preact/signals-react updating", () => {
});
expect(scratch.innerHTML).to.equal("<div>1 1</div>");
});

it("should not subscribe to computed signals only created and not used", async () => {
const sig = signal(0);
const childSpy = sinon.spy();
const parentSpy = sinon.spy();

function Child({ num }: { num: Signal<number> }) {
childSpy();
return <p>{num.value}</p>;
}

function Parent({ num }: { num: Signal<number> }) {
parentSpy();
const sig2 = useComputed(() => num.value + 1);
return <Child num={sig2} />;
}

await render(<Parent num={sig} />);
expect(scratch.innerHTML).to.equal("<p>1</p>");
expect(parentSpy).to.be.calledOnce;
expect(childSpy).to.be.calledOnce;

await act(() => {
sig.value += 1;
});
expect(scratch.innerHTML).to.equal("<p>2</p>");
expect(parentSpy).to.be.calledOnce;
expect(childSpy).to.be.calledTwice;
});

it("should properly subscribe and unsubscribe to conditionally rendered computed signals ", async () => {
const computedDep = signal(0);
const renderComputed = signal(true);
const renderSpy = sinon.spy();

function App() {
renderSpy();
const computed = useComputed(() => computedDep.value + 1);
return renderComputed.value ? <p>{computed.value}</p> : null;
}

await render(<App />);
expect(scratch.innerHTML).to.equal("<p>1</p>");
expect(renderSpy).to.be.calledOnce;

await act(() => {
computedDep.value += 1;
});
expect(scratch.innerHTML).to.equal("<p>2</p>");
expect(renderSpy).to.be.calledTwice;

await act(() => {
renderComputed.value = false;
});
expect(scratch.innerHTML).to.equal("");
expect(renderSpy).to.be.calledThrice;

await act(() => {
computedDep.value += 1;
});
expect(scratch.innerHTML).to.equal("");
expect(renderSpy).to.be.calledThrice; // Should not be called again
});
});

describe("useSignal()", () => {
Expand Down

0 comments on commit 145bcb3

Please sign in to comment.