Skip to content

Commit ec3ede4

Browse files
committed
refactor(core): use native Promise.withResolvers() in tests
Replaces the temporary `promiseWithResolvers` polyfill with the native `Promise.withResolvers()` API in test files and Updates the TypeScript configuration to include the `es2024.promise`.
1 parent 1fb4678 commit ec3ede4

8 files changed

Lines changed: 32 additions & 150 deletions

File tree

‎packages/core/test/resource/resource_spec.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {
2424
signal,
2525
TransferState,
2626
} from '../../src/core';
27-
import {promiseWithResolvers} from '../../src/util/promise_with_resolvers';
2827
import {TestBed} from '../../testing';
2928

3029
abstract class MockBackend<T, R> {
@@ -343,7 +342,7 @@ describe('resource', () => {
343342
const res = resource({
344343
params: request,
345344
loader: async ({params}) => {
346-
const p = promiseWithResolvers<number>();
345+
const p = Promise.withResolvers<number>();
347346
resolve.push(() => p.resolve(params));
348347
return p.promise;
349348
},

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

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ describe('debounce', () => {
104104
});
105105

106106
it('should synchronize value after promise resolves', async () => {
107-
const {promise, resolve} = promiseWithResolvers<void>();
107+
const {promise, resolve} = Promise.withResolvers<void>();
108108
const address = signal({street: ''});
109109
const addressForm = form(
110110
address,
@@ -126,8 +126,8 @@ describe('debounce', () => {
126126
});
127127

128128
it('should synchronize value after most recently returned promise resolves', async () => {
129-
const first = promiseWithResolvers();
130-
const second = promiseWithResolvers();
129+
const first = Promise.withResolvers<void>();
130+
const second = Promise.withResolvers<void>();
131131
const debounceFn = jasmine
132132
.createSpy('debounceFn')
133133
.and.returnValues(first.promise, second.promise);
@@ -158,7 +158,7 @@ describe('debounce', () => {
158158
});
159159

160160
it('should be ignored if value is directly set before it resolves', async () => {
161-
const debounceResult = promiseWithResolvers();
161+
const debounceResult = Promise.withResolvers<void>();
162162
const debounceFn = jasmine.createSpy('debounceFn').and.returnValues(debounceResult.promise);
163163

164164
const address = signal({street: ''});
@@ -188,7 +188,7 @@ describe('debounce', () => {
188188

189189
describe('abort signal', () => {
190190
it('should be aborted if control value is set again', async () => {
191-
const {promise, resolve} = promiseWithResolvers();
191+
const {promise, resolve} = Promise.withResolvers<void>();
192192
const abortSpy = jasmine.createSpy('abort');
193193

194194
const address = signal({street: ''});
@@ -519,25 +519,3 @@ function timeout(durationInMilliseconds: number): Promise<void> {
519519
function forever(): Promise<never> {
520520
return new Promise(() => {});
521521
}
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 & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,6 @@ import {
2525
validateTree,
2626
} from '../../../public_api';
2727

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-
}
43-
4428
describe('Forms compat', () => {
4529
it('should not error on a valid value', () => {
4630
const cat = signal({
@@ -349,7 +333,7 @@ describe('Forms compat', () => {
349333
expect(f().submitting()).toBe(false);
350334
expect(f.age().submitting()).toBe(false);
351335

352-
const {promise, resolve} = promiseWithResolvers<TreeValidationResult>();
336+
const {promise, resolve} = Promise.withResolvers<TreeValidationResult>();
353337

354338
const result = submit(f, {
355339
action: (field) => {

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

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,6 @@ function createSignalFormControl<T>(initialValue: T, schema?: SchemaFn<T>) {
2626
return new SignalFormControl(initialValue, schema, {injector});
2727
}
2828

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-
4329
describe('SignalFormControl', () => {
4430
describe('value and state access', () => {
4531
it('should have the same value as the signal', () => {
@@ -93,11 +79,11 @@ describe('SignalFormControl', () => {
9379
});
9480

9581
it('should expose pending status for async validators', async () => {
96-
let deferred = promiseWithResolvers<ValidationError[]>();
82+
let deferred = Promise.withResolvers<ValidationError[]>();
9783
const resolveNext = (errors: ValidationError[]) => {
9884
TestBed.tick();
9985
deferred.resolve(errors);
100-
deferred = promiseWithResolvers<ValidationError[]>();
86+
deferred = Promise.withResolvers<ValidationError[]>();
10187
};
10288

10389
const form = createSignalFormControl('initial', (p) => {

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

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('submit', () => {
5151
describe('while pending', () => {
5252
it('should not block', async () => {
5353
const data = signal('');
54-
const {promise} = promiseWithResolvers();
54+
const {promise} = Promise.withResolvers();
5555
const f = form(
5656
data,
5757
(p) => {
@@ -81,7 +81,7 @@ describe('submit', () => {
8181
it('should retain submit errors after pending validation resolves', async () => {
8282
const appRef = TestBed.inject(ApplicationRef);
8383
const data = signal('foo');
84-
const {promise, resolve} = promiseWithResolvers<boolean>();
84+
const {promise, resolve} = Promise.withResolvers<boolean>();
8585
const f = form(
8686
data,
8787
(p) => {
@@ -110,7 +110,7 @@ describe('submit', () => {
110110
it('should resolve pending validation on subfield', async () => {
111111
const appRef = TestBed.inject(ApplicationRef);
112112
const data = signal({first: 'foo', last: 'bar'});
113-
const {promise, resolve} = promiseWithResolvers<boolean>();
113+
const {promise, resolve} = Promise.withResolvers<boolean>();
114114
const f = form(
115115
data,
116116
(p) => {
@@ -142,7 +142,7 @@ describe('submit', () => {
142142
it('should resolve pending validation after successful submit', async () => {
143143
const appRef = TestBed.inject(ApplicationRef);
144144
const data = signal('foo');
145-
const {promise, resolve} = promiseWithResolvers();
145+
const {promise, resolve} = Promise.withResolvers<boolean>();
146146
const f = form(
147147
data,
148148
(p) => {
@@ -287,7 +287,7 @@ describe('submit', () => {
287287
);
288288
expect(f().submitting()).toBe(false);
289289

290-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
290+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
291291
const result = submit(f, {action: () => promise});
292292
expect(f().submitting()).toBe(true);
293293

@@ -297,7 +297,7 @@ describe('submit', () => {
297297

298298
it('prohibits concurrent submits', async () => {
299299
const f = form(signal(0), {injector});
300-
const {promise, resolve} = promiseWithResolvers<undefined>();
300+
const {promise, resolve} = Promise.withResolvers<undefined>();
301301
const submitSpy = jasmine.createSpy('submit').and.callFake(() => promise);
302302

303303
const result1 = submit(f, {action: submitSpy});
@@ -319,7 +319,7 @@ describe('submit', () => {
319319
const f = form(data, {injector});
320320
expect(f.a.b().submitting()).toBe(false);
321321

322-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
322+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
323323
const result = submit(f, {action: () => promise});
324324
expect(f.a.b().submitting()).toBe(true);
325325

@@ -383,7 +383,7 @@ describe('submit', () => {
383383
const f = form(signal(0), {injector});
384384
expect(f().submitting()).toBe(false);
385385

386-
const {promise, reject} = promiseWithResolvers<ValidationError[]>();
386+
const {promise, reject} = Promise.withResolvers<ValidationError[]>();
387387
const submitPromise = submit(f, {action: () => promise});
388388
expect(f().submitting()).toBe(true);
389389

@@ -540,7 +540,7 @@ describe('submit', () => {
540540

541541
it('fails with pending validators with ignoreValidators: none', async () => {
542542
const data = signal('');
543-
const resolvers = promiseWithResolvers();
543+
const resolvers = Promise.withResolvers();
544544
const f = form(
545545
data,
546546
(p) => {
@@ -642,24 +642,3 @@ describe('submit', () => {
642642
expect(submitSpy).toHaveBeenCalledWith({name: 'Alice'}, {name: 'Alice'}, 'Alice');
643643
});
644644
});
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: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,7 +1645,7 @@ describe('field directive', () => {
16451645

16461646
describe('pending', () => {
16471647
it('should bind to custom control', async () => {
1648-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
1648+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
16491649

16501650
@Component({
16511651
selector: 'custom-control',
@@ -1690,7 +1690,7 @@ describe('field directive', () => {
16901690
});
16911691

16921692
it('should bind to a custom control when composed as a host directive', async () => {
1693-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
1693+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
16941694

16951695
@Component({
16961696
selector: 'custom-control',
@@ -1736,7 +1736,7 @@ describe('field directive', () => {
17361736
});
17371737

17381738
it('should be reset when field changes on custom control', async () => {
1739-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
1739+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
17401740

17411741
@Component({selector: 'custom-control', template: ``})
17421742
class CustomControl implements FormValueControl<string> {
@@ -1780,7 +1780,7 @@ describe('field directive', () => {
17801780
});
17811781

17821782
it('should bind to directive input on native control', async () => {
1783-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
1783+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
17841784

17851785
@Directive({selector: '[testDir]'})
17861786
class TestDir {
@@ -1818,7 +1818,7 @@ describe('field directive', () => {
18181818
});
18191819

18201820
it('should bind to directive input on custom control', async () => {
1821-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
1821+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
18221822

18231823
@Directive({selector: '[testDir]'})
18241824
class TestDir {
@@ -5032,7 +5032,7 @@ describe('field directive', () => {
50325032
});
50335033

50345034
it('should synchronize pending status', async () => {
5035-
const {promise, resolve} = promiseWithResolvers<ValidationError[]>();
5035+
const {promise, resolve} = Promise.withResolvers<ValidationError[]>();
50365036

50375037
@Component({
50385038
selector: 'my-input',
@@ -5927,7 +5927,7 @@ describe('field directive', () => {
59275927

59285928
describe('debounce', () => {
59295929
it('should support native control', async () => {
5930-
const {promise, resolve} = promiseWithResolvers<void>();
5930+
const {promise, resolve} = Promise.withResolvers<void>();
59315931

59325932
@Component({
59335933
imports: [FormField],
@@ -5954,7 +5954,7 @@ describe('field directive', () => {
59545954
});
59555955

59565956
it('should support custom control', async () => {
5957-
const {promise, resolve} = promiseWithResolvers<void>();
5957+
const {promise, resolve} = Promise.withResolvers<void>();
59585958

59595959
@Component({
59605960
selector: 'my-input',
@@ -5986,7 +5986,7 @@ describe('field directive', () => {
59865986
});
59875987

59885988
it('should reset control when debounced update is reset', async () => {
5989-
const {promise, resolve} = promiseWithResolvers<void>();
5989+
const {promise, resolve} = Promise.withResolvers<void>();
59905990

59915991
@Component({
59925992
imports: [FormField],
@@ -6024,7 +6024,7 @@ describe('field directive', () => {
60246024
});
60256025

60266026
it('should reset child control when debounced update is reset at root', async () => {
6027-
const {promise, resolve} = promiseWithResolvers<void>();
6027+
const {promise, resolve} = Promise.withResolvers<void>();
60286028

60296029
@Component({
60306030
imports: [FormField],
@@ -6218,7 +6218,7 @@ describe('field directive', () => {
62186218
});
62196219

62206220
it('should create & bind input when a macro task is running', async () => {
6221-
const {promise, resolve} = promiseWithResolvers<void>();
6221+
const {promise, resolve} = Promise.withResolvers<void>();
62226222

62236223
@Component({
62246224
selector: 'app-form',
@@ -6490,25 +6490,3 @@ function act<T>(fn: () => T): T {
64906490
TestBed.tick();
64916491
}
64926492
}
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-
}

0 commit comments

Comments
 (0)