@tolgee/core 5.33.2 → 5.33.3-prerelease.2efc0e6b.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 (56) hide show
  1. package/dist/tolgee.cjs.js +227 -186
  2. package/dist/tolgee.cjs.js.map +1 -1
  3. package/dist/tolgee.cjs.min.js +1 -1
  4. package/dist/tolgee.cjs.min.js.map +1 -1
  5. package/dist/tolgee.esm.js +227 -186
  6. package/dist/tolgee.esm.js.map +1 -1
  7. package/dist/tolgee.esm.min.js +1 -1
  8. package/dist/tolgee.esm.min.js.map +1 -1
  9. package/dist/tolgee.esm.min.mjs +1 -1
  10. package/dist/tolgee.esm.min.mjs.map +1 -1
  11. package/dist/tolgee.esm.mjs +227 -186
  12. package/dist/tolgee.esm.mjs.map +1 -1
  13. package/dist/tolgee.umd.js +227 -186
  14. package/dist/tolgee.umd.js.map +1 -1
  15. package/dist/tolgee.umd.min.js +1 -1
  16. package/dist/tolgee.umd.min.js.map +1 -1
  17. package/lib/Controller/Cache/Cache.d.ts +8 -12
  18. package/lib/Controller/Cache/helpers.d.ts +3 -2
  19. package/lib/Controller/Controller.d.ts +57 -26
  20. package/lib/Controller/Events/EventEmitter.d.ts +5 -5
  21. package/lib/Controller/Events/EventEmitterCombined.d.ts +6 -0
  22. package/lib/Controller/Events/Events.d.ts +39 -12
  23. package/lib/Controller/State/State.d.ts +10 -4
  24. package/lib/Controller/State/initState.d.ts +29 -7
  25. package/lib/TolgeeCore.d.ts +25 -28
  26. package/lib/helpers.d.ts +2 -2
  27. package/lib/types/cache.d.ts +19 -1
  28. package/lib/types/events.d.ts +24 -23
  29. package/lib/types/index.d.ts +1 -1
  30. package/package.json +2 -2
  31. package/src/Controller/Cache/Cache.test.ts +189 -0
  32. package/src/Controller/Cache/Cache.ts +118 -57
  33. package/src/Controller/Cache/helpers.ts +12 -3
  34. package/src/Controller/Controller.ts +81 -27
  35. package/src/Controller/Events/EventEmitter.ts +23 -15
  36. package/src/Controller/Events/EventEmitterCombined.ts +55 -0
  37. package/src/Controller/Events/Events.ts +31 -23
  38. package/src/Controller/Plugins/Plugins.ts +5 -0
  39. package/src/Controller/State/State.ts +26 -6
  40. package/src/Controller/State/initState.ts +35 -7
  41. package/src/TolgeeCore.ts +14 -17
  42. package/src/__test/cache.test.ts +2 -26
  43. package/src/__test/client.test.ts +3 -3
  44. package/src/__test/events.test.ts +40 -13
  45. package/src/__test/load.matrix.test.ts +123 -0
  46. package/src/__test/load.required.test.ts +71 -0
  47. package/src/__test/namespaces.required.test.ts +52 -0
  48. package/src/__test/options.test.ts +1 -1
  49. package/src/__test/testTools.ts +39 -0
  50. package/src/helpers.ts +2 -1
  51. package/src/types/cache.ts +24 -1
  52. package/src/types/events.ts +33 -24
  53. package/src/types/index.ts +1 -0
  54. package/lib/Controller/Events/EventEmitterSelective.d.ts +0 -7
  55. package/src/Controller/Events/EventEmitterSelective.test.ts +0 -110
  56. package/src/Controller/Events/EventEmitterSelective.ts +0 -133
