Skip to content

Commit 2fa6ab7

Browse files
chore(deps): update jest monorepo to v30 (major) (#2605)
* chore(deps): update jest monorepo to v30 * .. * Lets go --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Arda TANRIKULU <[email protected]>
1 parent 26a128a commit 2fa6ab7

File tree

9 files changed

+919
-543
lines changed

9 files changed

+919
-543
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"@ianvs/prettier-plugin-sort-imports": "4.4.2",
3535
"@theguild/prettier-config": "2.0.7",
3636
"@types/benchmark": "2.1.5",
37-
"@types/jest": "29.5.14",
37+
"@types/jest": "30.0.0",
3838
"@types/k6": "1.0.2",
3939
"@types/node": "22.15.32",
4040
"@typescript-eslint/eslint-plugin": "8.35.0",
@@ -53,7 +53,7 @@
5353
"eslint-plugin-unicorn": "59.0.1",
5454
"globby": "14.1.0",
5555
"husky": "9.1.7",
56-
"jest": "29.7.0",
56+
"jest": "30.0.2",
5757
"lint-staged": "16.1.2",
5858
"prettier": "3.6.0",
5959
"prettier-plugin-pkg": "0.21.1",

packages/core/src/utils.ts

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -109,74 +109,96 @@ export function finalAsyncIterator<TInput>(
109109
source: AsyncIterable<TInput>,
110110
onFinal: () => void,
111111
): AsyncGenerator<TInput> {
112-
const iterator = source[Symbol.asyncIterator]();
112+
let iterator: AsyncIterator<TInput>;
113+
function ensureIterator() {
114+
if (!iterator) {
115+
iterator = source[Symbol.asyncIterator]();
116+
}
117+
return iterator;
118+
}
113119
let isDone = false;
114-
const stream: AsyncGenerator<TInput> = {
120+
return {
115121
[Symbol.asyncIterator]() {
116-
return stream;
122+
return this;
117123
},
118124
next() {
119-
return iterator.next().then(result => {
120-
if (result.done && isDone === false) {
121-
isDone = true;
122-
onFinal();
123-
}
124-
return result;
125-
});
125+
return ensureIterator()
126+
.next()
127+
.then(result => {
128+
if (result.done && isDone === false) {
129+
isDone = true;
130+
onFinal();
131+
}
132+
return result;
133+
});
126134
},
127135
return() {
128-
const promise = iterator.return?.();
136+
const promise = ensureIterator().return?.();
129137
if (isDone === false) {
130138
isDone = true;
131139
onFinal();
132140
}
133141
return promise || fakePromise({ done: true, value: undefined });
134142
},
135143
throw(error: unknown) {
136-
const promise = iterator.throw?.();
144+
const promise = ensureIterator().throw?.();
137145
if (promise) {
138146
return promise;
139147
}
140148
// if the source has no throw method we just re-throw error
141149
// usually throw is not called anyways
142150
throw error;
143151
},
144-
};
145-
146-
return stream;
152+
[Symbol.asyncDispose || Symbol.for('Symbol.asyncDispose')]() {
153+
// This is a no-op, but we need to implement it to ensure that the AsyncGenerator
154+
// is properly cleaned up when the subscription is disposed.
155+
return fakePromise();
156+
},
157+
} as AsyncGenerator<TInput>;
147158
}
148159

149160
export function errorAsyncIterator<TInput>(
150161
source: AsyncIterable<TInput>,
151162
onError: (err: unknown) => void,
152163
): AsyncGenerator<TInput> {
153-
const iterator = source[Symbol.asyncIterator]();
154-
const stream: AsyncGenerator<TInput> = {
164+
let iterator: AsyncIterator<TInput>;
165+
function ensureIterator() {
166+
if (!iterator) {
167+
iterator = source[Symbol.asyncIterator]();
168+
}
169+
return iterator;
170+
}
171+
return {
155172
[Symbol.asyncIterator]() {
156-
return stream;
173+
return this;
157174
},
158175
next() {
159-
return iterator.next().catch(error => {
160-
onError(error);
161-
return { done: true, value: undefined };
162-
});
176+
return ensureIterator()
177+
.next()
178+
.catch(error => {
179+
onError(error);
180+
return { done: true, value: undefined };
181+
});
163182
},
164183
return() {
165-
const promise = iterator.return?.();
184+
const promise = ensureIterator().return?.();
166185
return promise || fakePromise({ done: true, value: undefined });
167186
},
168187
throw(error: unknown) {
169-
const promise = iterator.throw?.();
188+
const promise = ensureIterator().throw?.();
170189
if (promise) {
171190
return promise;
172191
}
173192
// if the source has no throw method we just re-throw error
174193
// usually throw is not called anyways
175194
throw error;
176195
},
177-
};
178-
179-
return stream;
196+
[Symbol.asyncDispose || Symbol.for('Symbol.asyncDispose')]() {
197+
// This is a no-op, but we need to implement it to ensure that the AsyncGenerator
198+
// is properly cleaned up when the subscription is disposed.
199+
return fakePromise();
200+
},
201+
} as AsyncGenerator<TInput>;
180202
}
181203

182204
export { mapMaybePromise, isPromise } from '@whatwg-node/promise-helpers';

packages/core/test/execute.spec.ts

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '@envelop/testing';
99
import { OnExecuteDoneHookResult, OnSubscribeResultResult } from '@envelop/types';
1010
import { makeExecutableSchema } from '@graphql-tools/schema';
11+
import { fakePromise } from '@whatwg-node/promise-helpers';
1112
import { query, schema } from './common.js';
1213

1314
type Deferred<T = void> = {
@@ -324,6 +325,11 @@ describe('execute', () => {
324325
async throw() {
325326
throw new Error('Noop.');
326327
},
328+
[Symbol.asyncDispose]() {
329+
// This is a no-op, but we need to implement it to ensure that the AsyncGenerator
330+
// is properly cleaned up when the subscription is disposed.
331+
return fakePromise();
332+
},
327333
});
328334

329335
const teskit = createTestkit(
@@ -380,24 +386,30 @@ describe('execute', () => {
380386
const delayNextDeferred = createDeferred();
381387
let isReturnCalled = false;
382388

383-
const streamExecuteFn = (): AsyncGenerator => ({
384-
[Symbol.asyncIterator]() {
385-
return this;
386-
},
387-
async next() {
388-
return delayNextDeferred.promise.then(() => ({
389-
value: { data: { alphabet: 'a' } },
390-
done: false,
391-
}));
392-
},
393-
async return() {
394-
isReturnCalled = true;
395-
return { done: true, value: undefined };
396-
},
397-
async throw() {
398-
throw new Error('Noop.');
399-
},
400-
});
389+
const streamExecuteFn = () =>
390+
({
391+
[Symbol.asyncIterator]() {
392+
return this;
393+
},
394+
async next() {
395+
return delayNextDeferred.promise.then(() => ({
396+
value: { data: { alphabet: 'a' } },
397+
done: false,
398+
}));
399+
},
400+
async return() {
401+
isReturnCalled = true;
402+
return { done: true, value: undefined };
403+
},
404+
async throw() {
405+
throw new Error('Noop.');
406+
},
407+
[Symbol.asyncDispose]() {
408+
// This is a no-op, but we need to implement it to ensure that the AsyncGenerator
409+
// is properly cleaned up when the subscription is disposed.
410+
return fakePromise();
411+
},
412+
}) as AsyncGenerator;
401413

402414
const teskit = createTestkit(
403415
[
@@ -462,7 +474,7 @@ describe('execute', () => {
462474
expect.assertions(2);
463475
let isReturnCalled = false;
464476
const values = ['a', 'b', 'c', 'd'];
465-
const source: AsyncGenerator = {
477+
const source = {
466478
[Symbol.asyncIterator]() {
467479
return this;
468480
},
@@ -480,7 +492,12 @@ describe('execute', () => {
480492
async throw() {
481493
throw new Error('Noop.');
482494
},
483-
};
495+
[Symbol.asyncDispose]() {
496+
// This is a no-op, but we need to implement it to ensure that the AsyncGenerator
497+
// is properly cleaned up when the subscription is disposed.
498+
return fakePromise();
499+
},
500+
} as AsyncGenerator;
484501

485502
const schema = makeExecutableSchema({
486503
typeDefs: /* GraphQL */ `
@@ -575,7 +592,7 @@ it.each([
575592
const delayNextDeferred = createDeferred();
576593
let isReturnCalled = false;
577594

578-
const source: AsyncGenerator = {
595+
const source = {
579596
[Symbol.asyncIterator]() {
580597
return this;
581598
},
@@ -592,7 +609,12 @@ it.each([
592609
async throw() {
593610
throw new Error('Noop.');
594611
},
595-
};
612+
[Symbol.asyncDispose]() {
613+
// This is a no-op, but we need to implement it to ensure that the AsyncGenerator
614+
// is properly cleaned up when the subscription is disposed.
615+
return fakePromise();
616+
},
617+
} as AsyncGenerator;
596618

597619
const schema = makeExecutableSchema({
598620
typeDefs: /* GraphQL */ `

packages/core/test/plugins/use-error-handler.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ describe('useErrorHandler', () => {
134134

135135
expect(mockHandler).toHaveBeenCalledWith(
136136
expect.objectContaining({
137-
errors: expect.objectContaining([testError]),
137+
errors: expect.arrayContaining([testError]),
138138
phase: 'execution',
139139
}),
140140
);

packages/plugins/fragment-arguments/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"@types/common-tags": "1.8.4",
6161
"common-tags": "1.8.2",
6262
"graphql": "16.8.1",
63-
"jest-diff": "29.7.0",
63+
"jest-diff": "30.0.2",
6464
"oneline": "2.0.0",
6565
"typescript": "5.8.3"
6666
},

packages/plugins/on-resolve/test/use-on-resolve.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ describe('useOnResolve', () => {
2525

2626
await testkit.execute('{ test: value1, test1: value2 }');
2727

28-
expect(onResolveFn).toBeCalledTimes(2);
29-
expect(onResolveDoneFn).toBeCalledTimes(2);
28+
expect(onResolveFn).toHaveBeenCalledTimes(2);
29+
expect(onResolveDoneFn).toHaveBeenCalledTimes(2);
3030

3131
let i = 0;
3232
for (const field of ['value1', 'value2']) {
@@ -55,8 +55,8 @@ describe('useOnResolve', () => {
5555

5656
await testkit.execute('{ __schema{ ... on __Schema{ queryType { name } } } }');
5757

58-
expect(onResolveFn).toBeCalledTimes(2);
59-
expect(onResolveDoneFn).toBeCalledTimes(2);
58+
expect(onResolveFn).toHaveBeenCalledTimes(2);
59+
expect(onResolveDoneFn).toHaveBeenCalledTimes(2);
6060

6161
let i = 0;
6262
for (const field of ['queryType', 'name']) {
@@ -81,8 +81,8 @@ describe('useOnResolve', () => {
8181

8282
await testkit.execute('{ __schema{ ... on __Schema{ queryType { name } } } }');
8383

84-
expect(onResolveFn).toBeCalledTimes(0);
85-
expect(onResolveDoneFn).toBeCalledTimes(0);
84+
expect(onResolveFn).toHaveBeenCalledTimes(0);
85+
expect(onResolveDoneFn).toHaveBeenCalledTimes(0);
8686
});
8787

8888
it('should replace the result using the after hook', async () => {
@@ -122,7 +122,7 @@ describe('useOnResolve', () => {
122122

123123
const result = await testkit.execute('{ value1 }');
124124
// Expect two calls, not four.
125-
expect(afterResolve).toBeCalledTimes(2);
125+
expect(afterResolve).toHaveBeenCalledTimes(2);
126126

127127
assertSingleExecutionValue(result);
128128
expect(result.data?.value1).toBe('value2');

0 commit comments

Comments
 (0)