diff --git a/spec/tests/Iterate.spec.tsx b/spec/tests/Iterate.spec.tsx index c43ec25..3814432 100644 --- a/spec/tests/Iterate.spec.tsx +++ b/spec/tests/Iterate.spec.tsx @@ -1,4 +1,4 @@ -import { it, describe, expect, afterEach, vi } from 'vitest'; +import { it, describe, expect, afterEach } from 'vitest'; import { gray } from 'colorette'; import { render, cleanup as cleanupMountedReactTrees, act } from '@testing-library/react'; import { Iterate, It, type IterationResult } from '../../src/index.js'; @@ -503,11 +503,6 @@ describe('`Iterate` component', () => { new IteratorChannelTestHelper(), ]; - const [channelReturnSpy1, channelReturnSpy2] = [ - vi.spyOn(channel1, 'return'), - vi.spyOn(channel2, 'return'), - ]; - const buildTestContent = (value: AsyncIterable) => { return ( @@ -524,8 +519,8 @@ describe('`Iterate` component', () => { { rendered.rerender(buildTestContent(channel1)); - expect(channelReturnSpy1).not.toHaveBeenCalled(); - expect(channelReturnSpy2).not.toHaveBeenCalled(); + expect(channel1.return).not.toHaveBeenCalled(); + expect(channel2.return).not.toHaveBeenCalled(); expect(lastRenderFnInput).toStrictEqual({ value: undefined, pendingFirst: true, @@ -548,8 +543,8 @@ describe('`Iterate` component', () => { { rendered.rerender(buildTestContent(channel2)); - expect(channelReturnSpy1).toHaveBeenCalledOnce(); - expect(channelReturnSpy2).not.toHaveBeenCalled(); + expect(channel1.return).toHaveBeenCalledOnce(); + expect(channel2.return).not.toHaveBeenCalled(); expect(lastRenderFnInput).toStrictEqual({ value: 'a', pendingFirst: true, @@ -572,8 +567,8 @@ describe('`Iterate` component', () => { { rendered.rerender(buildTestContent((async function* () {})())); - expect(channelReturnSpy1).toHaveBeenCalledOnce(); - expect(channelReturnSpy2).toHaveBeenCalledOnce(); + expect(channel1.return).toHaveBeenCalledOnce(); + expect(channel2.return).toHaveBeenCalledOnce(); expect(lastRenderFnInput).toStrictEqual({ value: 'b', pendingFirst: true, @@ -589,7 +584,6 @@ describe('`Iterate` component', () => { let lastRenderFnInput: undefined | IterationResult; const channel = new IteratorChannelTestHelper(); - const channelReturnSpy = vi.spyOn(channel, 'return'); const buildTestContent = (value: AsyncIterable) => { return ( @@ -607,7 +601,7 @@ describe('`Iterate` component', () => { { rendered.rerender(buildTestContent(channel)); - expect(channelReturnSpy).not.toHaveBeenCalled(); + expect(channel.return).not.toHaveBeenCalled(); expect(lastRenderFnInput).toStrictEqual({ value: undefined, pendingFirst: true, @@ -629,7 +623,7 @@ describe('`Iterate` component', () => { { rendered.unmount(); - expect(channelReturnSpy).toHaveBeenCalledOnce(); + expect(channel.return).toHaveBeenCalledOnce(); } }); diff --git a/spec/tests/iterateFormatted.spec.tsx b/spec/tests/iterateFormatted.spec.tsx index ef0dc1d..a9291a3 100644 --- a/spec/tests/iterateFormatted.spec.tsx +++ b/spec/tests/iterateFormatted.spec.tsx @@ -1,4 +1,4 @@ -import { it, describe, expect, afterEach, vi } from 'vitest'; +import { it, describe, expect, afterEach } from 'vitest'; import { gray } from 'colorette'; import { render, cleanup as cleanupMountedReactTrees, act } from '@testing-library/react'; import { iterateFormatted, Iterate } from '../../src/index.js'; @@ -84,11 +84,6 @@ describe('`iterateFormatted` function', () => { new IteratorChannelTestHelper(), ]; - const [channelReturnSpy1, channelReturnSpy2] = [ - vi.spyOn(channel1, 'return'), - vi.spyOn(channel2, 'return'), - ]; - const rebuildTestContent = (it: AsyncIterable) => ( { const rendered = render(<>); rendered.rerender(rebuildTestContent(channel1)); - expect(channelReturnSpy1).not.toHaveBeenCalled(); + expect(channel1.return).not.toHaveBeenCalled(); rendered.rerender(rebuildTestContent(channel1)); - expect(channelReturnSpy1).not.toHaveBeenCalled(); + expect(channel1.return).not.toHaveBeenCalled(); rendered.rerender(rebuildTestContent(channel2)); - expect(channelReturnSpy1).toHaveBeenCalledOnce(); - expect(channelReturnSpy2).not.toHaveBeenCalled(); + expect(channel1.return).toHaveBeenCalledOnce(); + expect(channel2.return).not.toHaveBeenCalled(); rendered.rerender(rebuildTestContent(channel2)); - expect(channelReturnSpy2).not.toHaveBeenCalled(); + expect(channel2.return).not.toHaveBeenCalled(); } ); diff --git a/spec/tests/useAsyncIter.spec.ts b/spec/tests/useAsyncIter.spec.ts index 7d6ab6e..e698df4 100644 --- a/spec/tests/useAsyncIter.spec.ts +++ b/spec/tests/useAsyncIter.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect, afterEach, vi } from 'vitest'; +import { it, describe, expect, afterEach } from 'vitest'; import { gray } from 'colorette'; import { cleanup as cleanupMountedReactTrees, act, renderHook } from '@testing-library/react'; import { useAsyncIter } from '../../src/index.js'; @@ -339,11 +339,6 @@ describe('`useAsyncIter` hook', () => { new IteratorChannelTestHelper(), ]; - const [channelReturnSpy1, channelReturnSpy2] = [ - vi.spyOn(channel1, 'return'), - vi.spyOn(channel2, 'return'), - ]; - const renderedHook = renderHook(({ value }) => useAsyncIter(value), { initialProps: { value: (async function* () {})() as AsyncIterable, @@ -353,8 +348,8 @@ describe('`useAsyncIter` hook', () => { { renderedHook.rerender({ value: channel1 }); - expect(channelReturnSpy1).not.toHaveBeenCalled(); - expect(channelReturnSpy2).not.toHaveBeenCalled(); + expect(channel1.return).not.toHaveBeenCalled(); + expect(channel2.return).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual({ value: undefined, pendingFirst: true, @@ -375,8 +370,8 @@ describe('`useAsyncIter` hook', () => { { renderedHook.rerender({ value: channel2 }); - expect(channelReturnSpy1).toHaveBeenCalledOnce(); - expect(channelReturnSpy2).not.toHaveBeenCalled(); + expect(channel1.return).toHaveBeenCalledOnce(); + expect(channel2.return).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual({ value: 'a', pendingFirst: true, @@ -397,8 +392,8 @@ describe('`useAsyncIter` hook', () => { { renderedHook.rerender({ value: (async function* () {})() }); - expect(channelReturnSpy1).toHaveBeenCalledOnce(); - expect(channelReturnSpy2).toHaveBeenCalledOnce(); + expect(channel1.return).toHaveBeenCalledOnce(); + expect(channel2.return).toHaveBeenCalledOnce(); expect(renderedHook.result.current).toStrictEqual({ value: 'b', pendingFirst: true, @@ -411,7 +406,6 @@ describe('`useAsyncIter` hook', () => { it(gray('When unmounted will close the last active iterator it held'), async () => { const channel = new IteratorChannelTestHelper(); - const channelReturnSpy = vi.spyOn(channel, 'return'); const renderedHook = renderHook(({ value }) => useAsyncIter(value), { initialProps: { @@ -422,7 +416,7 @@ describe('`useAsyncIter` hook', () => { { renderedHook.rerender({ value: channel }); - expect(channelReturnSpy).not.toHaveBeenCalled(); + expect(channel.return).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual({ value: undefined, pendingFirst: true, @@ -442,7 +436,7 @@ describe('`useAsyncIter` hook', () => { { renderedHook.unmount(); - expect(channelReturnSpy).toHaveBeenCalledOnce(); + expect(channel.return).toHaveBeenCalledOnce(); } }); diff --git a/spec/tests/useAsyncIterMulti.spec.ts b/spec/tests/useAsyncIterMulti.spec.ts index d380885..641b637 100644 --- a/spec/tests/useAsyncIterMulti.spec.ts +++ b/spec/tests/useAsyncIterMulti.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect, afterEach, vi } from 'vitest'; +import { it, describe, expect, afterEach } from 'vitest'; import { gray } from 'colorette'; import { range } from 'lodash-es'; import { cleanup as cleanupMountedReactTrees, act, renderHook } from '@testing-library/react'; @@ -352,8 +352,8 @@ describe('`useAsyncIterMulti` hook', () => { async () => { let channel1 = new IteratorChannelTestHelper<'a' | 'b' | 'c'>(); let channel2 = new IteratorChannelTestHelper<'a' | 'b' | 'c'>(); - const channel1ReturnSpy = vi.spyOn(channel1, 'return'); - const channel2ReturnSpy = vi.spyOn(channel2, 'return'); + const origChannel1ReturnSpy = channel1.return; + const origChannel2ReturnSpy = channel2.return; let timesRerendered = 0; const renderedHook = renderHook( @@ -366,8 +366,8 @@ describe('`useAsyncIterMulti` hook', () => { await act(() => {}); expect(timesRerendered).toStrictEqual(1); - expect(channel1ReturnSpy).not.toHaveBeenCalled(); - expect(channel2ReturnSpy).not.toHaveBeenCalled(); + expect(origChannel1ReturnSpy).not.toHaveBeenCalled(); + expect(origChannel2ReturnSpy).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual([ { value: undefined, pendingFirst: true, done: false, error: undefined }, { value: undefined, pendingFirst: true, done: false, error: undefined }, @@ -375,8 +375,8 @@ describe('`useAsyncIterMulti` hook', () => { await act(() => channel1.put('a')); expect(timesRerendered).toStrictEqual(2); - expect(channel1ReturnSpy).not.toHaveBeenCalled(); - expect(channel2ReturnSpy).not.toHaveBeenCalled(); + expect(origChannel1ReturnSpy).not.toHaveBeenCalled(); + expect(origChannel2ReturnSpy).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual([ { value: 'a', pendingFirst: false, done: false, error: undefined }, { value: undefined, pendingFirst: true, done: false, error: undefined }, @@ -387,8 +387,8 @@ describe('`useAsyncIterMulti` hook', () => { renderedHook.rerender({ values: [channel1, channel2] as const }); }); expect(timesRerendered).toStrictEqual(3); - expect(channel1ReturnSpy).toHaveBeenCalled(); - expect(channel2ReturnSpy).not.toHaveBeenCalled(); + expect(origChannel1ReturnSpy).toHaveBeenCalledOnce(); + expect(origChannel2ReturnSpy).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual([ { value: 'a', pendingFirst: true, done: false, error: undefined }, { value: undefined, pendingFirst: true, done: false, error: undefined }, @@ -399,8 +399,8 @@ describe('`useAsyncIterMulti` hook', () => { renderedHook.rerender({ values: [channel1, channel2] as const }); }); expect(timesRerendered).toStrictEqual(4); - expect(channel1ReturnSpy).toHaveBeenCalled(); - expect(channel2ReturnSpy).toHaveBeenCalled(); + expect(origChannel1ReturnSpy).toHaveBeenCalledOnce(); + expect(origChannel2ReturnSpy).toHaveBeenCalledOnce(); expect(renderedHook.result.current).toStrictEqual([ { value: 'a', pendingFirst: true, done: false, error: undefined }, { value: undefined, pendingFirst: true, done: false, error: undefined }, @@ -418,8 +418,6 @@ describe('`useAsyncIterMulti` hook', () => { it(gray('When unmounted will close all the last held active iterators'), async () => { const channel1 = new IteratorChannelTestHelper<'a' | 'b' | 'c'>(); const channel2 = new IteratorChannelTestHelper<'a' | 'b' | 'c'>(); - const channel1ReturnSpy = vi.spyOn(channel1, 'return'); - const channel2ReturnSpy = vi.spyOn(channel2, 'return'); const renderedHook = renderHook(props => useAsyncIterMulti(props.values), { initialProps: { @@ -432,8 +430,8 @@ describe('`useAsyncIterMulti` hook', () => { { await act(() => renderedHook.rerender({ values: [channel1, channel2] })); - expect(channel1ReturnSpy).not.toHaveBeenCalled(); - expect(channel2ReturnSpy).not.toHaveBeenCalled(); + expect(channel1.return).not.toHaveBeenCalled(); + expect(channel2.return).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual([ { value: undefined, pendingFirst: true, done: false, error: undefined }, { value: undefined, pendingFirst: true, done: false, error: undefined }, @@ -448,8 +446,8 @@ describe('`useAsyncIterMulti` hook', () => { { renderedHook.unmount(); - expect(channel1ReturnSpy).toHaveBeenCalledOnce(); - expect(channel2ReturnSpy).toHaveBeenCalledOnce(); + expect(channel1.return).toHaveBeenCalledOnce(); + expect(channel2.return).toHaveBeenCalledOnce(); } }); @@ -464,12 +462,6 @@ describe('`useAsyncIterMulti` hook', () => { const channelB = new IteratorChannelTestHelper(); const channelC = new IteratorChannelTestHelper(); - const [channelReturnSpyA, channelReturnSpyB, channelReturnSpyC] = [ - channelA, - channelB, - channelC, - ].map(ch => vi.spyOn(ch, 'return')); - const renderedHook = await act(() => renderHook(({ values }) => useAsyncIterMulti(values), { initialProps: { values }, @@ -555,9 +547,9 @@ describe('`useAsyncIterMulti` hook', () => { values.splice(0, 3); renderedHook.rerender({ values }); }); - expect(channelReturnSpyC).not.toHaveBeenCalled(); - expect(channelReturnSpyB).not.toHaveBeenCalled(); - expect(channelReturnSpyA).not.toHaveBeenCalled(); + expect(channelC.return).not.toHaveBeenCalled(); + expect(channelB.return).not.toHaveBeenCalled(); + expect(channelA.return).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual([ { value: 'c_from_iter', pendingFirst: false, done: false, error: undefined }, { value: 'b_from_iter', pendingFirst: false, done: false, error: undefined }, @@ -568,9 +560,9 @@ describe('`useAsyncIterMulti` hook', () => { values.shift(); renderedHook.rerender({ values }); }); - expect(channelReturnSpyC).toHaveBeenCalledOnce(); - expect(channelReturnSpyB).not.toHaveBeenCalled(); - expect(channelReturnSpyA).not.toHaveBeenCalled(); + expect(channelC.return).toHaveBeenCalledOnce(); + expect(channelB.return).not.toHaveBeenCalled(); + expect(channelA.return).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual([ { value: 'b_from_iter', pendingFirst: false, done: false, error: undefined }, { value: 'a_from_iter', pendingFirst: false, done: false, error: undefined }, @@ -580,9 +572,9 @@ describe('`useAsyncIterMulti` hook', () => { values.shift(); renderedHook.rerender({ values }); }); - expect(channelReturnSpyC).toHaveBeenCalledOnce(); - expect(channelReturnSpyB).toHaveBeenCalledOnce(); - expect(channelReturnSpyA).not.toHaveBeenCalled(); + expect(channelC.return).toHaveBeenCalledOnce(); + expect(channelB.return).toHaveBeenCalledOnce(); + expect(channelA.return).not.toHaveBeenCalled(); expect(renderedHook.result.current).toStrictEqual([ { value: 'a_from_iter', pendingFirst: false, done: false, error: undefined }, ]); @@ -591,9 +583,9 @@ describe('`useAsyncIterMulti` hook', () => { values.shift(); renderedHook.rerender({ values }); }); - expect(channelReturnSpyC).toHaveBeenCalledOnce(); - expect(channelReturnSpyB).toHaveBeenCalledOnce(); - expect(channelReturnSpyA).toHaveBeenCalledOnce(); + expect(channelC.return).toHaveBeenCalledOnce(); + expect(channelB.return).toHaveBeenCalledOnce(); + expect(channelA.return).toHaveBeenCalledOnce(); expect(renderedHook.result.current).toStrictEqual([]); } ); @@ -665,8 +657,6 @@ describe('`useAsyncIterMulti` hook', () => { async () => { const channel1 = new IteratorChannelTestHelper(); const channel2 = new IteratorChannelTestHelper(); - const channel1ReturnSpy = vi.spyOn(channel1, 'return'); - const channel2ReturnSpy = vi.spyOn(channel2, 'return'); const renderedHook = await act(() => renderHook(() => @@ -685,8 +675,8 @@ describe('`useAsyncIterMulti` hook', () => { for (let i = 0; i < 3; ++i) { await act(() => renderedHook.rerender()); } - expect(channel1ReturnSpy).not.toHaveBeenCalled(); - expect(channel2ReturnSpy).not.toHaveBeenCalled(); + expect(channel1.return).not.toHaveBeenCalled(); + expect(channel2.return).not.toHaveBeenCalled(); await act(() => channel1.put('a')); expect(renderedHook.result.current).toStrictEqual([ diff --git a/spec/utils/IteratorChannelTestHelper.ts b/spec/utils/IteratorChannelTestHelper.ts index f4414b7..39b3fc8 100644 --- a/spec/utils/IteratorChannelTestHelper.ts +++ b/spec/utils/IteratorChannelTestHelper.ts @@ -1,3 +1,5 @@ +import { vi, type MockInstance } from 'vitest'; + export { IteratorChannelTestHelper }; class IteratorChannelTestHelper implements AsyncIterableIterator, AsyncDisposable { @@ -36,13 +38,20 @@ class IteratorChannelTestHelper implements AsyncIterableIterator, AsyncDis this.#nextIteration.resolve({ done: true, value: undefined }); } - async next(): Promise> { - return this.#nextIteration.promise; - } - - async return(): Promise> { + async #_return(): Promise> { this.complete(); const res = await this.#nextIteration.promise; return res as typeof res & { done: true }; } + + async next(): Promise> { + return this.#nextIteration.promise; + } + + return = (): Promise> => this.#_return(); + + returnSpy: MockInstance<() => Promise>> = vi.spyOn( + this as IteratorChannelTestHelper, + 'return' + ); }