mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(core): use native Promise.withResolvers() in remaining tests
Replaces the remaining hand-rolled deferred promise implementations with the native `Promise.withResolvers()` API and removes the now unused helper and import. Follow-up to #69739.
This commit is contained in:
committed by
Kristiyan Kostadinov
parent
49a797f510
commit
1bc7e3c2c3
@@ -767,15 +767,12 @@ describe('FetchBackend', () => {
|
||||
export class MockFetchFactory extends FetchFactory {
|
||||
public readonly response = new MockFetchResponse();
|
||||
public readonly request = new MockFetchRequest();
|
||||
private resolve!: Function;
|
||||
private reject!: Function;
|
||||
private resolve!: (value: Response | PromiseLike<Response>) => void;
|
||||
private reject!: (reason?: any) => void;
|
||||
|
||||
private clearWarningTimeout?: VoidFunction;
|
||||
|
||||
private promise = new Promise<Response>((resolve, reject) => {
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
});
|
||||
private promise = this.createFetchPromise();
|
||||
|
||||
override fetch = (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
|
||||
this.request.method = init?.method;
|
||||
@@ -849,10 +846,14 @@ export class MockFetchFactory extends FetchFactory {
|
||||
}
|
||||
|
||||
resetFetchPromise() {
|
||||
this.promise = new Promise<Response>((resolve, reject) => {
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
});
|
||||
this.promise = this.createFetchPromise();
|
||||
}
|
||||
|
||||
private createFetchPromise(): Promise<Response> {
|
||||
const {promise, resolve, reject} = Promise.withResolvers<Response>();
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,10 +178,7 @@ describe('AsyncPipe', () => {
|
||||
let promise: Promise<any>;
|
||||
|
||||
beforeEach(() => {
|
||||
promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
({promise, resolve, reject} = Promise.withResolvers<any>());
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
|
||||
@@ -1523,9 +1523,7 @@ describe('change detection', () => {
|
||||
private resolve?: Function;
|
||||
changeDetectorRef = inject(ChangeDetectorRef);
|
||||
createReadPromise() {
|
||||
this.promise = new Promise<void>((resolve) => {
|
||||
this.resolve = resolve;
|
||||
});
|
||||
({promise: this.promise, resolve: this.resolve} = Promise.withResolvers<void>());
|
||||
}
|
||||
resolveReadPromise() {
|
||||
this.resolve?.();
|
||||
|
||||
@@ -88,14 +88,10 @@ describe('public PendingTasks', () => {
|
||||
const appRef = TestBed.inject(ApplicationRef);
|
||||
const pendingTasks = TestBed.inject(PendingTasks);
|
||||
|
||||
let resolveFn: () => void;
|
||||
pendingTasks.run(() => {
|
||||
return new Promise<void>((r) => {
|
||||
resolveFn = r;
|
||||
});
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<void>();
|
||||
pendingTasks.run(() => promise);
|
||||
await expectAsync(applicationRefIsStable(appRef)).toBeResolvedTo(false);
|
||||
resolveFn!();
|
||||
resolve();
|
||||
await expectAsync(TestBed.inject(ApplicationRef).whenStable()).toBeResolved();
|
||||
});
|
||||
|
||||
@@ -105,14 +101,10 @@ describe('public PendingTasks', () => {
|
||||
const errorHandler = TestBed.inject(ErrorHandler);
|
||||
const spy = spyOn(errorHandler, 'handleError');
|
||||
|
||||
let rejectFn: () => void;
|
||||
pendingTasks.run(() => {
|
||||
return new Promise<void>((_, reject) => {
|
||||
rejectFn = reject;
|
||||
});
|
||||
});
|
||||
const {promise, reject} = Promise.withResolvers<void>();
|
||||
pendingTasks.run(() => promise);
|
||||
await expectAsync(applicationRefIsStable(appRef)).toBeResolvedTo(false);
|
||||
rejectFn!();
|
||||
reject();
|
||||
await expectAsync(appRef.whenStable()).toBeResolved();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -50,10 +50,7 @@ describe('ApplicationInitStatus', () => {
|
||||
let initFnInvoked = false;
|
||||
|
||||
beforeEach(() => {
|
||||
promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
({promise, resolve, reject} = Promise.withResolvers<any>());
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{provide: APP_INITIALIZER, useValue: [() => promise]}],
|
||||
});
|
||||
|
||||
@@ -466,10 +466,7 @@ describe('bootstrap', () => {
|
||||
}));
|
||||
|
||||
it('should wait for asynchronous app initializers', waitForAsync(async () => {
|
||||
let resolve: (result: any) => void;
|
||||
const promise: Promise<any> = new Promise((res) => {
|
||||
resolve = res;
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<any>();
|
||||
let initializerDone = false;
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
@@ -643,10 +640,7 @@ describe('bootstrap', () => {
|
||||
defaultPlatform = _platform;
|
||||
}));
|
||||
it('should wait for asynchronous app initializers', waitForAsync(async () => {
|
||||
let resolve: (result: any) => void;
|
||||
const promise: Promise<any> = new Promise((res) => {
|
||||
resolve = res;
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<any>();
|
||||
let initializerDone = false;
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
|
||||
@@ -469,10 +469,7 @@ describe('Angular with zoneless enabled', () => {
|
||||
});
|
||||
|
||||
it('executes render hooks when a new one is registered', async () => {
|
||||
let resolveFn: Function;
|
||||
let calledPromise = new Promise((resolve) => {
|
||||
resolveFn = resolve;
|
||||
});
|
||||
const {promise: calledPromise, resolve: resolveFn} = Promise.withResolvers<void>();
|
||||
TestBed.runInInjectionContext(() => {
|
||||
afterNextRender(() => {
|
||||
resolveFn();
|
||||
@@ -496,10 +493,7 @@ describe('Angular with zoneless enabled', () => {
|
||||
await fixture.whenStable();
|
||||
expect(checks).toBe(1);
|
||||
|
||||
let resolveFn: Function;
|
||||
let calledPromise = new Promise((resolve) => {
|
||||
resolveFn = resolve;
|
||||
});
|
||||
const {promise: calledPromise, resolve: resolveFn} = Promise.withResolvers<void>();
|
||||
TestBed.runInInjectionContext(() => {
|
||||
afterNextRender(() => {
|
||||
resolveFn();
|
||||
|
||||
@@ -62,10 +62,7 @@ describe('injectAsync', () => {
|
||||
});
|
||||
|
||||
await TestBed.runInInjectionContext(async () => {
|
||||
let prefetchResolve!: () => void;
|
||||
const prefetchPromise = new Promise<void>((resolve) => {
|
||||
prefetchResolve = resolve;
|
||||
});
|
||||
const {promise: prefetchPromise, resolve: prefetchResolve} = Promise.withResolvers<void>();
|
||||
|
||||
let prefetchCalled = false;
|
||||
const loader = () => {
|
||||
|
||||
@@ -2422,13 +2422,11 @@ class PushCmpWithHostEvent {
|
||||
})
|
||||
class PushCmpWithAsyncPipe {
|
||||
numberOfChecks: number = 0;
|
||||
resolve!: (result: any) => void;
|
||||
resolve: (result: any) => void;
|
||||
promise: Promise<any>;
|
||||
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve) => {
|
||||
this.resolve = resolve;
|
||||
});
|
||||
({promise: this.promise, resolve: this.resolve} = Promise.withResolvers<any>());
|
||||
}
|
||||
|
||||
get field() {
|
||||
|
||||
@@ -103,17 +103,16 @@ export class MockResourceLoader extends ResourceLoader {
|
||||
}
|
||||
|
||||
class _PendingRequest {
|
||||
// Using non null assertion, these fields are defined below
|
||||
// within the `new Promise` callback (synchronously).
|
||||
resolve!: (result: string) => void;
|
||||
reject!: (error: any) => void;
|
||||
resolve: (result: string) => void;
|
||||
reject: (error: any) => void;
|
||||
promise: Promise<string>;
|
||||
|
||||
constructor(public url: string) {
|
||||
this.promise = new Promise((res, rej) => {
|
||||
this.resolve = res;
|
||||
this.reject = rej;
|
||||
});
|
||||
({
|
||||
promise: this.promise,
|
||||
resolve: this.resolve,
|
||||
reject: this.reject,
|
||||
} = Promise.withResolvers<string>());
|
||||
}
|
||||
|
||||
complete(response: string | null) {
|
||||
|
||||
@@ -142,11 +142,12 @@ describe('debounced', () => {
|
||||
|
||||
const res = debounced(
|
||||
source,
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
calls++;
|
||||
release = resolve;
|
||||
}),
|
||||
() => {
|
||||
calls++;
|
||||
const {promise, resolve} = Promise.withResolvers<void>();
|
||||
release = resolve;
|
||||
return promise;
|
||||
},
|
||||
{injector},
|
||||
);
|
||||
|
||||
@@ -198,12 +199,13 @@ describe('debounced', () => {
|
||||
|
||||
const res = debounced(
|
||||
source,
|
||||
(val: string) =>
|
||||
new Promise<void>((resolve) => {
|
||||
if (val === 'initial') releaseInitial = resolve;
|
||||
if (val === 'update1') release1 = resolve;
|
||||
if (val === 'update2') release2 = resolve;
|
||||
}),
|
||||
(val: string) => {
|
||||
const {promise, resolve} = Promise.withResolvers<void>();
|
||||
if (val === 'initial') releaseInitial = resolve;
|
||||
if (val === 'update1') release1 = resolve;
|
||||
if (val === 'update2') release2 = resolve;
|
||||
return promise;
|
||||
},
|
||||
{injector},
|
||||
);
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
signal,
|
||||
TransferState,
|
||||
} from '../../src/core';
|
||||
import {promiseWithResolvers} from '../../src/util/promise_with_resolvers';
|
||||
import {TestBed} from '../../testing';
|
||||
|
||||
abstract class MockBackend<T, R> {
|
||||
@@ -344,7 +343,7 @@ describe('resource', () => {
|
||||
const res = resource({
|
||||
params: request,
|
||||
loader: async ({params}) => {
|
||||
const p = promiseWithResolvers<number>();
|
||||
const p = Promise.withResolvers<number>();
|
||||
resolve.push(() => p.resolve(params));
|
||||
return p.promise;
|
||||
},
|
||||
|
||||
@@ -90,10 +90,7 @@ describe('NgZone', () => {
|
||||
|
||||
it('should produce long stack traces', (done) => {
|
||||
macroTask(() => {
|
||||
let resolve: (result: any) => void;
|
||||
const promise: Promise<any> = new Promise((res) => {
|
||||
resolve = res;
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<any>();
|
||||
|
||||
_zone.run(() => {
|
||||
setTimeout(() => {
|
||||
@@ -114,10 +111,7 @@ describe('NgZone', () => {
|
||||
|
||||
it('should produce long stack traces (when using microtasks)', (done) => {
|
||||
macroTask(() => {
|
||||
let resolve: (result: any) => void;
|
||||
const promise: Promise<any> = new Promise((res) => {
|
||||
resolve = res;
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<any>();
|
||||
|
||||
_zone.run(() => {
|
||||
queueMicrotask(() => {
|
||||
@@ -150,10 +144,7 @@ describe('NgZone', () => {
|
||||
|
||||
it('should disable long stack traces', (done) => {
|
||||
macroTask(() => {
|
||||
let resolve: (result: any) => void;
|
||||
const promise: Promise<any> = new Promise((res) => {
|
||||
resolve = res;
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<any>();
|
||||
|
||||
_zone.run(() => {
|
||||
setTimeout(() => {
|
||||
@@ -524,12 +515,8 @@ function commonTests() {
|
||||
|
||||
runNgZoneNoLog(() => {
|
||||
macroTask(() => {
|
||||
aPromise = new Promise((res) => {
|
||||
aResolve = res;
|
||||
});
|
||||
bPromise = new Promise((res) => {
|
||||
bResolve = res;
|
||||
});
|
||||
({promise: aPromise, resolve: aResolve} = Promise.withResolvers<string>());
|
||||
({promise: bPromise, resolve: bResolve} = Promise.withResolvers<string>());
|
||||
|
||||
_log.add('run start');
|
||||
aPromise.then(_log.fn('a then'));
|
||||
@@ -569,9 +556,7 @@ function commonTests() {
|
||||
|
||||
macroTask(() => {
|
||||
NgZone.assertNotInAngularZone();
|
||||
promise = new Promise<string | null>((res) => {
|
||||
resolve = res;
|
||||
});
|
||||
({promise, resolve} = Promise.withResolvers<string | null>());
|
||||
});
|
||||
|
||||
runNgZoneNoLog(() => {
|
||||
@@ -748,12 +733,8 @@ function commonTests() {
|
||||
|
||||
runNgZoneNoLog(() => {
|
||||
macroTask(() => {
|
||||
aPromise = new Promise<string | null>((res) => {
|
||||
aResolve = res;
|
||||
});
|
||||
bPromise = new Promise<string | null>((res) => {
|
||||
bResolve = res;
|
||||
});
|
||||
({promise: aPromise, resolve: aResolve} = Promise.withResolvers<string | null>());
|
||||
({promise: bPromise, resolve: bResolve} = Promise.withResolvers<string | null>());
|
||||
aPromise.then(_log.fn('a then'));
|
||||
bPromise.then(_log.fn('b then'));
|
||||
_log.add('run start');
|
||||
|
||||
@@ -1570,10 +1570,7 @@ describe('FieldNode', () => {
|
||||
});
|
||||
|
||||
it('should immediately update value on reset even if a debounce is pending', async () => {
|
||||
let resolveDebounce: (value: void | PromiseLike<void>) => void;
|
||||
const debouncePromise = new Promise<void>((resolve) => {
|
||||
resolveDebounce = resolve;
|
||||
});
|
||||
const {promise: debouncePromise, resolve: resolveDebounce} = Promise.withResolvers<void>();
|
||||
|
||||
const model = signal('initial');
|
||||
const f = form(
|
||||
@@ -1598,7 +1595,7 @@ describe('FieldNode', () => {
|
||||
expect(f().controlValue()).toBe('reset value');
|
||||
|
||||
// 3. Resolve the debounce
|
||||
resolveDebounce!();
|
||||
resolveDebounce();
|
||||
await Promise.resolve(); // Wait for promise microtasks
|
||||
|
||||
// Value should STILL be 'reset value', not 'user input'
|
||||
@@ -1635,10 +1632,7 @@ describe('FieldNode', () => {
|
||||
});
|
||||
|
||||
it('should abort pending debounce on reset without value and not trigger further sync', async () => {
|
||||
let resolveDebounce: (value: void | PromiseLike<void>) => void;
|
||||
const debouncePromise = new Promise<void>((resolve) => {
|
||||
resolveDebounce = resolve;
|
||||
});
|
||||
const {promise: debouncePromise, resolve: resolveDebounce} = Promise.withResolvers<void>();
|
||||
|
||||
const model = signal('initial');
|
||||
const f = form(
|
||||
@@ -1664,7 +1658,7 @@ describe('FieldNode', () => {
|
||||
expect(f().controlValue()).toBe('initial');
|
||||
|
||||
// 3. Resolve the debounce
|
||||
resolveDebounce!();
|
||||
resolveDebounce();
|
||||
await Promise.resolve(); // Wait for promise microtasks
|
||||
|
||||
// value.set should NEVER have been called during or after reset
|
||||
@@ -1673,10 +1667,7 @@ describe('FieldNode', () => {
|
||||
});
|
||||
|
||||
it('should abort pending debounce on reset with new value and only call value.set once immediately', async () => {
|
||||
let resolveDebounce: (value: void | PromiseLike<void>) => void;
|
||||
const debouncePromise = new Promise<void>((resolve) => {
|
||||
resolveDebounce = resolve;
|
||||
});
|
||||
const {promise: debouncePromise, resolve: resolveDebounce} = Promise.withResolvers<void>();
|
||||
|
||||
const model = signal('initial');
|
||||
const f = form(
|
||||
@@ -1704,7 +1695,7 @@ describe('FieldNode', () => {
|
||||
expect(f().value.set).toHaveBeenCalledWith('reset value');
|
||||
|
||||
// 3. Resolve the debounce
|
||||
resolveDebounce!();
|
||||
resolveDebounce();
|
||||
await Promise.resolve(); // Wait for promise microtasks
|
||||
|
||||
// value.set should STILL have only been called once (the immediate one)
|
||||
|
||||
@@ -69,10 +69,7 @@ describe('Signal Forms array removal orphan repro', () => {
|
||||
}
|
||||
});
|
||||
it('should handle debounceSync resolving after the field is orphaned', async () => {
|
||||
let resolveDebounce!: () => void;
|
||||
const debouncePromise = new Promise<void>((r) => {
|
||||
resolveDebounce = r;
|
||||
});
|
||||
const {promise: debouncePromise, resolve: resolveDebounce} = Promise.withResolvers<void>();
|
||||
|
||||
@Component({
|
||||
imports: [FormField],
|
||||
|
||||
@@ -6300,10 +6300,7 @@ function asyncValidator(
|
||||
},
|
||||
) {
|
||||
return (c: AbstractControl) => {
|
||||
let resolve: (result: any) => void;
|
||||
const promise = new Promise<any>((res) => {
|
||||
resolve = res;
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<any>();
|
||||
const res = checker(c) ? null : error;
|
||||
setTimeout(() => resolve(res), timeout);
|
||||
return promise;
|
||||
|
||||
@@ -924,12 +924,7 @@ describe('public testing API', () => {
|
||||
let originalJasmineIt: (description: string, func: () => void) => jasmine.Spec;
|
||||
|
||||
const patchJasmineIt = () => {
|
||||
let resolve: (result: any) => void;
|
||||
let reject: (error: any) => void;
|
||||
const promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
const {promise, resolve, reject} = Promise.withResolvers<any>();
|
||||
const jasmineEnv = jasmine.getEnv() as any;
|
||||
originalJasmineIt = jasmineEnv.it;
|
||||
jasmineEnv.it = (description: string, fn: (done: DoneFn) => void): any => {
|
||||
|
||||
@@ -90,7 +90,7 @@ describe('bootstrap', () => {
|
||||
doc.body.appendChild(el1);
|
||||
doc.body.appendChild(el2);
|
||||
|
||||
const {promise, resolveFn} = createPromise();
|
||||
const {promise, resolve: resolveFn} = Promise.withResolvers<void>();
|
||||
navigationEndPromise = promise;
|
||||
log = [];
|
||||
testProviders = [
|
||||
@@ -455,7 +455,7 @@ describe('bootstrap', () => {
|
||||
spyOn(router as any, 'resetRootComponentType').and.callThrough();
|
||||
|
||||
const appRef: ApplicationRef = res.injector.get(ApplicationRef);
|
||||
const {promise, resolveFn} = createPromise();
|
||||
const {promise, resolve: resolveFn} = Promise.withResolvers<void>();
|
||||
appRef.components[0].onDestroy(() => {
|
||||
appRef.bootstrap(SecondRootCmp);
|
||||
expect((router as any).resetRootComponentType).toHaveBeenCalled();
|
||||
@@ -629,11 +629,3 @@ function provideNavigationEndAction(fn: Function) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createPromise() {
|
||||
let resolveFn: () => void;
|
||||
const promise = new Promise<void>((r) => {
|
||||
resolveFn = r;
|
||||
});
|
||||
return {resolveFn: () => resolveFn(), promise};
|
||||
}
|
||||
|
||||
@@ -94,9 +94,9 @@ describe('routerResource behavior tests', () => {
|
||||
resolveImmediately = false;
|
||||
return Promise.resolve('initial');
|
||||
}
|
||||
return new Promise<string>((resolve) => {
|
||||
resolveLoader = resolve;
|
||||
});
|
||||
const {promise, resolve} = Promise.withResolvers<string>();
|
||||
resolveLoader = resolve;
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user