Skip to content

Commit 92d5ef0

Browse files
committed
refactor(forms): extract shared promiseWithResolvers test helper to private/testing
Move the duplicated `promiseWithResolvers` utility function from submit.spec.ts, debounce.spec.ts, form_field.spec.ts, interop.spec.ts, compat.spec.ts, and signal_form_control.spec.ts into `packages/private/testing/src/utils.ts` and replace all local definitions with an import from `@angular/private/testing`. Fix call sites that resolve with a non-void value to use an explicit type parameter (e.g. `promiseWithResolvers<boolean>()`) to match the shared function's `T = void` default.
1 parent 1fb4678 commit 92d5ef0

7 files changed

Lines changed: 29 additions & 118 deletions

File tree

‎packages/forms/signals/test/node/api/debounce.spec.ts‎

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import {Injector, signal} from '@angular/core';
1010
import {TestBed} from '@angular/core/testing';
1111
import {applyWhenValue, debounce, form} from '@angular/forms/signals';
12+
import {promiseWithResolvers} from '@angular/private/testing';
1213

1314
describe('debounce', () => {
1415
describe('by duration', () => {
@@ -519,25 +520,3 @@ function timeout(durationInMilliseconds: number): Promise<void> {
519520
function forever(): Promise<never> {
520521
return new Promise(() => {});
521522
}
522-
523-
/**
524-
* Replace with `Promise.withResolvers()` once it's available.
525-
*
526-
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers.
527-
*/
528-
// TODO: share this with submit.spec.ts
529-
function promiseWithResolvers<T = void>(): {
530-
promise: Promise<T>;
531-
resolve: (value: T | PromiseLike<T>) => void;
532-
reject: (reason?: any) => void;
533-
} {
534-
let resolve!: (value: T | PromiseLike<T>) => void;
535-
let reject!: (reason?: any) => void;
536-
537-
const promise = new Promise<T>((res, rej) => {
538-
resolve = res;
539-
reject = rej;
540-
});
541-
542-
return {promise, resolve, reject};
543-
}

‎packages/forms/signals/test/node/compat/compat.spec.ts‎

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,7 @@ import {
2424
validate,
2525
validateTree,
2626
} from '../../../public_api';
27-
28-
function promiseWithResolvers<T>(): {
29-
promise: Promise<T>;
30-
resolve: (value: T | PromiseLike<T>) => void;
31-
reject: (reason?: any) => void;
32-
} {
33-
let resolve!: (value: T | PromiseLike<T>) => void;
34-
let reject!: (reason?: any) => void;
35-
36-
const promise = new Promise<T>((res, rej) => {
37-
resolve = res;
38-
reject = rej;
39-
});
40-
41-
return {promise, resolve, reject};
42-
}
27+
import {promiseWithResolvers} from '@angular/private/testing';
4328

4429
describe('Forms compat', () => {
4530
it('should not error on a valid value', () => {

‎packages/forms/signals/test/node/compat/signal_form_control.spec.ts‎

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,14 @@ import {ControlEvent, FormControlStatus, FormGroup, FormResetEvent} from '@angul
1919
import {disabled, required, validateAsync, ValidationError} from '@angular/forms/signals';
2020
import {SchemaFn} from '../../../src/api/types';
2121
import {SignalFormControl} from '../../../compat';
22+
import {promiseWithResolvers} from '@angular/private/testing';
2223

2324
function createSignalFormControl<T>(initialValue: T, schema?: SchemaFn<T>) {
2425
const injector = TestBed.inject(Injector);
2526

2627
return new SignalFormControl(initialValue, schema, {injector});
2728
}
2829

29-
function promiseWithResolvers<T = void>(): {
30-
promise: Promise<T>;
31-
resolve: (value: T | PromiseLike<T>) => void;
32-
reject: (reason?: any) => void;
33-
} {
34-
let resolve!: (value: T | PromiseLike<T>) => void;
35-
let reject!: (reason?: any) => void;
36-
const promise = new Promise<T>((res, rej) => {
37-
resolve = res;
38-
reject = rej;
39-
});
40-
return {promise, resolve, reject};
41-
}
42-
4330
describe('SignalFormControl', () => {
4431
describe('value and state access', () => {
4532
it('should have the same value as the signal', () => {

‎packages/forms/signals/test/node/submit.spec.ts‎

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
validateAsync,
2020
ValidationError,
2121
} from '../../public_api';
22+
import {promiseWithResolvers} from '@angular/private/testing';
2223

2324
describe('submit', () => {
2425
let injector: Injector;
@@ -142,7 +143,7 @@ describe('submit', () => {
142143
it('should resolve pending validation after successful submit', async () => {
143144
const appRef = TestBed.inject(ApplicationRef);
144145
const data = signal('foo');
145-
const {promise, resolve} = promiseWithResolvers();
146+
const {promise, resolve} = promiseWithResolvers<boolean>();
146147
const f = form(
147148
data,
148149
(p) => {
@@ -642,24 +643,3 @@ describe('submit', () => {
642643
expect(submitSpy).toHaveBeenCalledWith({name: 'Alice'}, {name: 'Alice'}, 'Alice');
643644
});
644645
});
645-
646-
/**
647-
* Replace with `Promise.withResolvers()` once it's available.
648-
*
649-
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers.
650-
*/
651-
function promiseWithResolvers<T>(): {
652-
promise: Promise<T>;
653-
resolve: (value: T | PromiseLike<T>) => void;
654-
reject: (reason?: any) => void;
655-
} {
656-
let resolve!: (value: T | PromiseLike<T>) => void;
657-
let reject!: (reason?: any) => void;
658-
659-
const promise = new Promise<T>((res, rej) => {
660-
resolve = res;
661-
reject = rej;
662-
});
663-
664-
return {promise, resolve, reject};
665-
}

‎packages/forms/signals/test/web/form_field.spec.ts‎

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import {
6969
} from '../../public_api';
7070
import {InputValidityMonitor} from '../../src/directive/input_validity_monitor';
7171
import {TestInputValidityMonitor} from './test_input_validity_monitor';
72+
import {promiseWithResolvers} from '@angular/private/testing';
7273

7374
function configureTestValidityMonitor() {
7475
TestBed.configureTestingModule({
@@ -6490,25 +6491,3 @@ function act<T>(fn: () => T): T {
64906491
TestBed.tick();
64916492
}
64926493
}
6493-
6494-
/**
6495-
* Replace with `Promise.withResolvers()` once it's available.
6496-
*
6497-
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers.
6498-
*/
6499-
// TODO: share this with submit.spec.ts
6500-
function promiseWithResolvers<T = void>(): {
6501-
promise: Promise<T>;
6502-
resolve: (value: T | PromiseLike<T>) => void;
6503-
reject: (reason?: any) => void;
6504-
} {
6505-
let resolve!: (value: T | PromiseLike<T>) => void;
6506-
let reject!: (reason?: any) => void;
6507-
6508-
const promise = new Promise<T>((res, rej) => {
6509-
resolve = res;
6510-
reject = rej;
6511-
});
6512-
6513-
return {promise, resolve, reject};
6514-
}

‎packages/forms/signals/test/web/interop.spec.ts‎

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import {
5656
WithOptionalFieldTree,
5757
transformedValue,
5858
} from '@angular/forms/signals';
59+
import {promiseWithResolvers} from '@angular/private/testing';
5960

6061
describe('ControlValueAccessor', () => {
6162
beforeEach(() => {
@@ -1520,25 +1521,3 @@ async function actAsync<T>(fn: () => T): Promise<T> {
15201521
await TestBed.inject(ApplicationRef).whenStable();
15211522
}
15221523
}
1523-
1524-
/**
1525-
* Replace with `Promise.withResolvers()` once it's available.
1526-
*
1527-
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers.
1528-
*/
1529-
// TODO: share this with submit.spec.ts
1530-
function promiseWithResolvers<T = void>(): {
1531-
promise: Promise<T>;
1532-
resolve: (value: T | PromiseLike<T>) => void;
1533-
reject: (reason?: any) => void;
1534-
} {
1535-
let resolve!: (value: T | PromiseLike<T>) => void;
1536-
let reject!: (reason?: any) => void;
1537-
1538-
const promise = new Promise<T>((res, rej) => {
1539-
resolve = res;
1540-
reject = rej;
1541-
});
1542-
1543-
return {promise, resolve, reject};
1544-
}

‎packages/private/testing/src/utils.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,25 @@ export async function waitFor<T>(
298298
await new Promise((resolve) => void realSetTimeout(resolve, interval));
299299
}
300300
}
301+
302+
/**
303+
* Replace with `Promise.withResolvers()` once it's available.
304+
* NET September 2026
305+
*
306+
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers.
307+
*/
308+
export function promiseWithResolvers<T = void>(): {
309+
promise: Promise<T>;
310+
resolve: (value: T | PromiseLike<T>) => void;
311+
reject: (reason?: any) => void;
312+
} {
313+
let resolve!: (value: T | PromiseLike<T>) => void;
314+
let reject!: (reason?: any) => void;
315+
316+
const promise = new Promise<T>((res, rej) => {
317+
resolve = res;
318+
reject = rej;
319+
});
320+
321+
return {promise, resolve, reject};
322+
}

0 commit comments

Comments
 (0)