@@ -4,20 +4,6 @@ declare function createTolgee(options: TolgeeOptions): Readonly<{
4
4
  * Listen to tolgee events.
5
5
  */
6
6
  on: import("./types").TolgeeOn<keyof import("./types").EventType>;
7
- /**
8
- * Listen for specific namespaces changes.
9
- *
10
- * ```
11
- * const sub = tolgee.onUpdate(handler)
12
- *
13
- * // subscribe to selected namespace
14
- * sub.subscribeNs(['common'])
15
- *
16
- * // unsubscribe
17
- * sub.unsubscribe()
18
- * ```
19
- */
20
- onNsUpdate: (handler: import("./types").Listener<undefined>) => import("./types").SubscriptionSelective;
21
7
  /**
22
8
  * Turn off/on events emitting. Is on by default.
23
9
  */
@@ -44,7 +30,9 @@ declare function createTolgee(options: TolgeeOptions): Readonly<{
44
30
  * @return object with revert method.
45
31
  */
46
32
  changeTranslation: (descriptor: import("./types").CacheDescriptor, key: string, value: string) => {
47
- revert(): void;
33
+ revert(): void; /**
34
+ * Manually load record from `Backend` (or `DevBackend` when in dev mode)
35
+ */
48
36
  };
49
37
  /**
50
38
  * Adds namespace(s) list of active namespaces. And if tolgee is running, loads required data.
@@ -57,41 +45,47 @@ declare function createTolgee(options: TolgeeOptions): Readonly<{
57
45
  * so this method will remove namespace only if the counter goes down to 0.
58
46
  */
59
47
  removeActiveNs: (ns: import("./types").NsFallback) => void;
48
+ /**
49
+ * Load records which would be loaded by `run` function
50
+ *
51
+ * You can provide language if not previously set on tolgee instance
52
+ */
53
+ loadRequired: (options?: import("./types").LoadRequiredOptions | undefined) => Promise<import("./types").CacheInternalRecord[]>;
54
+ /**
55
+ * Load records in matrix (languages x namespaces)
56
+ */
57
+ loadMatrix: (options: import("./types").LoadMatrixOptions) => Promise<import("./types").CacheInternalRecord[]>;
60
58
  /**
61
59
  * Manually load multiple records from `Backend` (or `DevBackend` when in dev mode)
62
60
  *
63
61
  * It loads data together and adds them to cache in one operation, to prevent partly loaded state.
64
62
  */
65
- loadRecords: (descriptors: import("./types").CacheDescriptor[]) => Promise<import("./types").TranslationsFlat[]>;
63
+ loadRecords: (descriptors: import("./types").CacheDescriptor[], options?: import("./types").LoadOptions | undefined) => Promise<import("./types").CacheInternalRecord[]>;
66
64
  /**
67
65
  * Manually load record from `Backend` (or `DevBackend` when in dev mode)
68
66
  */
69
- loadRecord: (descriptor: import("./types").CacheDescriptor) => Promise<import("./types").TranslationsFlat>;
67
+ loadRecord: (descriptor: import("./types").CacheDescriptor, options?: import("./types").LoadOptions | undefined) => Promise<import("./types").TranslationsFlat>;
70
68
  /**
71
69
  * Prefill static data
72
70
  */
73
- addStaticData: (data: import("./types").TolgeeStaticData | undefined) => void;
71
+ addStaticData: (data: import("./types").TolgeeStaticDataProp | undefined) => void;
74
72
  /**
75
73
  * Get record from cache.
76
74
  */
77
- getRecord: (descriptor: import("./types").CacheDescriptor) => import("./types").TranslationsFlat | undefined;
75
+ getRecord: (descriptor: import("./types").CacheDescriptor) => import("./types").CacheInternalRecord | undefined;
78
76
  /**
79
77
  * Get all records from cache.
80
78
  */
81
- getAllRecords: () => {
82
- data: import("./types").TranslationsFlat;
83
- language: string;
84
- namespace: string;
85
- }[];
79
+ getAllRecords: () => (import("./types").CacheInternalRecord | undefined)[];
86
80
  /**
87
81
  * @param ns optional list of namespaces that you are interested in
88
82
  * @return `true` if there are data that need to be fetched.
89
83
  */
90
84
  isLoaded: (ns?: import("./types").NsFallback) => boolean;
91
85
  /**
92
- * Returns records needed for instance to be `loaded`
86
+ * Returns descriptors of records needed for instance to be `loaded`
93
87
  */
94
- getRequiredRecords: (lang?: string | undefined, ns?: import("./types").NsFallback) => import("./types").CacheDescriptor[];
88
+ getRequiredDescriptors: (lang?: string | undefined, ns?: import("./types").NsFallback) => import("./types").CacheDescriptorInternal[];
95
89
  /**
96
90
  * @return `true` if tolgee is loading initial data (triggered by `run`).
97
91
  */
@@ -145,8 +139,9 @@ declare function createTolgee(options: TolgeeOptions): Readonly<{
145
139
  fallbackLanguage?: import("./types").FallbackLanguageOption;
146
140
  ns?: string[] | undefined;
147
141
  fallbackNs?: import("./types").FallbackGeneral;
148
- defaultNs: string;
149
- staticData?: import("./types").TolgeeStaticData | undefined;
142
+ defaultNs?: string | undefined;
143
+ availableNs?: string[] | undefined;
144
+ staticData?: import("./types").TolgeeStaticDataProp | undefined;
150
145
  observerType: "invisible" | "text";
151
146
  observerOptions: import("./types").ObserverOptionsInternal;
152
147
  onFormatError: import("./types").OnFormatError;
@@ -154,6 +149,8 @@ declare function createTolgee(options: TolgeeOptions): Readonly<{
154
149
  fetch: import("./types").FetchFn;
155
150
  tagNewKeys?: string[] | undefined;
156
151
  filterTag?: string[] | undefined;
152
+ autoLoadRequiredData: boolean;
153
+ disableCache: boolean;
157
154
  };
158
155
  /**
159
156
  * Tolgee is in dev mode if `DevTools` plugin is used and `apiKey` + `apiUrl` are specified.
package/lib/helpers.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { FallbackGeneral, FallbackLanguageOption, FetchFn, TolgeeError } from './types';
1
+ import { FallbackGeneral, FallbackLanguageOption, FetchFn, TolgeeError, ErrorEvent } from './types';
2
2
  import { EventEmitterInstance } from './Controller/Events/EventEmitter';
3
3
  export declare function isPromise(value: unknown): value is Promise<unknown>;
4
4
  export declare function valueOrPromise<T, R>(value: T | Promise<T>, callback: (value: T) => R): R | Promise<R>;
5
- export declare function handleRegularOrAsyncErr<T>(onError: EventEmitterInstance<TolgeeError>, createError: (e: any) => TolgeeError, callback: () => Promise<T> | T): Promise<T> | T;
5
+ export declare function handleRegularOrAsyncErr<T>(onError: EventEmitterInstance<ErrorEvent>, createError: (e: any) => TolgeeError, callback: () => Promise<T> | T): Promise<T> | T;
6
6
  export declare function missingOptionError(option: string | string[]): string;
7
7
  export declare function isObject(item: any): boolean;
8
8
  export declare function getFallback(value: FallbackGeneral): string[] | undefined;
@@ -1,5 +1,5 @@
1
1
  export type TranslationValue = string | undefined | null;
2
- export type TranslationsFlat = Map<string, TranslationValue>;
2
+ export type TranslationsFlat = Record<string, TranslationValue>;
3
3
  export type TreeTranslationsData = {
4
4
  [key: string]: TranslationValue | TreeTranslationsData;
5
5
  };
@@ -23,3 +23,21 @@ export type CachePublicRecord = {
23
23
  language: string;
24
24
  namespace: string;
25
25
  };
26
+ export type CacheInternalRecord = {
27
+ data: TranslationsFlat;
28
+ language: string;
29
+ namespace: string;
30
+ cacheKey: string;
31
+ };
32
+ export type LoadOptions = {
33
+ noDev?: boolean;
34
+ useCache?: boolean;
35
+ };
36
+ export type LoadRequiredOptions = LoadOptions & {
37
+ language?: string;
38
+ };
39
+ export type MatrixOptions = {
40
+ languages: string[] | 'all';
41
+ namespaces: string[] | 'all';
42
+ };
43
+ export type LoadMatrixOptions = LoadOptions & MatrixOptions;
@@ -1,23 +1,24 @@
1
- import type { NsFallback } from './general';
2
1
  import type { CacheDescriptorWithKey } from './cache';
3
2
  import { TolgeeError } from './errors';
4
3
  export type Subscription = {
5
4
  unsubscribe: () => void;
6
5
  };
7
- export type SubscriptionSelective = {
8
- unsubscribe: () => void;
9
- /**
10
- * Subscribes to namespace(s)
11
- * @param ns - namespace(s), if empty default namespace is used
12
- *
13
- * Can be used multiple times to subscribe for more.
14
- */
15
- subscribeNs(ns?: NsFallback): SubscriptionSelective;
16
- };
17
- export type ListenerEvent<T> = {
6
+ export type ListenerEvent<E extends string, T> = {
7
+ type: E;
18
8
  value: T;
19
9
  };
20
- export type Listener<T> = (e: ListenerEvent<T>) => void;
10
+ export type Handler<E extends ListenerEvent<string, any>> = (e: E) => void;
11
+ export type CombinedHandler<E extends ListenerEvent<string, any>> = (e: E[]) => void;
12
+ export type LanguageEvent = ListenerEvent<'language', string>;
13
+ export type PendingLanguageEvent = ListenerEvent<'pendingLanguage', string>;
14
+ export type LoadingEvent = ListenerEvent<'loading', boolean>;
15
+ export type FetchingEvent = ListenerEvent<'fetching', boolean>;
16
+ export type InitialLoadEvent = ListenerEvent<'initialLoad', void>;
17
+ export type RunningEvent = ListenerEvent<'running', boolean>;
18
+ export type CacheEvent = ListenerEvent<'cache', CacheDescriptorWithKey>;
19
+ export type ErrorEvent = ListenerEvent<'error', TolgeeError>;
20
+ export type PermanentChangeEvent = ListenerEvent<'permanentChange', TranslationDescriptor>;
21
+ export type UpdateEvent = LanguageEvent | CacheEvent | InitialLoadEvent;
21
22
  export type TolgeeEvent = 'language' | 'pendingLanguage' | 'loading' | 'fetching' | 'initialLoad' | 'running' | 'cache' | 'update' | 'permanentChange';
22
23
  export interface EventType {
23
24
  language: string;
@@ -36,43 +37,43 @@ export type TolgeeOn<E extends keyof EventType = keyof EventType> = {
36
37
  * Emitted when any key needs (or might need) to be re-rendered.
37
38
  * Similar to tolgee.onNsUpdate, except for all namespaces.
38
39
  */
39
- (event: 'update', handler: Listener<void>): Subscription;
40
+ (event: 'update', handler: CombinedHandler<UpdateEvent>): Subscription;
40
41
  /**
41
42
  * Emitted on language change.
42
43
  */
43
- (event: 'language', handler: Listener<string>): Subscription;
44
+ (event: 'language', handler: Handler<LanguageEvent>): Subscription;
44
45
  /**
45
46
  * Emitted on pendingLanguage change.
46
47
  */
47
- (event: 'pendingLanguage', handler: Listener<string>): Subscription;
48
+ (event: 'pendingLanguage', handler: Handler<PendingLanguageEvent>): Subscription;
48
49
  /**
49
50
  * Emitted on loading change. Changes when tolgee is loading some data for the first time.
50
51
  */
51
- (event: 'loading', handler: Listener<boolean>): Subscription;
52
+ (event: 'loading', handler: Handler<LoadingEvent>): Subscription;
52
53
  /**
53
54
  * Emitted on fetching change. Changes when tolgee is fetching any data.
54
55
  */
55
- (event: 'fetching', handler: Listener<boolean>): Subscription;
56
+ (event: 'fetching', handler: Handler<FetchingEvent>): Subscription;
56
57
  /**
57
58
  * Emitted when `tolgee.run` method finishes.
58
59
  */
59
- (event: 'initialLoad', handler: Listener<void>): Subscription;
60
+ (event: 'initialLoad', handler: Handler<InitialLoadEvent>): Subscription;
60
61
  /**
61
62
  * Emitted when internal `running` state changes.
62
63
  */
63
- (event: 'running', handler: Listener<boolean>): Subscription;
64
+ (event: 'running', handler: Handler<RunningEvent>): Subscription;
64
65
  /**
65
66
  * Emitted when cache changes.
66
67
  */
67
- (event: 'cache', handler: Listener<CacheDescriptorWithKey>): Subscription;
68
+ (event: 'cache', handler: Handler<CacheEvent>): Subscription;
68
69
  /**
69
70
  * Emitted on errors
70
71
  */
71
- (event: 'error', handler: Listener<TolgeeError>): Subscription;
72
+ (event: 'error', handler: Handler<ErrorEvent>): Subscription;
72
73
  /**
73
74
  * Translation was changed or created via dev tools
74
75
  */
75
- (event: 'permanentChange', handler: Listener<CacheDescriptorWithKey>): Subscription;
76
+ (event: 'permanentChange', handler: Handler<PermanentChangeEvent>): Subscription;
76
77
  (event: E, handler: unknown): Subscription;
77
78
  };
78
79
  export type TranslationDescriptor = {
@@ -3,6 +3,6 @@ export * from './events';
3
3
  export * from './cache';
4
4
  export * from './plugin';
5
5
  export * from './errors';
6
- export type { State, TolgeeOptions, TolgeeOptionsInternal, TolgeeStaticData, } from '../Controller/State/initState';
6
+ export type { State, TolgeeOptions, TolgeeOptionsInternal, TolgeeStaticData, TolgeeStaticDataProp, } from '../Controller/State/initState';
7
7
  export type { ObserverOptions, ObserverOptionsInternal, ModifierKey, } from '../Controller/State/observerOptions';
8
8
  export type { TolgeeChainer, TolgeeInstance } from '../TolgeeCore';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tolgee/core",
3
- "version": "5.33.2",
3
+ "version": "5.33.3-prerelease.2efc0e6b.0",
4
4
  "description": "Library providing ability to translate messages directly in context of developed application.",
5
5
  "main": "./dist/tolgee.cjs.js",
6
6
  "module": "./dist/tolgee.esm.js",
@@ -73,5 +73,5 @@
73
73
  "access": "public"
74
74
  },
75
75
  "sideEffects": false,
76
- "gitHead": "73467e06c29511cafab7e7162cef8ac4a36ff507"
76
+ "gitHead": "799332abc27675f19c1b722ac063cbe2451f500e"
77
77
  }
@@ -0,0 +1,189 @@
1
+ import { ListenerEvent } from '../../types';
2
+ import { EventEmitterInstance } from '../Events/EventEmitter';
3
+ import { ValueObserver } from '../ValueObserver';
4
+ import { Cache, CacheInstance } from './Cache';
5
+
6
+ describe('cache', () => {
7
+ function createEventMock(): EventEmitterInstance<ListenerEvent<any, any>> {
8
+ return {
9
+ emit: jest.fn(),
10
+ listen: jest.fn(),
11
+ };
12
+ }
13
+
14
+ let mockedBackendGetRecord: jest.Mock<any, any>;
15
+ let mockedBackendGetDevRecord: jest.Mock<any, any>;
16
+
17
+ let onFetchingChange: jest.Mock<any, any>;
18
+ let onLoadingChange: jest.Mock<any, any>;
19
+
20
+ let cache: CacheInstance;
21
+
22
+ beforeEach(() => {
23
+ const mockedEvents = {
24
+ on: jest.fn(),
25
+ onCacheChange: createEventMock(),
26
+ onError: createEventMock(),
27
+ onFetchingChange: createEventMock(),
28
+ onInitialLoaded: createEventMock(),
29
+ onLanguageChange: createEventMock(),
30
+ onLoadingChange: createEventMock(),
31
+ onPendingLanguageChange: createEventMock(),
32
+ onPermanentChange: createEventMock(),
33
+ onRunningChange: createEventMock(),
34
+ onUpdate: createEventMock() as any,
35
+ setEmitterActive: jest.fn(),
36
+ };
37
+
38
+ mockedBackendGetRecord = jest.fn((args) => {
39
+ return Promise.resolve({ data: 'Prod', ...args });
40
+ });
41
+ mockedBackendGetDevRecord = jest.fn((args) => {
42
+ return Promise.resolve({ data: 'Dev', ...args });
43
+ });
44
+
45
+ onFetchingChange = jest.fn();
46
+ onLoadingChange = jest.fn();
47
+
48
+ const fetchingObserver = ValueObserver(
49
+ false,
50
+ () => cache.isFetching(),
51
+ onFetchingChange
52
+ );
53
+
54
+ const loadingObserver = ValueObserver(
55
+ false,
56
+ () => cache.isLoading('en'),
57
+ onLoadingChange
58
+ );
59
+
60
+ cache = Cache(
61
+ mockedEvents,
62
+ mockedBackendGetRecord,
63
+ mockedBackendGetDevRecord,
64
+ (descriptor) => ({ namespace: '', ...descriptor }),
65
+ () => false,
66
+ () => false,
67
+ fetchingObserver,
68
+ loadingObserver
69
+ );
70
+ });
71
+
72
+ it('fetches language with default namespace', async () => {
73
+ const result = await cache.loadRecords([{ language: 'en' }]);
74
+ expect(result[0].data).toEqual({
75
+ language: 'en',
76
+ namespace: '',
77
+ data: 'Dev',
78
+ });
79
+ });
80
+
81
+ it('fetches language with specified namespace', async () => {
82
+ const result = await cache.loadRecords([
83
+ { language: 'en', namespace: 'test' },
84
+ ]);
85
+ expect(result[0].data).toEqual({
86
+ language: 'en',
87
+ namespace: 'test',
88
+ data: 'Dev',
89
+ });
90
+ });
91
+
92
+ it('fetches language with specified namespace', async () => {
93
+ const result = await cache.loadRecords([
94
+ { language: 'en', namespace: 'test' },
95
+ ]);
96
+ expect(result[0].data).toEqual({
97
+ language: 'en',
98
+ namespace: 'test',
99
+ data: 'Dev',
100
+ });
101
+ });
102
+
103
+ it('uses cache when fetching twice the same thing', async () => {
104
+ await cache.loadRecords([{ language: 'en' }]);
105
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(1);
106
+ const result = await cache.loadRecords([{ language: 'en' }], {
107
+ useCache: true,
108
+ });
109
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(1);
110
+ expect(result[0].data).toEqual({
111
+ language: 'en',
112
+ namespace: '',
113
+ data: 'Dev',
114
+ });
115
+ });
116
+
117
+ it('uses cache when fetching twice production data', async () => {
118
+ await cache.loadRecords([{ language: 'en' }], { noDev: true });
119
+ expect(mockedBackendGetRecord).toBeCalledTimes(1);
120
+ const result = await cache.loadRecords([{ language: 'en' }], {
121
+ noDev: true,
122
+ useCache: true,
123
+ });
124
+ expect(mockedBackendGetRecord).toBeCalledTimes(1);
125
+ expect(result[0].data).toEqual({
126
+ language: 'en',
127
+ namespace: '',
128
+ data: 'Prod',
129
+ });
130
+ });
131
+
132
+ it('does not use cache when `noCache` is on', async () => {
133
+ await cache.loadRecords([{ language: 'en' }]);
134
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(1);
135
+ await cache.loadRecords([{ language: 'en' }]);
136
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(2);
137
+ });
138
+
139
+ it('correctly returns combination of non-cached and cached', async () => {
140
+ await cache.loadRecords([{ language: 'en' }]);
141
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(1);
142
+ const result = await cache.loadRecords(
143
+ [{ language: 'en' }, { language: 'en', namespace: 'new' }],
144
+ { useCache: true }
145
+ );
146
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(2);
147
+ expect(result).toEqual([
148
+ {
149
+ cacheKey: 'en',
150
+ data: { data: 'Dev', language: 'en', namespace: '' },
151
+ language: 'en',
152
+ namespace: '',
153
+ },
154
+ {
155
+ cacheKey: 'en:new',
156
+ data: { data: 'Dev', language: 'en', namespace: 'new' },
157
+ language: 'en',
158
+ namespace: 'new',
159
+ },
160
+ ]);
161
+ });
162
+
163
+ it('correctly refetches dev data', async () => {
164
+ await cache.loadRecords([{ language: 'en' }], { noDev: true });
165
+ expect(mockedBackendGetRecord).toBeCalledTimes(1);
166
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(0);
167
+ cache.invalidate();
168
+ const result = await cache.loadRecords([{ language: 'en' }]);
169
+ expect(mockedBackendGetRecord).toBeCalledTimes(1);
170
+ expect(mockedBackendGetDevRecord).toBeCalledTimes(1);
171
+ expect(result[0].data).toEqual({
172
+ language: 'en',
173
+ namespace: '',
174
+ data: 'Dev',
175
+ });
176
+ });
177
+
178
+ it('correctly notifies about fetching and loading', async () => {
179
+ expect(onLoadingChange).toBeCalledTimes(0);
180
+ expect(onFetchingChange).toBeCalledTimes(0);
181
+ await cache.loadRecords([{ language: 'en' }]);
182
+ expect(onLoadingChange).toBeCalledTimes(2);
183
+ expect(onFetchingChange).toBeCalledTimes(2);
184
+ cache.invalidate();
185
+ await cache.loadRecords([{ language: 'en' }]);
186
+ expect(onFetchingChange).toBeCalledTimes(4);
187
+ expect(onLoadingChange).toBeCalledTimes(2);
188
+ });
189
+ });