@symbiote-native/localization 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/build/angular/index.js +3 -3
- package/build/angular/services/calendars.service/index.js +1 -1
- package/build/angular/services/locales.service/index.js +1 -1
- package/build/core/index.js +3 -3
- package/build/core/localization.js +1 -1
- package/build/react/hooks/use-calendars/index.js +1 -1
- package/build/react/hooks/use-locales/index.js +1 -1
- package/build/react/index.js +3 -3
- package/build/vue/composables/use-calendars/index.js +1 -1
- package/build/vue/composables/use-locales/index.js +1 -1
- package/build/vue/index.js +3 -3
- package/package.json +9 -6
- package/src/angular/services/calendars.service/calendars.service.test.ts +0 -102
- package/src/angular/services/locales.service/locales.service.test.ts +0 -122
- package/src/core/localization.test.ts +0 -64
- package/src/react/hooks/use-calendars/use-calendars.test.tsx +0 -87
- package/src/react/hooks/use-locales/use-locales.test.tsx +0 -107
- package/src/vue/composables/use-calendars/use-calendars.test.ts +0 -96
- package/src/vue/composables/use-locales/use-locales.test.ts +0 -116
package/README.md
CHANGED
|
@@ -38,8 +38,8 @@ package (`@symbiote-native/battery`, `@symbiote-native/device`, ...) with zero f
|
|
|
38
38
|
|
|
39
39
|
Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
|
|
40
40
|
peer-dependency exclusion list — live in the `symbiote-expo-native-module` skill. Reference
|
|
41
|
-
implementation:
|
|
42
|
-
|
|
41
|
+
implementation: `examples/expo-react/ios/Podfile` and
|
|
42
|
+
`examples/expo-react/android/app/src/main/java/com/canaryexpo/MainApplication.kt`.
|
|
43
43
|
|
|
44
44
|
No platform permission string is needed — locale and calendar settings are read-only system
|
|
45
45
|
state with no runtime permission prompt on either platform.
|
package/build/angular/index.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// event subscription plumbing all live in core, shared with React/Vue. Two separate services
|
|
3
3
|
// (not one combined service), matching upstream's own useLocales/useCalendars being two separate
|
|
4
4
|
// hooks.
|
|
5
|
-
export { LocalesService } from './services/locales.service';
|
|
6
|
-
export { CalendarsService } from './services/calendars.service';
|
|
7
|
-
export { getLocales, getCalendars, addLocaleListener, addCalendarListener, Weekday, CalendarIdentifier, } from '../core';
|
|
5
|
+
export { LocalesService } from './services/locales.service/index.js';
|
|
6
|
+
export { CalendarsService } from './services/calendars.service/index.js';
|
|
7
|
+
export { getLocales, getCalendars, addLocaleListener, addCalendarListener, Weekday, CalendarIdentifier, } from '../core/index.js';
|
|
@@ -33,7 +33,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
35
|
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
36
|
-
import { addCalendarListener, getCalendars } from '../../../core';
|
|
36
|
+
import { addCalendarListener, getCalendars } from '../../../core/index.js';
|
|
37
37
|
// Angular twin of React's `useCalendars` hook and Vue's `useCalendars` composable — mirrors
|
|
38
38
|
// LocalesService's shape exactly.
|
|
39
39
|
//
|
|
@@ -33,7 +33,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
35
|
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
36
|
-
import { addLocaleListener, getLocales } from '../../../core';
|
|
36
|
+
import { addLocaleListener, getLocales } from '../../../core/index.js';
|
|
37
37
|
// Angular twin of React's `useLocales` hook and Vue's `useLocales` composable. See
|
|
38
38
|
// packages/battery's BatteryStateService for the `connect()` pattern rationale. getLocales() is
|
|
39
39
|
// synchronous, so the signal seeds from it directly rather than an async `.then()` fetch.
|
package/build/core/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { getLocales, getCalendars } from './localization';
|
|
2
|
-
export { addLocaleListener, addCalendarListener } from './native-module';
|
|
3
|
-
export { Weekday, CalendarIdentifier } from './types';
|
|
1
|
+
export { getLocales, getCalendars } from './localization.js';
|
|
2
|
+
export { addLocaleListener, addCalendarListener } from './native-module.js';
|
|
3
|
+
export { Weekday, CalendarIdentifier } from './types.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Hand-ported from .vendors/expo/packages/expo-localization/src/Localization.ts (sdk-57) —
|
|
2
2
|
// both functions delegate straight to the native module, no extra wrapping needed beyond typing
|
|
3
3
|
// them as synchronous getters.
|
|
4
|
-
import ExpoLocalizationModule from './native-module';
|
|
4
|
+
import ExpoLocalizationModule from './native-module.js';
|
|
5
5
|
/**
|
|
6
6
|
* List of user's locales, returned as an array of objects of type `Locale`.
|
|
7
7
|
* Guaranteed to contain at least 1 element.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// React lifecycle wiring over the framework-agnostic core — mirrors use-locales' shape exactly.
|
|
2
2
|
// Ported from expo-localization's own useCalendars hook (sdk-57).
|
|
3
3
|
import { useEffect, useMemo, useReducer } from 'react';
|
|
4
|
-
import { addCalendarListener, getCalendars } from '../../../core';
|
|
4
|
+
import { addCalendarListener, getCalendars } from '../../../core/index.js';
|
|
5
5
|
export function useCalendars() {
|
|
6
6
|
const [invalidationKey, invalidate] = useReducer((key) => key + 1, 0);
|
|
7
7
|
const calendars = useMemo(() => getCalendars(), [invalidationKey]);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// useReducer-driven invalidation counter that useMemo recomputes getLocales() from, whenever the
|
|
4
4
|
// native module fires onLocaleSettingsChanged.
|
|
5
5
|
import { useEffect, useMemo, useReducer } from 'react';
|
|
6
|
-
import { addLocaleListener, getLocales } from '../../../core';
|
|
6
|
+
import { addLocaleListener, getLocales } from '../../../core/index.js';
|
|
7
7
|
export function useLocales() {
|
|
8
8
|
const [invalidationKey, invalidate] = useReducer((key) => key + 1, 0);
|
|
9
9
|
const locales = useMemo(() => getLocales(), [invalidationKey]);
|
package/build/react/index.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// and calendars each get their own lifecycle hook, matching upstream's own useLocales/
|
|
3
3
|
// useCalendars being two separate hooks, not one combined hook — mirrors the lifecycle-bucket
|
|
4
4
|
// naming convention of adapters/react/src/hooks (never `composables`, that's Vue's term).
|
|
5
|
-
export { useLocales } from './hooks/use-locales';
|
|
6
|
-
export { useCalendars } from './hooks/use-calendars';
|
|
7
|
-
export { getLocales, getCalendars, addLocaleListener, addCalendarListener, Weekday, CalendarIdentifier, } from '../core';
|
|
5
|
+
export { useLocales } from './hooks/use-locales/index.js';
|
|
6
|
+
export { useCalendars } from './hooks/use-calendars/index.js';
|
|
7
|
+
export { getLocales, getCalendars, addLocaleListener, addCalendarListener, Weekday, CalendarIdentifier, } from '../core/index.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Vue lifecycle wiring over the framework-agnostic core — mirrors use-locales' shape exactly.
|
|
2
2
|
import { onMounted, onUnmounted, ref } from '@vue/runtime-core';
|
|
3
|
-
import { addCalendarListener, getCalendars, } from '../../../core';
|
|
3
|
+
import { addCalendarListener, getCalendars, } from '../../../core/index.js';
|
|
4
4
|
export function useCalendars() {
|
|
5
5
|
const calendars = ref(getCalendars());
|
|
6
6
|
let subscription;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// setup — onMounted only wires the change listener, mirroring use-network-state's
|
|
5
5
|
// onMounted/onUnmounted subscription shape otherwise.
|
|
6
6
|
import { onMounted, onUnmounted, ref } from '@vue/runtime-core';
|
|
7
|
-
import { addLocaleListener, getLocales } from '../../../core';
|
|
7
|
+
import { addLocaleListener, getLocales } from '../../../core/index.js';
|
|
8
8
|
export function useLocales() {
|
|
9
9
|
const locales = ref(getLocales());
|
|
10
10
|
let subscription;
|
package/build/vue/index.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// calendars each get their own lifecycle composable, matching upstream's own useLocales/
|
|
3
3
|
// useCalendars being two separate hooks, not one combined hook — mirrors the lifecycle-bucket
|
|
4
4
|
// naming convention of adapters/vue/src/composables (never `hooks`, that's React's term).
|
|
5
|
-
export { useLocales } from './composables/use-locales';
|
|
6
|
-
export { useCalendars } from './composables/use-calendars';
|
|
7
|
-
export { getLocales, getCalendars, addLocaleListener, addCalendarListener, Weekday, CalendarIdentifier, } from '../core';
|
|
5
|
+
export { useLocales } from './composables/use-locales/index.js';
|
|
6
|
+
export { useCalendars } from './composables/use-calendars/index.js';
|
|
7
|
+
export { getLocales, getCalendars, addLocaleListener, addCalendarListener, Weekday, CalendarIdentifier, } from '../core/index.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/localization",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "expo-localization wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. Two independent synchronous getters (getLocales, getCalendars), each with its own native change listener and its own reactive hook per adapter.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -40,7 +40,10 @@
|
|
|
40
40
|
"src",
|
|
41
41
|
"build",
|
|
42
42
|
"build-ngc",
|
|
43
|
-
"native-link.json"
|
|
43
|
+
"native-link.json",
|
|
44
|
+
"!src/**/*.test.*",
|
|
45
|
+
"!src/**/*.spec.*",
|
|
46
|
+
"!src/**/*.detox.*"
|
|
44
47
|
],
|
|
45
48
|
"publishConfig": {
|
|
46
49
|
"access": "public"
|
|
@@ -56,7 +59,7 @@
|
|
|
56
59
|
"react": ">=19.0.0",
|
|
57
60
|
"react-native": ">=0.86",
|
|
58
61
|
"vue": ">=3.5.0",
|
|
59
|
-
"@symbiote-native/angular": "0.6.
|
|
62
|
+
"@symbiote-native/angular": "0.6.2",
|
|
60
63
|
"@symbiote-native/react": "0.2.8",
|
|
61
64
|
"@symbiote-native/vue": "0.3.8"
|
|
62
65
|
},
|
|
@@ -92,11 +95,11 @@
|
|
|
92
95
|
"@vue/runtime-core": "^3.5.13",
|
|
93
96
|
"react": "19.2.3",
|
|
94
97
|
"typescript": "~6.0.0",
|
|
95
|
-
"@symbiote-native/angular": "0.6.
|
|
98
|
+
"@symbiote-native/angular": "0.6.2",
|
|
99
|
+
"@symbiote-native/engine": "0.1.7",
|
|
96
100
|
"@symbiote-native/react": "0.2.8",
|
|
97
|
-
"@symbiote-native/vue": "0.3.8",
|
|
98
101
|
"@symbiote-native/test-utils": "0.1.6",
|
|
99
|
-
"@symbiote-native/
|
|
102
|
+
"@symbiote-native/vue": "0.3.8"
|
|
100
103
|
},
|
|
101
104
|
"scripts": {
|
|
102
105
|
"typecheck": "tsc --build",
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// Co-located Angular-driven test (ADR 0025) for CalendarsService. See locales.service.test.ts for
|
|
2
|
-
// the shared rationale.
|
|
3
|
-
|
|
4
|
-
import '@angular/compiler';
|
|
5
|
-
import { Component, inject, type Signal } from '@angular/core';
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import { mount, unmount } from '@symbiote-native/angular';
|
|
8
|
-
import { installFabric } from '@symbiote-native/test-utils';
|
|
9
|
-
import { CalendarIdentifier, Weekday, type Calendar } from '../../../core/types';
|
|
10
|
-
import { CalendarsService } from './index';
|
|
11
|
-
|
|
12
|
-
const FAKE_CALENDARS_INITIAL: Calendar[] = [
|
|
13
|
-
{
|
|
14
|
-
calendar: CalendarIdentifier.GREGORY,
|
|
15
|
-
uses24hourClock: true,
|
|
16
|
-
firstWeekday: Weekday.SUNDAY,
|
|
17
|
-
timeZone: 'Europe/Warsaw',
|
|
18
|
-
},
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
const FAKE_CALENDARS_UPDATED: Calendar[] = [
|
|
22
|
-
{
|
|
23
|
-
calendar: CalendarIdentifier.ISO8601,
|
|
24
|
-
uses24hourClock: false,
|
|
25
|
-
firstWeekday: Weekday.MONDAY,
|
|
26
|
-
timeZone: 'America/New_York',
|
|
27
|
-
},
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const addListenerMock = vi.fn();
|
|
31
|
-
const removeMock = vi.fn();
|
|
32
|
-
const getCalendarsMock = vi.fn(() => FAKE_CALENDARS_INITIAL);
|
|
33
|
-
|
|
34
|
-
vi.mock('../../../core', () => ({
|
|
35
|
-
addCalendarListener: (listener: () => void) => addListenerMock(listener),
|
|
36
|
-
getCalendars: () => getCalendarsMock(),
|
|
37
|
-
}));
|
|
38
|
-
|
|
39
|
-
const ROOT_TAG = 975;
|
|
40
|
-
const fabric = installFabric();
|
|
41
|
-
const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
|
|
42
|
-
|
|
43
|
-
let capturedResult: Signal<Calendar[]> | undefined;
|
|
44
|
-
let capturedListener: (() => void) | undefined;
|
|
45
|
-
|
|
46
|
-
@Component({
|
|
47
|
-
selector: 'symbiote-calendars-host',
|
|
48
|
-
standalone: true,
|
|
49
|
-
template: '',
|
|
50
|
-
})
|
|
51
|
-
class CalendarsHost {
|
|
52
|
-
readonly calendars = inject(CalendarsService).connect();
|
|
53
|
-
|
|
54
|
-
constructor() {
|
|
55
|
-
capturedResult = this.calendars;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
beforeEach(() => {
|
|
60
|
-
capturedResult = undefined;
|
|
61
|
-
capturedListener = undefined;
|
|
62
|
-
getCalendarsMock.mockReturnValue(FAKE_CALENDARS_INITIAL);
|
|
63
|
-
addListenerMock.mockImplementation(listener => {
|
|
64
|
-
capturedListener = listener;
|
|
65
|
-
return { remove: removeMock };
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
afterEach(() => {
|
|
70
|
-
unmount(ROOT_TAG);
|
|
71
|
-
fabric.reset();
|
|
72
|
-
vi.clearAllMocks();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('CalendarsService.connect', () => {
|
|
76
|
-
it('reads the current calendars synchronously', () => {
|
|
77
|
-
mount(ROOT_TAG, CalendarsHost);
|
|
78
|
-
|
|
79
|
-
expect(capturedResult?.()).toEqual(FAKE_CALENDARS_INITIAL);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('recomputes the signal when the registered listener fires', async () => {
|
|
83
|
-
mount(ROOT_TAG, CalendarsHost);
|
|
84
|
-
await tick();
|
|
85
|
-
|
|
86
|
-
if (capturedListener === undefined) throw new Error('addListener callback was not captured');
|
|
87
|
-
getCalendarsMock.mockReturnValue(FAKE_CALENDARS_UPDATED);
|
|
88
|
-
capturedListener();
|
|
89
|
-
|
|
90
|
-
expect(capturedResult?.()).toEqual(FAKE_CALENDARS_UPDATED);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('removes the subscription when the host component is unmounted', async () => {
|
|
94
|
-
mount(ROOT_TAG, CalendarsHost);
|
|
95
|
-
await tick();
|
|
96
|
-
|
|
97
|
-
unmount(ROOT_TAG);
|
|
98
|
-
await tick();
|
|
99
|
-
|
|
100
|
-
expect(removeMock).toHaveBeenCalledOnce();
|
|
101
|
-
});
|
|
102
|
-
});
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
// Co-located Angular-driven test (ADR 0025) for LocalesService. See packages/battery's
|
|
2
|
-
// battery-state.service.test.ts for the shared rationale.
|
|
3
|
-
|
|
4
|
-
import '@angular/compiler';
|
|
5
|
-
import { Component, inject, type Signal } from '@angular/core';
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import { mount, unmount } from '@symbiote-native/angular';
|
|
8
|
-
import { installFabric } from '@symbiote-native/test-utils';
|
|
9
|
-
import type { Locale } from '../../../core';
|
|
10
|
-
import { LocalesService } from './index';
|
|
11
|
-
|
|
12
|
-
const FAKE_LOCALES_INITIAL: Locale[] = [
|
|
13
|
-
{
|
|
14
|
-
languageTag: 'pl-PL',
|
|
15
|
-
languageCode: 'pl',
|
|
16
|
-
languageScriptCode: 'Latn',
|
|
17
|
-
regionCode: 'PL',
|
|
18
|
-
languageRegionCode: 'PL',
|
|
19
|
-
currencyCode: 'PLN',
|
|
20
|
-
currencySymbol: 'zł',
|
|
21
|
-
languageCurrencyCode: 'PLN',
|
|
22
|
-
languageCurrencySymbol: 'zł',
|
|
23
|
-
decimalSeparator: ',',
|
|
24
|
-
digitGroupingSeparator: ' ',
|
|
25
|
-
textDirection: 'ltr',
|
|
26
|
-
measurementSystem: 'metric',
|
|
27
|
-
temperatureUnit: 'celsius',
|
|
28
|
-
},
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const FAKE_LOCALES_UPDATED: Locale[] = [
|
|
32
|
-
{
|
|
33
|
-
languageTag: 'en-US',
|
|
34
|
-
languageCode: 'en',
|
|
35
|
-
languageScriptCode: 'Latn',
|
|
36
|
-
regionCode: 'US',
|
|
37
|
-
languageRegionCode: 'US',
|
|
38
|
-
currencyCode: 'USD',
|
|
39
|
-
currencySymbol: '$',
|
|
40
|
-
languageCurrencyCode: 'USD',
|
|
41
|
-
languageCurrencySymbol: '$',
|
|
42
|
-
decimalSeparator: '.',
|
|
43
|
-
digitGroupingSeparator: ',',
|
|
44
|
-
textDirection: 'ltr',
|
|
45
|
-
measurementSystem: 'us',
|
|
46
|
-
temperatureUnit: 'fahrenheit',
|
|
47
|
-
},
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
const addListenerMock = vi.fn();
|
|
51
|
-
const removeMock = vi.fn();
|
|
52
|
-
const getLocalesMock = vi.fn(() => FAKE_LOCALES_INITIAL);
|
|
53
|
-
|
|
54
|
-
vi.mock('../../../core', () => ({
|
|
55
|
-
addLocaleListener: (listener: () => void) => addListenerMock(listener),
|
|
56
|
-
getLocales: () => getLocalesMock(),
|
|
57
|
-
}));
|
|
58
|
-
|
|
59
|
-
const ROOT_TAG = 974;
|
|
60
|
-
const fabric = installFabric();
|
|
61
|
-
const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
|
|
62
|
-
|
|
63
|
-
let capturedResult: Signal<Locale[]> | undefined;
|
|
64
|
-
let capturedListener: (() => void) | undefined;
|
|
65
|
-
|
|
66
|
-
@Component({
|
|
67
|
-
selector: 'symbiote-locales-host',
|
|
68
|
-
standalone: true,
|
|
69
|
-
template: '',
|
|
70
|
-
})
|
|
71
|
-
class LocalesHost {
|
|
72
|
-
readonly locales = inject(LocalesService).connect();
|
|
73
|
-
|
|
74
|
-
constructor() {
|
|
75
|
-
capturedResult = this.locales;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
beforeEach(() => {
|
|
80
|
-
capturedResult = undefined;
|
|
81
|
-
capturedListener = undefined;
|
|
82
|
-
getLocalesMock.mockReturnValue(FAKE_LOCALES_INITIAL);
|
|
83
|
-
addListenerMock.mockImplementation(listener => {
|
|
84
|
-
capturedListener = listener;
|
|
85
|
-
return { remove: removeMock };
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
afterEach(() => {
|
|
90
|
-
unmount(ROOT_TAG);
|
|
91
|
-
fabric.reset();
|
|
92
|
-
vi.clearAllMocks();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('LocalesService.connect', () => {
|
|
96
|
-
it('reads the current locales synchronously', () => {
|
|
97
|
-
mount(ROOT_TAG, LocalesHost);
|
|
98
|
-
|
|
99
|
-
expect(capturedResult?.()).toEqual(FAKE_LOCALES_INITIAL);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('recomputes the signal when the registered listener fires', async () => {
|
|
103
|
-
mount(ROOT_TAG, LocalesHost);
|
|
104
|
-
await tick();
|
|
105
|
-
|
|
106
|
-
if (capturedListener === undefined) throw new Error('addListener callback was not captured');
|
|
107
|
-
getLocalesMock.mockReturnValue(FAKE_LOCALES_UPDATED);
|
|
108
|
-
capturedListener();
|
|
109
|
-
|
|
110
|
-
expect(capturedResult?.()).toEqual(FAKE_LOCALES_UPDATED);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('removes the subscription when the host component is unmounted', async () => {
|
|
114
|
-
mount(ROOT_TAG, LocalesHost);
|
|
115
|
-
await tick();
|
|
116
|
-
|
|
117
|
-
unmount(ROOT_TAG);
|
|
118
|
-
await tick();
|
|
119
|
-
|
|
120
|
-
expect(removeMock).toHaveBeenCalledOnce();
|
|
121
|
-
});
|
|
122
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { CalendarIdentifier, Weekday, type Calendar, type Locale } from './types';
|
|
3
|
-
|
|
4
|
-
const FAKE_LOCALES: Locale[] = [
|
|
5
|
-
{
|
|
6
|
-
languageTag: 'pl-PL',
|
|
7
|
-
languageCode: 'pl',
|
|
8
|
-
languageScriptCode: 'Latn',
|
|
9
|
-
regionCode: 'PL',
|
|
10
|
-
languageRegionCode: 'PL',
|
|
11
|
-
currencyCode: 'PLN',
|
|
12
|
-
currencySymbol: 'zł',
|
|
13
|
-
languageCurrencyCode: 'PLN',
|
|
14
|
-
languageCurrencySymbol: 'zł',
|
|
15
|
-
decimalSeparator: ',',
|
|
16
|
-
digitGroupingSeparator: ' ',
|
|
17
|
-
textDirection: 'ltr',
|
|
18
|
-
measurementSystem: 'metric',
|
|
19
|
-
temperatureUnit: 'celsius',
|
|
20
|
-
},
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
const FAKE_CALENDARS: Calendar[] = [
|
|
24
|
-
{
|
|
25
|
-
calendar: CalendarIdentifier.GREGORY,
|
|
26
|
-
uses24hourClock: true,
|
|
27
|
-
firstWeekday: Weekday.MONDAY,
|
|
28
|
-
timeZone: 'Europe/Warsaw',
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const getLocalesMock = vi.fn(() => FAKE_LOCALES);
|
|
33
|
-
const getCalendarsMock = vi.fn(() => FAKE_CALENDARS);
|
|
34
|
-
|
|
35
|
-
// The real ExpoLocalization native module only exists on device — resolving it via
|
|
36
|
-
// requireNativeModule() at import time would throw in this headless test run, so the
|
|
37
|
-
// module-lookup file is faked in place of expo-modules-core's runtime resolution, the same
|
|
38
|
-
// pattern packages/battery/src/core/battery.test.ts uses.
|
|
39
|
-
vi.mock('./native-module', () => ({
|
|
40
|
-
default: {
|
|
41
|
-
getLocales: getLocalesMock,
|
|
42
|
-
getCalendars: getCalendarsMock,
|
|
43
|
-
},
|
|
44
|
-
}));
|
|
45
|
-
|
|
46
|
-
const { getLocales, getCalendars } = await import('./localization');
|
|
47
|
-
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
vi.clearAllMocks();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('getLocales', () => {
|
|
53
|
-
it('delegates to the native module', () => {
|
|
54
|
-
expect(getLocales()).toEqual(FAKE_LOCALES);
|
|
55
|
-
expect(getLocalesMock).toHaveBeenCalledOnce();
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe('getCalendars', () => {
|
|
60
|
-
it('delegates to the native module', () => {
|
|
61
|
-
expect(getCalendars()).toEqual(FAKE_CALENDARS);
|
|
62
|
-
expect(getCalendarsMock).toHaveBeenCalledOnce();
|
|
63
|
-
});
|
|
64
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// Co-located React-driven test (ADR 0025) for useCalendars. See use-locales' test for the shared
|
|
2
|
-
// rationale (mocks `core`, not expo-modules-core internals).
|
|
3
|
-
|
|
4
|
-
import { createElement, type ReactElement } from 'react';
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
-
import { mount, unmount, View } from '@symbiote-native/react';
|
|
7
|
-
import { installFabric } from '@symbiote-native/test-utils';
|
|
8
|
-
import { CalendarIdentifier, Weekday, type Calendar } from '../../../core/types';
|
|
9
|
-
import { useCalendars } from './index';
|
|
10
|
-
|
|
11
|
-
const FAKE_CALENDARS_INITIAL: Calendar[] = [
|
|
12
|
-
{
|
|
13
|
-
calendar: CalendarIdentifier.GREGORY,
|
|
14
|
-
uses24hourClock: true,
|
|
15
|
-
firstWeekday: Weekday.SUNDAY,
|
|
16
|
-
timeZone: 'Europe/Warsaw',
|
|
17
|
-
},
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
const FAKE_CALENDARS_UPDATED: Calendar[] = [
|
|
21
|
-
{
|
|
22
|
-
calendar: CalendarIdentifier.ISO8601,
|
|
23
|
-
uses24hourClock: false,
|
|
24
|
-
firstWeekday: Weekday.MONDAY,
|
|
25
|
-
timeZone: 'America/New_York',
|
|
26
|
-
},
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const { addListener, getCalendars, remove } = vi.hoisted(() => {
|
|
30
|
-
const remove = vi.fn();
|
|
31
|
-
return {
|
|
32
|
-
addListener: vi.fn((_listener: () => void) => ({ remove })),
|
|
33
|
-
getCalendars: vi.fn(),
|
|
34
|
-
remove,
|
|
35
|
-
};
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
vi.mock('../../../core', () => ({
|
|
39
|
-
addCalendarListener: addListener,
|
|
40
|
-
getCalendars,
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
const ROOT_TAG = 955;
|
|
44
|
-
|
|
45
|
-
const results: Calendar[][] = [];
|
|
46
|
-
|
|
47
|
-
function Probe(): ReactElement {
|
|
48
|
-
results.push(useCalendars());
|
|
49
|
-
return createElement(View);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const fabric = installFabric();
|
|
53
|
-
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
fabric.reset();
|
|
56
|
-
results.length = 0;
|
|
57
|
-
vi.clearAllMocks();
|
|
58
|
-
getCalendars.mockReturnValue(FAKE_CALENDARS_INITIAL);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
afterEach(() => unmount(ROOT_TAG));
|
|
62
|
-
|
|
63
|
-
describe('useCalendars', () => {
|
|
64
|
-
it('reads the current calendars synchronously on first render', () => {
|
|
65
|
-
mount(ROOT_TAG, createElement(Probe));
|
|
66
|
-
|
|
67
|
-
expect(results[results.length - 1]).toEqual(FAKE_CALENDARS_INITIAL);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('recomputes calendars when the native listener fires', async () => {
|
|
71
|
-
mount(ROOT_TAG, createElement(Probe));
|
|
72
|
-
|
|
73
|
-
const invalidate = addListener.mock.calls[0][0];
|
|
74
|
-
getCalendars.mockReturnValue(FAKE_CALENDARS_UPDATED);
|
|
75
|
-
invalidate();
|
|
76
|
-
|
|
77
|
-
await vi.waitFor(() => expect(results[results.length - 1]).toEqual(FAKE_CALENDARS_UPDATED));
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('unsubscribes from the native listener on unmount', () => {
|
|
81
|
-
mount(ROOT_TAG, createElement(Probe));
|
|
82
|
-
|
|
83
|
-
unmount(ROOT_TAG);
|
|
84
|
-
|
|
85
|
-
expect(remove).toHaveBeenCalledTimes(1);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
// Co-located React-driven test (ADR 0025) for useLocales. Mocks `core`, not expo-modules-core
|
|
2
|
-
// internals — same pattern packages/battery's hook tests use.
|
|
3
|
-
|
|
4
|
-
import { createElement, type ReactElement } from 'react';
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
-
import { mount, unmount, View } from '@symbiote-native/react';
|
|
7
|
-
import { installFabric } from '@symbiote-native/test-utils';
|
|
8
|
-
import type { Locale } from '../../../core';
|
|
9
|
-
import { useLocales } from './index';
|
|
10
|
-
|
|
11
|
-
const FAKE_LOCALES_INITIAL: Locale[] = [
|
|
12
|
-
{
|
|
13
|
-
languageTag: 'pl-PL',
|
|
14
|
-
languageCode: 'pl',
|
|
15
|
-
languageScriptCode: 'Latn',
|
|
16
|
-
regionCode: 'PL',
|
|
17
|
-
languageRegionCode: 'PL',
|
|
18
|
-
currencyCode: 'PLN',
|
|
19
|
-
currencySymbol: 'zł',
|
|
20
|
-
languageCurrencyCode: 'PLN',
|
|
21
|
-
languageCurrencySymbol: 'zł',
|
|
22
|
-
decimalSeparator: ',',
|
|
23
|
-
digitGroupingSeparator: ' ',
|
|
24
|
-
textDirection: 'ltr',
|
|
25
|
-
measurementSystem: 'metric',
|
|
26
|
-
temperatureUnit: 'celsius',
|
|
27
|
-
},
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const FAKE_LOCALES_UPDATED: Locale[] = [
|
|
31
|
-
{
|
|
32
|
-
languageTag: 'en-US',
|
|
33
|
-
languageCode: 'en',
|
|
34
|
-
languageScriptCode: 'Latn',
|
|
35
|
-
regionCode: 'US',
|
|
36
|
-
languageRegionCode: 'US',
|
|
37
|
-
currencyCode: 'USD',
|
|
38
|
-
currencySymbol: '$',
|
|
39
|
-
languageCurrencyCode: 'USD',
|
|
40
|
-
languageCurrencySymbol: '$',
|
|
41
|
-
decimalSeparator: '.',
|
|
42
|
-
digitGroupingSeparator: ',',
|
|
43
|
-
textDirection: 'ltr',
|
|
44
|
-
measurementSystem: 'us',
|
|
45
|
-
temperatureUnit: 'fahrenheit',
|
|
46
|
-
},
|
|
47
|
-
];
|
|
48
|
-
|
|
49
|
-
const { addListener, getLocales, remove } = vi.hoisted(() => {
|
|
50
|
-
const remove = vi.fn();
|
|
51
|
-
return {
|
|
52
|
-
addListener: vi.fn((_listener: () => void) => ({ remove })),
|
|
53
|
-
getLocales: vi.fn(),
|
|
54
|
-
remove,
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
vi.mock('../../../core', () => ({
|
|
59
|
-
addLocaleListener: addListener,
|
|
60
|
-
getLocales,
|
|
61
|
-
}));
|
|
62
|
-
|
|
63
|
-
const ROOT_TAG = 954;
|
|
64
|
-
|
|
65
|
-
const results: Locale[][] = [];
|
|
66
|
-
|
|
67
|
-
function Probe(): ReactElement {
|
|
68
|
-
results.push(useLocales());
|
|
69
|
-
return createElement(View);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const fabric = installFabric();
|
|
73
|
-
|
|
74
|
-
beforeEach(() => {
|
|
75
|
-
fabric.reset();
|
|
76
|
-
results.length = 0;
|
|
77
|
-
vi.clearAllMocks();
|
|
78
|
-
getLocales.mockReturnValue(FAKE_LOCALES_INITIAL);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
afterEach(() => unmount(ROOT_TAG));
|
|
82
|
-
|
|
83
|
-
describe('useLocales', () => {
|
|
84
|
-
it('reads the current locales synchronously on first render', () => {
|
|
85
|
-
mount(ROOT_TAG, createElement(Probe));
|
|
86
|
-
|
|
87
|
-
expect(results[results.length - 1]).toEqual(FAKE_LOCALES_INITIAL);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('recomputes locales when the native listener fires', async () => {
|
|
91
|
-
mount(ROOT_TAG, createElement(Probe));
|
|
92
|
-
|
|
93
|
-
const invalidate = addListener.mock.calls[0][0];
|
|
94
|
-
getLocales.mockReturnValue(FAKE_LOCALES_UPDATED);
|
|
95
|
-
invalidate();
|
|
96
|
-
|
|
97
|
-
await vi.waitFor(() => expect(results[results.length - 1]).toEqual(FAKE_LOCALES_UPDATED));
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('unsubscribes from the native listener on unmount', () => {
|
|
101
|
-
mount(ROOT_TAG, createElement(Probe));
|
|
102
|
-
|
|
103
|
-
unmount(ROOT_TAG);
|
|
104
|
-
|
|
105
|
-
expect(remove).toHaveBeenCalledTimes(1);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
// Co-located Vue-driven test (ADR 0025) for useCalendars. See use-locales' test for the shared
|
|
2
|
-
// rationale.
|
|
3
|
-
|
|
4
|
-
import { defineComponent, h, type Ref } from '@vue/runtime-core';
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
-
import { mount, unmount } from '@symbiote-native/vue';
|
|
7
|
-
import { installFabric } from '@symbiote-native/test-utils';
|
|
8
|
-
import { CalendarIdentifier, Weekday, type Calendar } from '../../../core/types';
|
|
9
|
-
import { useCalendars } from './index';
|
|
10
|
-
|
|
11
|
-
const ROOT_TAG = 9955;
|
|
12
|
-
|
|
13
|
-
const FAKE_CALENDARS_INITIAL: Calendar[] = [
|
|
14
|
-
{
|
|
15
|
-
calendar: CalendarIdentifier.GREGORY,
|
|
16
|
-
uses24hourClock: true,
|
|
17
|
-
firstWeekday: Weekday.SUNDAY,
|
|
18
|
-
timeZone: 'Europe/Warsaw',
|
|
19
|
-
},
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
const FAKE_CALENDARS_UPDATED: Calendar[] = [
|
|
23
|
-
{
|
|
24
|
-
calendar: CalendarIdentifier.ISO8601,
|
|
25
|
-
uses24hourClock: false,
|
|
26
|
-
firstWeekday: Weekday.MONDAY,
|
|
27
|
-
timeZone: 'America/New_York',
|
|
28
|
-
},
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
let registeredListener: (() => void) | undefined;
|
|
32
|
-
const removeMock = vi.fn();
|
|
33
|
-
const addListenerMock = vi.fn((listener: () => void) => {
|
|
34
|
-
registeredListener = listener;
|
|
35
|
-
return { remove: removeMock };
|
|
36
|
-
});
|
|
37
|
-
const getCalendarsMock = vi.fn(() => FAKE_CALENDARS_INITIAL);
|
|
38
|
-
|
|
39
|
-
vi.mock('../../../core', () => ({
|
|
40
|
-
addCalendarListener: (listener: () => void) => addListenerMock(listener),
|
|
41
|
-
getCalendars: () => getCalendarsMock(),
|
|
42
|
-
}));
|
|
43
|
-
|
|
44
|
-
const fabric = installFabric();
|
|
45
|
-
|
|
46
|
-
beforeEach(() => {
|
|
47
|
-
fabric.reset();
|
|
48
|
-
registeredListener = undefined;
|
|
49
|
-
addListenerMock.mockClear();
|
|
50
|
-
removeMock.mockClear();
|
|
51
|
-
getCalendarsMock.mockClear();
|
|
52
|
-
getCalendarsMock.mockReturnValue(FAKE_CALENDARS_INITIAL);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
afterEach(() => unmount(ROOT_TAG));
|
|
56
|
-
|
|
57
|
-
function mountCalendars(): Ref<Calendar[]> {
|
|
58
|
-
let calendars: Ref<Calendar[]> | undefined;
|
|
59
|
-
mount(
|
|
60
|
-
ROOT_TAG,
|
|
61
|
-
defineComponent({
|
|
62
|
-
setup: () => {
|
|
63
|
-
calendars = useCalendars();
|
|
64
|
-
return () => h('symbiote-text', {}, 'calendars');
|
|
65
|
-
},
|
|
66
|
-
}),
|
|
67
|
-
);
|
|
68
|
-
if (calendars === undefined) {
|
|
69
|
-
throw new Error('setup() did not run');
|
|
70
|
-
}
|
|
71
|
-
return calendars;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
describe('useCalendars (Vue)', () => {
|
|
75
|
-
it('reads the current calendars synchronously at setup', () => {
|
|
76
|
-
const calendars = mountCalendars();
|
|
77
|
-
|
|
78
|
-
expect(calendars.value).toEqual(FAKE_CALENDARS_INITIAL);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('recomputes the ref when the native listener fires', () => {
|
|
82
|
-
const calendars = mountCalendars();
|
|
83
|
-
|
|
84
|
-
getCalendarsMock.mockReturnValue(FAKE_CALENDARS_UPDATED);
|
|
85
|
-
registeredListener?.();
|
|
86
|
-
|
|
87
|
-
expect(calendars.value).toEqual(FAKE_CALENDARS_UPDATED);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('removes the subscription on unmount', () => {
|
|
91
|
-
mountCalendars();
|
|
92
|
-
unmount(ROOT_TAG);
|
|
93
|
-
|
|
94
|
-
expect(removeMock).toHaveBeenCalledTimes(1);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// Co-located Vue-driven test (ADR 0025) for useLocales. See packages/battery's
|
|
2
|
-
// use-battery-state.test.ts for the shared rationale.
|
|
3
|
-
|
|
4
|
-
import { defineComponent, h, type Ref } from '@vue/runtime-core';
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
-
import { mount, unmount } from '@symbiote-native/vue';
|
|
7
|
-
import { installFabric } from '@symbiote-native/test-utils';
|
|
8
|
-
import type { Locale } from '../../../core';
|
|
9
|
-
import { useLocales } from './index';
|
|
10
|
-
|
|
11
|
-
const ROOT_TAG = 9954;
|
|
12
|
-
|
|
13
|
-
const FAKE_LOCALES_INITIAL: Locale[] = [
|
|
14
|
-
{
|
|
15
|
-
languageTag: 'pl-PL',
|
|
16
|
-
languageCode: 'pl',
|
|
17
|
-
languageScriptCode: 'Latn',
|
|
18
|
-
regionCode: 'PL',
|
|
19
|
-
languageRegionCode: 'PL',
|
|
20
|
-
currencyCode: 'PLN',
|
|
21
|
-
currencySymbol: 'zł',
|
|
22
|
-
languageCurrencyCode: 'PLN',
|
|
23
|
-
languageCurrencySymbol: 'zł',
|
|
24
|
-
decimalSeparator: ',',
|
|
25
|
-
digitGroupingSeparator: ' ',
|
|
26
|
-
textDirection: 'ltr',
|
|
27
|
-
measurementSystem: 'metric',
|
|
28
|
-
temperatureUnit: 'celsius',
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const FAKE_LOCALES_UPDATED: Locale[] = [
|
|
33
|
-
{
|
|
34
|
-
languageTag: 'en-US',
|
|
35
|
-
languageCode: 'en',
|
|
36
|
-
languageScriptCode: 'Latn',
|
|
37
|
-
regionCode: 'US',
|
|
38
|
-
languageRegionCode: 'US',
|
|
39
|
-
currencyCode: 'USD',
|
|
40
|
-
currencySymbol: '$',
|
|
41
|
-
languageCurrencyCode: 'USD',
|
|
42
|
-
languageCurrencySymbol: '$',
|
|
43
|
-
decimalSeparator: '.',
|
|
44
|
-
digitGroupingSeparator: ',',
|
|
45
|
-
textDirection: 'ltr',
|
|
46
|
-
measurementSystem: 'us',
|
|
47
|
-
temperatureUnit: 'fahrenheit',
|
|
48
|
-
},
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
let registeredListener: (() => void) | undefined;
|
|
52
|
-
const removeMock = vi.fn();
|
|
53
|
-
const addListenerMock = vi.fn((listener: () => void) => {
|
|
54
|
-
registeredListener = listener;
|
|
55
|
-
return { remove: removeMock };
|
|
56
|
-
});
|
|
57
|
-
const getLocalesMock = vi.fn(() => FAKE_LOCALES_INITIAL);
|
|
58
|
-
|
|
59
|
-
vi.mock('../../../core', () => ({
|
|
60
|
-
addLocaleListener: (listener: () => void) => addListenerMock(listener),
|
|
61
|
-
getLocales: () => getLocalesMock(),
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
const fabric = installFabric();
|
|
65
|
-
|
|
66
|
-
beforeEach(() => {
|
|
67
|
-
fabric.reset();
|
|
68
|
-
registeredListener = undefined;
|
|
69
|
-
addListenerMock.mockClear();
|
|
70
|
-
removeMock.mockClear();
|
|
71
|
-
getLocalesMock.mockClear();
|
|
72
|
-
getLocalesMock.mockReturnValue(FAKE_LOCALES_INITIAL);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
afterEach(() => unmount(ROOT_TAG));
|
|
76
|
-
|
|
77
|
-
function mountLocales(): Ref<Locale[]> {
|
|
78
|
-
let locales: Ref<Locale[]> | undefined;
|
|
79
|
-
mount(
|
|
80
|
-
ROOT_TAG,
|
|
81
|
-
defineComponent({
|
|
82
|
-
setup: () => {
|
|
83
|
-
locales = useLocales();
|
|
84
|
-
return () => h('symbiote-text', {}, 'locales');
|
|
85
|
-
},
|
|
86
|
-
}),
|
|
87
|
-
);
|
|
88
|
-
if (locales === undefined) {
|
|
89
|
-
throw new Error('setup() did not run');
|
|
90
|
-
}
|
|
91
|
-
return locales;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
describe('useLocales (Vue)', () => {
|
|
95
|
-
it('reads the current locales synchronously at setup', () => {
|
|
96
|
-
const locales = mountLocales();
|
|
97
|
-
|
|
98
|
-
expect(locales.value).toEqual(FAKE_LOCALES_INITIAL);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('recomputes the ref when the native listener fires', () => {
|
|
102
|
-
const locales = mountLocales();
|
|
103
|
-
|
|
104
|
-
getLocalesMock.mockReturnValue(FAKE_LOCALES_UPDATED);
|
|
105
|
-
registeredListener?.();
|
|
106
|
-
|
|
107
|
-
expect(locales.value).toEqual(FAKE_LOCALES_UPDATED);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('removes the subscription on unmount', () => {
|
|
111
|
-
mountLocales();
|
|
112
|
-
unmount(ROOT_TAG);
|
|
113
|
-
|
|
114
|
-
expect(removeMock).toHaveBeenCalledTimes(1);
|
|
115
|
-
});
|
|
116
|
-
});
|