Skip to content

Commit d1500ec

Browse files
yaacovCRrobrichardglasser
committed
reintroduce experimental incremental delivery support for subscriptions
to preserve backwards compatibility with v16 alphas/experimental branches entrypoint renamed to legacyExperimentalSubscribeIncrementally Co-authored-by: Rob Richard <rob@1stdibs.com> Co-authored-by: David Glasser <glasser@davidglasser.net>
1 parent 2779370 commit d1500ec

File tree

6 files changed

+641
-14
lines changed

6 files changed

+641
-14
lines changed
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import { expect } from 'chai';
2+
import { describe, it } from 'mocha';
3+
4+
import { expectPromise } from '../../__testUtils__/expectPromise.js';
5+
6+
import { flattenAsyncIterable } from '../flattenAsyncIterable.js';
7+
8+
describe('flattenAsyncIterable', () => {
9+
it('flatten nested async generators', async () => {
10+
async function* source() {
11+
yield await Promise.resolve({
12+
value: 1,
13+
nestedIterable: (async function* nested(): AsyncGenerator<
14+
number,
15+
void,
16+
void
17+
> {
18+
yield await Promise.resolve(1.1);
19+
yield await Promise.resolve(1.2);
20+
})(),
21+
});
22+
yield await Promise.resolve({
23+
value: 2,
24+
nestedIterable: (async function* nested(): AsyncGenerator<
25+
number,
26+
void,
27+
void
28+
> {
29+
yield await Promise.resolve(2.1);
30+
yield await Promise.resolve(2.2);
31+
})(),
32+
});
33+
}
34+
35+
const doubles = flattenAsyncIterable(source(), (item) => item);
36+
37+
const result = [];
38+
for await (const x of doubles) {
39+
result.push(x);
40+
}
41+
expect(result).to.deep.equal([1, 1.1, 1.2, 2, 2.1, 2.2]);
42+
});
43+
44+
it('passes through errors from a nested async generator', async () => {
45+
async function* source() {
46+
yield await Promise.resolve({
47+
value: 1,
48+
nestedIterable: (async function* nested(): AsyncGenerator<
49+
number,
50+
void,
51+
void
52+
> {
53+
yield await Promise.resolve(1.1);
54+
yield await Promise.resolve(1.2);
55+
})(),
56+
});
57+
throw new Error('ouch');
58+
}
59+
/* c8 ignore stop */
60+
61+
const doubles = flattenAsyncIterable(source(), (item) => item);
62+
63+
expect(await doubles.next()).to.deep.equal({ value: 1, done: false });
64+
expect(await doubles.next()).to.deep.equal({ value: 1.1, done: false });
65+
expect(await doubles.next()).to.deep.equal({ value: 1.2, done: false });
66+
67+
await expectPromise(doubles.next()).toRejectWith('ouch');
68+
});
69+
70+
it('allows returning early from a nested async generator', async () => {
71+
async function* source() {
72+
yield await Promise.resolve({
73+
value: 1,
74+
nestedIterable: (async function* nested(): AsyncGenerator<
75+
number,
76+
void,
77+
void
78+
> {
79+
yield await Promise.resolve(1.1);
80+
yield await Promise.resolve(1.2);
81+
})(),
82+
});
83+
yield await Promise.resolve({
84+
value: 2,
85+
nestedIterable: (async function* nested(): AsyncGenerator<
86+
number,
87+
void,
88+
void
89+
> {
90+
yield await Promise.resolve(2.1); /* c8 ignore start */
91+
// Not reachable, early return
92+
yield await Promise.resolve(2.2);
93+
})(),
94+
});
95+
// Not reachable, early return
96+
yield await Promise.resolve({
97+
value: 3,
98+
nestedIterable: (async function* nested(): AsyncGenerator<
99+
number,
100+
void,
101+
void
102+
> {
103+
yield await Promise.resolve(3.1);
104+
yield await Promise.resolve(3.2);
105+
})(),
106+
});
107+
}
108+
/* c8 ignore stop */
109+
110+
const doubles = flattenAsyncIterable(source(), (item) => item);
111+
112+
expect(await doubles.next()).to.deep.equal({ value: 1, done: false });
113+
expect(await doubles.next()).to.deep.equal({ value: 1.1, done: false });
114+
expect(await doubles.next()).to.deep.equal({ value: 1.2, done: false });
115+
expect(await doubles.next()).to.deep.equal({ value: 2, done: false });
116+
expect(await doubles.next()).to.deep.equal({ value: 2.1, done: false });
117+
118+
// Early return
119+
expect(await doubles.return()).to.deep.equal({
120+
value: undefined,
121+
done: true,
122+
});
123+
124+
// Subsequent next calls
125+
expect(await doubles.next()).to.deep.equal({
126+
value: undefined,
127+
done: true,
128+
});
129+
expect(await doubles.next()).to.deep.equal({
130+
value: undefined,
131+
done: true,
132+
});
133+
});
134+
135+
it('allows throwing errors into a nested async generator', async () => {
136+
async function* source() {
137+
yield await Promise.resolve({
138+
value: 1,
139+
nestedIterable: (async function* nested(): AsyncGenerator<
140+
number,
141+
void,
142+
void
143+
> {
144+
yield await Promise.resolve(1.1);
145+
yield await Promise.resolve(1.2);
146+
})(),
147+
});
148+
yield await Promise.resolve({
149+
value: 2,
150+
nestedIterable: (async function* nested(): AsyncGenerator<
151+
number,
152+
void,
153+
void
154+
> {
155+
yield await Promise.resolve(2.1); /* c8 ignore start */
156+
// Not reachable, early return
157+
yield await Promise.resolve(2.2);
158+
})(),
159+
});
160+
// Not reachable, early return
161+
yield await Promise.resolve({ value: 3 });
162+
}
163+
/* c8 ignore stop */
164+
165+
const doubles = flattenAsyncIterable(source(), (item) => item);
166+
167+
expect(await doubles.next()).to.deep.equal({ value: 1, done: false });
168+
expect(await doubles.next()).to.deep.equal({ value: 1.1, done: false });
169+
expect(await doubles.next()).to.deep.equal({ value: 1.2, done: false });
170+
expect(await doubles.next()).to.deep.equal({ value: 2, done: false });
171+
expect(await doubles.next()).to.deep.equal({ value: 2.1, done: false });
172+
173+
// Throw error
174+
await expectPromise(doubles.throw(new Error('ouch'))).toRejectWith('ouch');
175+
});
176+
177+
it('completely yields sub-iterables even when next() called in parallel', async () => {
178+
async function* source() {
179+
yield await Promise.resolve({
180+
value: 1,
181+
nestedIterable: (async function* nested(): AsyncGenerator<
182+
number,
183+
void,
184+
void
185+
> {
186+
yield await Promise.resolve(1.1);
187+
yield await Promise.resolve(1.2);
188+
})(),
189+
});
190+
yield await Promise.resolve({
191+
value: 2,
192+
nestedIterable: (async function* nested(): AsyncGenerator<
193+
number,
194+
void,
195+
void
196+
> {
197+
yield await Promise.resolve(2.1);
198+
yield await Promise.resolve(2.2);
199+
})(),
200+
});
201+
}
202+
203+
const result = flattenAsyncIterable(source(), (item) => item);
204+
205+
const promise1 = result.next();
206+
const promise2 = result.next();
207+
const promise3 = result.next();
208+
expect(await promise1).to.deep.equal({ value: 1, done: false });
209+
expect(await promise2).to.deep.equal({ value: 1.1, done: false });
210+
expect(await promise3).to.deep.equal({ value: 1.2, done: false });
211+
expect(await result.next()).to.deep.equal({ value: 2, done: false });
212+
expect(await result.next()).to.deep.equal({ value: 2.1, done: false });
213+
expect(await result.next()).to.deep.equal({ value: 2.2, done: false });
214+
expect(await result.next()).to.deep.equal({
215+
value: undefined,
216+
done: true,
217+
});
218+
});
219+
});

0 commit comments

Comments
 (0)