Skip to content

Commit 9f6e47a

Browse files
authored
feat: iterateFormatted's to also format given iterables' current values if present (#56)
1 parent 01a30fc commit 9f6e47a

File tree

5 files changed

+214
-119
lines changed

5 files changed

+214
-119
lines changed

spec/tests/Iterate.spec.tsx

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -627,55 +627,68 @@ describe('`Iterate` component', () => {
627627
'When given an iterable with a `.value.current` property at any point, uses that as the current value and skips the pending stage'
628628
),
629629
() =>
630-
[{ initialValue: undefined }, { initialValue: '_' }].forEach(({ initialValue }) => {
631-
it(
632-
gray(`${!initialValue ? 'without initial value' : 'with initial value and ignoring it'}`),
633-
async () => {
634-
const renderFn = vi.fn() as Mock<
635-
(next: IterationResult<AsyncIterable<string>, string>) => any
636-
>;
637-
const [channel1, channel2] = ['__current__1', '__current__2'].map(current =>
638-
Object.assign(new IteratorChannelTestHelper<string>(), {
639-
value: { current },
640-
})
641-
);
642-
643-
const Component = (props: { value: AsyncIterable<string> }) => (
644-
<Iterate value={props.value} initialValue={initialValue}>
645-
{renderFn.mockImplementation(() => (
646-
<div id="test-created-elem">Render count: {renderFn.mock.calls.length}</div>
647-
))}
648-
</Iterate>
649-
);
650-
651-
const rendered = render(<></>);
652-
const renderedHtmls = [];
653-
654-
for (const run of [
655-
() => act(() => rendered.rerender(<Component value={channel1} />)),
656-
() => act(() => channel1.put('a')),
657-
() => act(() => rendered.rerender(<Component value={channel2} />)),
658-
() => act(() => channel2.put('b')),
659-
]) {
660-
await run();
661-
renderedHtmls.push(rendered.container.innerHTML);
630+
([{ initialValue: undefined }, { initialValue: '_' }] as const).forEach(
631+
({ initialValue }) => {
632+
it(
633+
gray(
634+
`${!initialValue ? 'without initial value' : 'with initial value and ignoring it'}`
635+
),
636+
async () => {
637+
const renderFn = vi.fn() as Mock<
638+
(next: IterationResult<AsyncIterable<string>, string>) => any
639+
>;
640+
const [channel1, channel2] = ['a_current', 'b_current'].map(current =>
641+
Object.assign(new IteratorChannelTestHelper<string>(), {
642+
value: { current },
643+
})
644+
);
645+
646+
const Component = (props: { value: AsyncIterable<string> }) => (
647+
<Iterate value={props.value} initialValue={initialValue}>
648+
{renderFn.mockImplementation(() => (
649+
<div id="test-created-elem">Render count: {renderFn.mock.calls.length}</div>
650+
))}
651+
</Iterate>
652+
);
653+
654+
const rendered = render(<></>);
655+
const renderedHtmls = [];
656+
657+
for (const run of [
658+
() => act(() => rendered.rerender(<Component value={channel1} />)),
659+
() => act(() => channel1.put('a')),
660+
() =>
661+
act(() =>
662+
rendered.rerender(
663+
<Component
664+
value={iterateFormatted(channel2, (val, i) => `${val}_formatted_${i}`)}
665+
/>
666+
)
667+
),
668+
() => act(() => channel2.put('b')),
669+
]) {
670+
await run();
671+
renderedHtmls.push(rendered.container.innerHTML);
672+
}
673+
674+
expect(renderFn.mock.calls.flat()).toStrictEqual(
675+
['a_current', 'a', 'b_current_formatted_0', 'b_formatted_0'].map(value => ({
676+
value,
677+
pendingFirst: false,
678+
done: false,
679+
error: undefined,
680+
}))
681+
);
682+
expect(renderedHtmls).toStrictEqual([
683+
'<div id="test-created-elem">Render count: 1</div>',
684+
'<div id="test-created-elem">Render count: 2</div>',
685+
'<div id="test-created-elem">Render count: 3</div>',
686+
'<div id="test-created-elem">Render count: 4</div>',
687+
]);
662688
}
663-
664-
expect(renderFn.mock.calls.flat()).toStrictEqual([
665-
{ value: '__current__1', pendingFirst: false, done: false, error: undefined },
666-
{ value: 'a', pendingFirst: false, done: false, error: undefined },
667-
{ value: '__current__2', pendingFirst: false, done: false, error: undefined },
668-
{ value: 'b', pendingFirst: false, done: false, error: undefined },
669-
]);
670-
expect(renderedHtmls).toStrictEqual([
671-
'<div id="test-created-elem">Render count: 1</div>',
672-
'<div id="test-created-elem">Render count: 2</div>',
673-
'<div id="test-created-elem">Render count: 3</div>',
674-
'<div id="test-created-elem">Render count: 4</div>',
675-
]);
676-
}
677-
);
678-
})
689+
);
690+
}
691+
)
679692
);
680693

681694
it(gray('When unmounted will close the last active iterator it held'), async () => {

spec/tests/IterateMulti.spec.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ describe('`IterateMulti` hook', () => {
680680
const renderFn = vi.fn() as Mock<
681681
(nexts: IterationResultSet<AsyncIterable<string>[]>) => any
682682
>;
683-
const [channel1, channel2] = ['__current__1', '__current__2'].map(current =>
683+
const [channel1, channel2] = ['a_current', 'b_current'].map(current =>
684684
Object.assign(new IteratorChannelTestHelper<string>(), {
685685
value: { current },
686686
})
@@ -700,22 +700,37 @@ describe('`IterateMulti` hook', () => {
700700
for (const run of [
701701
() => act(() => rendered.rerender(<Component values={[channel1]} />)),
702702
() => act(() => channel1.put('a')),
703-
() => act(() => rendered.rerender(<Component values={[channel2, channel1]} />)),
703+
() =>
704+
act(() =>
705+
rendered.rerender(
706+
<Component
707+
values={[
708+
iterateFormatted(channel2, (val, i) => `${val}_formatted_${i}`),
709+
channel1,
710+
]}
711+
/>
712+
)
713+
),
704714
() => act(() => channel2.put('b')),
705715
]) {
706716
await run();
707717
renderedHtmls.push(rendered.container.innerHTML);
708718
}
709719

710720
expect(renderFn.mock.calls.flat()).toStrictEqual([
711-
[{ value: '__current__1', pendingFirst: false, done: false, error: undefined }],
721+
[{ value: 'a_current', pendingFirst: false, done: false, error: undefined }],
712722
[{ value: 'a', pendingFirst: false, done: false, error: undefined }],
713723
[
714-
{ value: '__current__2', pendingFirst: false, done: false, error: undefined },
724+
{
725+
value: 'b_current_formatted_0',
726+
pendingFirst: false,
727+
done: false,
728+
error: undefined,
729+
},
715730
{ value: 'a', pendingFirst: false, done: false, error: undefined },
716731
],
717732
[
718-
{ value: 'b', pendingFirst: false, done: false, error: undefined },
733+
{ value: 'b_formatted_0', pendingFirst: false, done: false, error: undefined },
719734
{ value: 'a', pendingFirst: false, done: false, error: undefined },
720735
],
721736
]);

spec/tests/useAsyncIter.spec.ts

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { it, describe, expect, afterEach, vi } from 'vitest';
22
import { gray } from 'colorette';
33
import { cleanup as cleanupMountedReactTrees, act, renderHook } from '@testing-library/react';
44
import { useAsyncIter, iterateFormatted } from '../../src/index.js';
5+
import { pipe } from '../utils/pipe.js';
56
import { asyncIterOf } from '../utils/asyncIterOf.js';
67
import { IteratorChannelTestHelper } from '../utils/IteratorChannelTestHelper.js';
78

@@ -435,41 +436,57 @@ describe('`useAsyncIter` hook', () => {
435436
'When given an iterable with a `.value.current` property at any point, uses that as the current value and skips the pending stage'
436437
),
437438
() =>
438-
[{ initialValue: undefined }, { initialValue: '_' }].forEach(({ initialValue }) => {
439-
it(
440-
gray(`${!initialValue ? 'without initial value' : 'with initial value and ignoring it'}`),
441-
async () => {
442-
const [channel1, channel2] = ['__current__1', '__current__2'].map(current =>
443-
Object.assign(new IteratorChannelTestHelper<string>(), {
444-
value: { current },
445-
})
446-
);
447-
448-
const renderedHook = renderHook(props => useAsyncIter(props.channel, initialValue), {
449-
initialProps: { channel: undefined as undefined | AsyncIterable<string> },
450-
});
451-
452-
const results: any[] = [];
453-
454-
for (const run of [
455-
() => act(() => renderedHook.rerender({ channel: channel1 })),
456-
() => act(() => channel1.put('a')),
457-
() => act(() => renderedHook.rerender({ channel: channel2 })),
458-
() => act(() => channel2.put('b')),
459-
]) {
460-
await run();
461-
results.push(renderedHook.result.current);
439+
([{ initialValue: undefined }, { initialValue: '_' }] as const).forEach(
440+
({ initialValue }) => {
441+
it(
442+
gray(
443+
`${!initialValue ? 'without initial value' : 'with initial value and ignoring it'}`
444+
),
445+
async () => {
446+
const [channel1, channel2] = ['a_current', 'b_current'].map(current =>
447+
Object.assign(new IteratorChannelTestHelper<string>(), {
448+
value: { current },
449+
})
450+
);
451+
452+
const renderedHook = renderHook(props => useAsyncIter(props.value, initialValue), {
453+
initialProps: { value: undefined as undefined | AsyncIterable<string> },
454+
});
455+
456+
const results: any[] = [];
457+
458+
for (const run of [
459+
() =>
460+
act(() =>
461+
renderedHook.rerender({
462+
value: channel1,
463+
})
464+
),
465+
() => act(() => channel1.put('a')),
466+
() =>
467+
act(() =>
468+
renderedHook.rerender({
469+
value: iterateFormatted(channel2, (val, i) => `${val}_formatted_${i}`),
470+
})
471+
),
472+
() => act(() => channel2.put('b')),
473+
]) {
474+
await run();
475+
results.push(renderedHook.result.current);
476+
}
477+
478+
expect(results).toStrictEqual(
479+
['a_current', 'a', 'b_current_formatted_0', 'b_formatted_0'].map(value => ({
480+
value,
481+
pendingFirst: false,
482+
done: false,
483+
error: undefined,
484+
}))
485+
);
462486
}
463-
464-
expect(results).toStrictEqual([
465-
{ value: '__current__1', pendingFirst: false, done: false, error: undefined },
466-
{ value: 'a', pendingFirst: false, done: false, error: undefined },
467-
{ value: '__current__2', pendingFirst: false, done: false, error: undefined },
468-
{ value: 'b', pendingFirst: false, done: false, error: undefined },
469-
]);
470-
}
471-
);
472-
})
487+
);
488+
}
489+
)
473490
);
474491

475492
it(gray('When unmounted will close the last active iterator it held'), async () => {
@@ -603,7 +620,7 @@ describe('`useAsyncIter` hook', () => {
603620

604621
it(
605622
gray(
606-
'When given a `ReactAsyncIterable` yielding `undefined`s or `null`s that wraps an iter which originally yields non-nullable values, returns the `undefined`s and `null`s in the result as expected'
623+
'When given a `ReactAsyncIterable` yielding `undefined`s or `null`s that wraps an iter which originally yields non-nullable values, returns the `undefined`s and `null`s in the result as expected (https://github.com/shtaif/react-async-iterators/pull/32)'
607624
),
608625
async () => {
609626
const channel = new IteratorChannelTestHelper<string>();

spec/tests/useAsyncIterMulti.spec.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -456,38 +456,51 @@ describe('`useAsyncIterMulti` hook', () => {
456456
`${!initialValues?.length ? 'without initial values' : 'with initial values and ignoring them'}`
457457
),
458458
async () => {
459-
const [channel1, channel2] = ['__current__1', '__current__2'].map(current =>
459+
const [channel1, channel2] = ['a_current', 'b_current'].map(current =>
460460
Object.assign(new IteratorChannelTestHelper<string>(), {
461461
value: { current },
462462
})
463463
);
464464

465465
const renderedHook = renderHook(
466-
props => useAsyncIterMulti(props.channels, { initialValues }),
467-
{ initialProps: { channels: [] as AsyncIterable<string>[] } }
466+
props => useAsyncIterMulti(props.values, { initialValues }),
467+
{ initialProps: { values: [] as AsyncIterable<string>[] } }
468468
);
469469

470470
const results: any[] = [];
471471

472472
for (const run of [
473-
() => act(() => renderedHook.rerender({ channels: [channel1] })),
473+
() => act(() => renderedHook.rerender({ values: [channel1] })),
474474
() => act(() => channel1.put('a')),
475-
() => act(() => renderedHook.rerender({ channels: [channel2, channel1] })),
475+
() =>
476+
act(() =>
477+
renderedHook.rerender({
478+
values: [
479+
iterateFormatted(channel2, (val, i) => `${val}_formatted_${i}`),
480+
channel1,
481+
],
482+
})
483+
),
476484
() => act(() => channel2.put('b')),
477485
]) {
478486
await run();
479487
results.push(renderedHook.result.current);
480488
}
481489

482490
expect(results).toStrictEqual([
483-
[{ value: '__current__1', pendingFirst: false, done: false, error: undefined }],
491+
[{ value: 'a_current', pendingFirst: false, done: false, error: undefined }],
484492
[{ value: 'a', pendingFirst: false, done: false, error: undefined }],
485493
[
486-
{ value: '__current__2', pendingFirst: false, done: false, error: undefined },
494+
{
495+
value: 'b_current_formatted_0',
496+
pendingFirst: false,
497+
done: false,
498+
error: undefined,
499+
},
487500
{ value: 'a', pendingFirst: false, done: false, error: undefined },
488501
],
489502
[
490-
{ value: 'b', pendingFirst: false, done: false, error: undefined },
503+
{ value: 'b_formatted_0', pendingFirst: false, done: false, error: undefined },
491504
{ value: 'a', pendingFirst: false, done: false, error: undefined },
492505
],
493506
]);

0 commit comments

Comments
 (0)