Skip to content

Commit e60b800

Browse files
committed
refactor: Remove zonejs-related wrappers
1 parent 2a1c0da commit e60b800

9 files changed

Lines changed: 93 additions & 269 deletions

File tree

angular/headless/angular.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
"builder": "@angular/build:unit-test",
2020
"options": {
2121
"include": ["src/**/*.spec.ts"],
22-
"providersFile": "test-providers.ts",
23-
"setupFiles": ["setup-test.ts"],
2422
"buildTarget": ":build",
2523
"browsers": ["ChromiumHeadless"]
2624
},

angular/headless/setup-test.ts

Lines changed: 0 additions & 2 deletions
This file was deleted.

angular/headless/src/utils/stores.spec.ts

Lines changed: 22 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,10 @@
11
import {readable, writable} from '@amadeus-it-group/tansu';
2-
import {ChangeDetectionStrategy, Component, NgZone, effect} from '@angular/core';
2+
import {ChangeDetectionStrategy, Component, effect} from '@angular/core';
33
import {TestBed} from '@angular/core/testing';
4-
import {beforeEach, describe, expect, it} from 'vitest';
4+
import {describe, expect, it} from 'vitest';
55
import {toAngularSignal, toAngularWritableSignal} from './stores';
66

77
describe('toAngularSignals', () => {
8-
let log: string[] = [];
9-
10-
beforeEach(() => {
11-
log = [];
12-
});
13-
14-
const createZoneCheckFn =
15-
<T extends any[], R>(name: string, fn: (...args: T) => R) =>
16-
(...args: T): R => {
17-
log.push(`begin ${name}, ngZone = ${NgZone.isInAngularZone()}`);
18-
try {
19-
return fn(...args);
20-
} finally {
21-
log.push(`end ${name}, ngZone = ${NgZone.isInAngularZone()}`);
22-
}
23-
};
24-
258
it('[toAngularSignal] works synchronously', () => {
269
const tansuStore = writable(1);
2710
const signal = TestBed.runInInjectionContext(() => toAngularSignal(tansuStore));
@@ -33,51 +16,38 @@ describe('toAngularSignals', () => {
3316
expect(signal()).toBe(2); // no change as the subscription was ended
3417
});
3518

19+
it('[toAngularSignal] subscribes and unsubscribes', () => {
20+
const log: string[] = [];
21+
const tansuStore = readable(0 as number, {
22+
onUse: (set) => {
23+
log.push('onUse');
24+
set(1);
25+
return () => {
26+
log.push('destroy');
27+
};
28+
},
29+
});
30+
const signal = TestBed.runInInjectionContext(() => toAngularSignal(tansuStore));
31+
expect(signal()).toBe(1);
32+
TestBed.resetTestingModule();
33+
expect(log).toStrictEqual(['onUse', 'destroy']);
34+
});
35+
3636
it('[toAngularWritableSignal] works synchronously', () => {
3737
const tansuStore = writable(1);
3838
const signal = TestBed.runInInjectionContext(() => toAngularWritableSignal(tansuStore));
3939
expect(signal()).toBe(1);
4040
tansuStore.set(2);
4141
expect(signal()).toBe(2);
42-
const ngZone = TestBed.inject(NgZone);
43-
ngZone.run(() => {
44-
signal.set(3);
45-
});
42+
signal.set(3);
4643
expect(tansuStore.get()).toBe(3);
47-
ngZone.run(() => {
48-
signal.set(4);
49-
});
44+
signal.set(4);
5045
expect(tansuStore.get()).toBe(4);
5146
TestBed.resetTestingModule(); // this ends the subscription
5247
tansuStore.set(5);
5348
expect(signal()).toBe(4); // no change as the subscription was ended
5449
});
5550

56-
it('[toAngularSignal] subscribes and unsubscribes outside Angular zone', () => {
57-
const ngZone = TestBed.inject(NgZone);
58-
const tansuStore = readable(0 as number, {
59-
onUse: createZoneCheckFn('onUse', (set) => {
60-
set(1);
61-
return createZoneCheckFn('destroy', () => {});
62-
}),
63-
});
64-
ngZone.run(
65-
createZoneCheckFn('ngZone.run', () => {
66-
const signal = TestBed.runInInjectionContext(() => toAngularSignal(tansuStore));
67-
expect(signal()).toBe(1);
68-
TestBed.resetTestingModule();
69-
}),
70-
);
71-
expect(log).toStrictEqual([
72-
'begin ngZone.run, ngZone = true',
73-
'begin onUse, ngZone = false',
74-
'end onUse, ngZone = false',
75-
'begin destroy, ngZone = false',
76-
'end destroy, ngZone = false',
77-
'end ngZone.run, ngZone = true',
78-
]);
79-
});
80-
8151
@Component({
8252
selector: '[auMyTestWithoutEffect]',
8353
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -107,50 +77,19 @@ describe('toAngularSignals', () => {
10777
}
10878

10979
for (const MyComponent of [MyTestWithEffectComponent, MyTestWithoutEffectComponent]) {
110-
it(`[toAngularSignal] works in ${MyComponent.name} (inside Angular zone)`, async () => {
111-
TestBed.configureTestingModule({
112-
imports: [MyComponent],
113-
});
114-
const fixture = TestBed.createComponent(MyComponent);
115-
fixture.autoDetectChanges();
116-
await fixture.whenStable();
117-
expect(fixture.nativeElement.textContent).toBe('1');
118-
if (MyComponent === MyTestWithEffectComponent) {
119-
// eslint-disable-next-line vitest/no-conditional-expect
120-
expect(fixture.componentInstance.changes).toStrictEqual([1]);
121-
}
122-
const zone = TestBed.inject(NgZone);
123-
expect(NgZone.isInAngularZone()).toBeFalsy();
124-
zone.run(() => {
125-
expect(NgZone.isInAngularZone()).toBeTruthy();
126-
fixture.componentInstance.myStore.set(2);
127-
fixture.componentInstance.myStore.set(3);
128-
});
129-
await fixture.whenStable();
130-
expect(fixture.nativeElement.textContent).toBe('3');
131-
if (MyComponent === MyTestWithEffectComponent) {
132-
// eslint-disable-next-line vitest/no-conditional-expect
133-
expect(fixture.componentInstance.changes).toStrictEqual([1, 3]);
134-
}
135-
fixture.destroy();
136-
});
137-
138-
it(`[toAngularSignal] works in ${MyComponent.name} (outside Angular zone)`, async () => {
80+
it(`[toAngularSignal] works in ${MyComponent.name}`, async () => {
13981
const fixture = TestBed.createComponent(MyComponent);
14082
fixture.autoDetectChanges();
14183
await fixture.whenStable();
14284
expect(fixture.nativeElement.textContent).toBe('1');
14385
if (MyComponent === MyTestWithEffectComponent) {
144-
// eslint-disable-next-line vitest/no-conditional-expect
14586
expect(fixture.componentInstance.changes).toStrictEqual([1]);
14687
}
147-
expect(NgZone.isInAngularZone()).toBeFalsy();
14888
fixture.componentInstance.myStore.set(2);
14989
fixture.componentInstance.myStore.set(3);
15090
await fixture.whenStable();
15191
expect(fixture.nativeElement.textContent).toBe('3');
15292
if (MyComponent === MyTestWithEffectComponent) {
153-
// eslint-disable-next-line vitest/no-conditional-expect
15493
expect(fixture.componentInstance.changes).toStrictEqual([1, 3]);
15594
}
15695
fixture.destroy();
Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,53 @@
11
import type {ReadableSignal, WritableSignal as TansuWritableSignal} from '@amadeus-it-group/tansu';
22
import type {Signal, WritableSignal} from '@angular/core';
33
import {DestroyRef, inject, signal} from '@angular/core';
4-
import {ZoneWrapper} from './zone';
54

65
export * from '@agnos-ui/core/utils/stores';
76

87
/**
98
* Converts a Tansu `ReadableSignal` to an Angular `Signal`.
109
*
11-
* This function wraps the provided Tansu signal in an Angular signal, ensuring that updates
12-
* are properly handled within Angular's zone. It subscribes to the Tansu signal and updates
13-
* the Angular signal with the received values. The equality function for the Angular signal
14-
* is set to always return false, ensuring that every new value from the Tansu signal triggers
15-
* an update.
10+
* This function wraps the provided Tansu signal in an Angular signal. It subscribes to the
11+
* Tansu signal and updates the Angular signal with the received values. The equality function
12+
* for the Angular signal is set to always return false, ensuring that every new value from the
13+
* Tansu signal triggers an update.
1614
*
1715
* @template T - The type of the value emitted by the signals.
1816
* @param tansuSignal - The Tansu signal to convert.
1917
* @returns - The resulting Angular signal.
2018
*/
2119
export const toAngularSignal = <T>(tansuSignal: ReadableSignal<T>): Signal<T> => {
22-
const zoneWrapper = inject(ZoneWrapper);
2320
// The equality of objects from 2 sequential emissions is already checked in tansu signal.
2421
// Here we'll always emit the value received from tansu signal, therefor the equality function
2522
const res = signal(undefined as any as T, {equal: () => false});
26-
const subscription = zoneWrapper.outsideNgZone(tansuSignal.subscribe)((value) => {
23+
const subscription = tansuSignal.subscribe((value) => {
2724
res.set(value);
28-
zoneWrapper.planNgZoneRun();
2925
});
30-
inject(DestroyRef).onDestroy(zoneWrapper.outsideNgZone(subscription));
26+
inject(DestroyRef).onDestroy(subscription);
3127

3228
return res.asReadonly();
3329
};
3430

3531
/**
3632
* Converts a Tansu `WritableSignal` to an Angular `WritableSignal`.
3733
*
38-
* This function wraps the provided Tansu signal in an Angular signal, ensuring that updates
39-
* are properly handled within Angular's zone. It subscribes to the Tansu signal and updates
40-
* the Angular signal with the received values. The equality function for the Angular signal
41-
* is set to always return false, ensuring that every new value from the Tansu signal triggers
42-
* an update.
34+
* This function wraps the provided Tansu signal in an Angular signal. It subscribes to the
35+
* Tansu signal and updates the Angular signal with the received values. The equality function
36+
* for the Angular signal is set to always return false, ensuring that every new value from the
37+
* Tansu signal triggers an update.
4338
*
4439
* @template T - The type of the value emitted by the signals.
4540
* @param tansuSignal - The Tansu signal to convert.
4641
* @returns - The resulting Angular signal.
4742
*/
4843
export const toAngularWritableSignal = <T>(tansuSignal: TansuWritableSignal<T>): WritableSignal<T> => {
49-
const zoneWrapper = inject(ZoneWrapper);
5044
const res = signal(undefined as any as T, {equal: () => false});
5145
const set = res.set.bind(res);
52-
const subscription = zoneWrapper.outsideNgZone(tansuSignal.subscribe)((value) => {
46+
const subscription = tansuSignal.subscribe((value) => {
5347
set(value);
54-
zoneWrapper.planNgZoneRun();
5548
});
56-
inject(DestroyRef).onDestroy(zoneWrapper.outsideNgZone(subscription));
57-
res.set = zoneWrapper.outsideNgZone(tansuSignal.set);
58-
res.update = zoneWrapper.outsideNgZone(tansuSignal.update);
49+
inject(DestroyRef).onDestroy(subscription);
50+
res.set = tansuSignal.set;
51+
res.update = tansuSignal.update;
5952
return res;
6053
};

0 commit comments

Comments
 (0)