@symbiote-native/localization 0.0.1 → 0.2.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.
Files changed (45) hide show
  1. package/README.md +2 -2
  2. package/build/angular/index.d.ts +1 -1
  3. package/build/angular/index.js +3 -3
  4. package/build/angular/services/calendars.service/index.js +1 -1
  5. package/build/angular/services/locales.service/index.js +1 -1
  6. package/build/core/index.js +3 -3
  7. package/build/core/localization.js +1 -1
  8. package/build/core/native-module.js +4 -6
  9. package/build/react/hooks/use-calendars/index.js +1 -1
  10. package/build/react/hooks/use-locales/index.js +1 -1
  11. package/build/react/index.d.ts +1 -1
  12. package/build/react/index.js +3 -3
  13. package/build/svelte/index.d.ts +3 -0
  14. package/build/svelte/index.js +8 -0
  15. package/build/svelte/runes/use-calendars.svelte.d.ts +4 -0
  16. package/build/svelte/runes/use-calendars.svelte.js +21 -0
  17. package/build/svelte/runes/use-locales.svelte.d.ts +4 -0
  18. package/build/svelte/runes/use-locales.svelte.js +27 -0
  19. package/build/vue/composables/use-calendars/index.js +1 -1
  20. package/build/vue/composables/use-locales/index.js +1 -1
  21. package/build/vue/index.d.ts +1 -1
  22. package/build/vue/index.js +3 -3
  23. package/build-ngc/angular/index.d.ts +1 -1
  24. package/build-ngc/angular/index.js +1 -1
  25. package/build-ngc/angular/index.js.map +1 -1
  26. package/build-ngc/angular/services/calendars.service/index.js +3 -3
  27. package/build-ngc/angular/services/locales.service/index.js +3 -3
  28. package/build-ngc/core/native-module.js +4 -6
  29. package/build-ngc/core/native-module.js.map +1 -1
  30. package/package.json +30 -13
  31. package/src/angular/index.ts +1 -11
  32. package/src/core/native-module.ts +4 -6
  33. package/src/react/index.ts +1 -11
  34. package/src/svelte/index.ts +9 -0
  35. package/src/svelte/runes/use-calendars.svelte.ts +29 -0
  36. package/src/svelte/runes/use-locales.svelte.ts +30 -0
  37. package/src/svelte/svelte-ambient.d.ts +6 -0
  38. package/src/vue/index.ts +1 -11
  39. package/src/angular/services/calendars.service/calendars.service.test.ts +0 -102
  40. package/src/angular/services/locales.service/locales.service.test.ts +0 -122
  41. package/src/core/localization.test.ts +0 -64
  42. package/src/react/hooks/use-calendars/use-calendars.test.tsx +0 -87
  43. package/src/react/hooks/use-locales/use-locales.test.tsx +0 -107
  44. package/src/vue/composables/use-calendars/use-calendars.test.ts +0 -96
  45. package/src/vue/composables/use-locales/use-locales.test.ts +0 -116
@@ -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
- });