Skip to content

Commit 8d73fad

Browse files
committed
react naive
1 parent 7bb5c64 commit 8d73fad

6 files changed

+408
-19
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Copyright 2024, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { getForwardingEventProcessor } from './forwarding_event_processor';
18+
import { EventDispatcher } from './eventDispatcher';
19+
import { EventProcessor } from './eventProcessor';
20+
import { EventWithId } from './batch_event_processor';
21+
import { getBatchEventProcessor, BatchEventProcessorOptions } from './event_processor_factory';
22+
import defaultEventDispatcher from './default_dispatcher.browser';
23+
import sendBeaconEventDispatcher from '../plugins/event_dispatcher/send_beacon_dispatcher';
24+
import { LocalStorageCache } from '../utils/cache/local_storage_cache.browser';
25+
import { SyncPrefixCache } from '../utils/cache/cache';
26+
27+
export const FAILED_EVENT_RETRY_INTERVAL = 20 * 1000;
28+
export const EVENT_STORE_PREFIX = 'optly_event:';
29+
30+
export const createForwardingEventProcessor = (
31+
eventDispatcher: EventDispatcher = defaultEventDispatcher,
32+
): EventProcessor => {
33+
return getForwardingEventProcessor(eventDispatcher);
34+
};
35+
36+
const identity = <T>(v: T): T => v;
37+
38+
export const createBatchEventProcessor = (
39+
options: BatchEventProcessorOptions
40+
): EventProcessor => {
41+
const localStorageCache = new LocalStorageCache<EventWithId>();
42+
const eventStore = new SyncPrefixCache<EventWithId, EventWithId>(
43+
localStorageCache, EVENT_STORE_PREFIX,
44+
identity,
45+
identity,
46+
);
47+
48+
return getBatchEventProcessor({
49+
eventDispatcher: options.eventDispatcher || defaultEventDispatcher,
50+
closingEventDispatcher: options.closingEventDispatcher ||
51+
(options.eventDispatcher ? undefined : sendBeaconEventDispatcher),
52+
flushInterval: options.flushInterval,
53+
batchSize: options.batchSize,
54+
retryOptions: {
55+
maxRetries: 5,
56+
},
57+
failedEventRetryInterval: FAILED_EVENT_RETRY_INTERVAL,
58+
eventStore,
59+
});
60+
};
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/**
2+
* Copyright 2024, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { vi, describe, it, expect, beforeEach } from 'vitest';
17+
18+
vi.mock('./default_dispatcher.browser', () => {
19+
return { default: {} };
20+
});
21+
22+
vi.mock('./forwarding_event_processor', () => {
23+
const getForwardingEventProcessor = vi.fn().mockImplementation(() => {
24+
return {};
25+
});
26+
return { getForwardingEventProcessor };
27+
});
28+
29+
vi.mock('./event_processor_factory', () => {
30+
const getBatchEventProcessor = vi.fn().mockImplementation(() => {
31+
return {};
32+
});
33+
return { getBatchEventProcessor };
34+
});
35+
36+
vi.mock('../utils/cache/local_storage_cache.browser', () => {
37+
return { LocalStorageCache: vi.fn() };
38+
});
39+
40+
vi.mock('../utils/cache/cache', () => {
41+
return { SyncPrefixCache: vi.fn() };
42+
});
43+
44+
45+
import defaultEventDispatcher from './default_dispatcher.browser';
46+
import { LocalStorageCache } from '../utils/cache/local_storage_cache.browser';
47+
import { SyncPrefixCache } from '../utils/cache/cache';
48+
import { createForwardingEventProcessor, createBatchEventProcessor, EVENT_STORE_PREFIX, FAILED_EVENT_RETRY_INTERVAL } from './event_processor_factory.browser';
49+
import sendBeaconEventDispatcher from '../plugins/event_dispatcher/send_beacon_dispatcher';
50+
import { getForwardingEventProcessor } from './forwarding_event_processor';
51+
import browserDefaultEventDispatcher from './default_dispatcher.browser';
52+
import { getBatchEventProcessor } from './event_processor_factory';
53+
54+
describe('createForwardingEventProcessor', () => {
55+
const mockGetForwardingEventProcessor = vi.mocked(getForwardingEventProcessor);
56+
57+
beforeEach(() => {
58+
mockGetForwardingEventProcessor.mockClear();
59+
});
60+
61+
it('returns forwarding event processor by calling getForwardingEventProcessor with the provided dispatcher', () => {
62+
const eventDispatcher = {
63+
dispatchEvent: vi.fn(),
64+
};
65+
66+
const processor = createForwardingEventProcessor(eventDispatcher);
67+
68+
expect(Object.is(processor, mockGetForwardingEventProcessor.mock.results[0].value)).toBe(true);
69+
expect(mockGetForwardingEventProcessor).toHaveBeenNthCalledWith(1, eventDispatcher);
70+
});
71+
72+
it('uses the browser default event dispatcher if none is provided', () => {
73+
const processor = createForwardingEventProcessor();
74+
75+
expect(Object.is(processor, mockGetForwardingEventProcessor.mock.results[0].value)).toBe(true);
76+
expect(mockGetForwardingEventProcessor).toHaveBeenNthCalledWith(1, browserDefaultEventDispatcher);
77+
});
78+
});
79+
80+
describe('createBatchEventProcessor', () => {
81+
const mockGetBatchEventProcessor = vi.mocked(getBatchEventProcessor);
82+
const MockLocalStorageCache = vi.mocked(LocalStorageCache);
83+
const MockSyncPrefixCache = vi.mocked(SyncPrefixCache);
84+
85+
beforeEach(() => {
86+
mockGetBatchEventProcessor.mockClear();
87+
MockLocalStorageCache.mockClear();
88+
MockSyncPrefixCache.mockClear();
89+
});
90+
91+
it('uses localStorageCache and SyncPrefixCache to create eventStore', () => {
92+
const options = {
93+
eventDispatcher: {
94+
dispatchEvent: vi.fn(),
95+
},
96+
flushInterval: 1000,
97+
batchSize: 10,
98+
};
99+
100+
const processor = createBatchEventProcessor(options);
101+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
102+
const eventStore = mockGetBatchEventProcessor.mock.calls[0][0].eventStore;
103+
expect(Object.is(eventStore, MockSyncPrefixCache.mock.results[0].value)).toBe(true);
104+
105+
const [cache, prefix, transformGet, transformSet] = MockSyncPrefixCache.mock.calls[0];
106+
expect(Object.is(cache, MockLocalStorageCache.mock.results[0].value)).toBe(true);
107+
expect(prefix).toBe(EVENT_STORE_PREFIX);
108+
109+
// transformGet and transformSet should be identity functions
110+
expect(transformGet('value')).toBe('value');
111+
expect(transformSet('value')).toBe('value');
112+
});
113+
114+
it('uses the provided eventDispatcher', () => {
115+
const eventDispatcher = {
116+
dispatchEvent: vi.fn(),
117+
};
118+
119+
const processor = createBatchEventProcessor({ eventDispatcher });
120+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
121+
expect(mockGetBatchEventProcessor.mock.calls[0][0].eventDispatcher).toBe(eventDispatcher);
122+
});
123+
124+
it('uses the default broser event dispatcher if none is provided', () => {
125+
const processor = createBatchEventProcessor({ });
126+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
127+
expect(mockGetBatchEventProcessor.mock.calls[0][0].eventDispatcher).toBe(defaultEventDispatcher);
128+
});
129+
130+
it('uses the provided closingEventDispatcher', () => {
131+
const closingEventDispatcher = {
132+
dispatchEvent: vi.fn(),
133+
};
134+
135+
const processor = createBatchEventProcessor({ closingEventDispatcher });
136+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
137+
expect(mockGetBatchEventProcessor.mock.calls[0][0].closingEventDispatcher).toBe(closingEventDispatcher);
138+
});
139+
140+
it('does not use any closingEventDispatcher if eventDispatcher is provided but closingEventDispatcher is not', () => {
141+
const eventDispatcher = {
142+
dispatchEvent: vi.fn(),
143+
};
144+
145+
const processor = createBatchEventProcessor({ eventDispatcher });
146+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
147+
expect(mockGetBatchEventProcessor.mock.calls[0][0].closingEventDispatcher).toBe(undefined);
148+
});
149+
150+
it('uses the default sendBeacon event dispatcher if neither eventDispatcher nor closingEventDispatcher is provided', () => {
151+
const processor = createBatchEventProcessor({ });
152+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
153+
expect(mockGetBatchEventProcessor.mock.calls[0][0].closingEventDispatcher).toBe(sendBeaconEventDispatcher);
154+
});
155+
156+
it('uses the provided flushInterval', () => {
157+
const processor1 = createBatchEventProcessor({ flushInterval: 2000 });
158+
expect(Object.is(processor1, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
159+
expect(mockGetBatchEventProcessor.mock.calls[0][0].flushInterval).toBe(2000);
160+
161+
const processor2 = createBatchEventProcessor({ });
162+
expect(Object.is(processor2, mockGetBatchEventProcessor.mock.results[1].value)).toBe(true);
163+
expect(mockGetBatchEventProcessor.mock.calls[1][0].flushInterval).toBe(undefined);
164+
});
165+
166+
it('uses the provided batchSize', () => {
167+
const processor1 = createBatchEventProcessor({ batchSize: 20 });
168+
expect(Object.is(processor1, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
169+
expect(mockGetBatchEventProcessor.mock.calls[0][0].batchSize).toBe(20);
170+
171+
const processor2 = createBatchEventProcessor({ });
172+
expect(Object.is(processor2, mockGetBatchEventProcessor.mock.results[1].value)).toBe(true);
173+
expect(mockGetBatchEventProcessor.mock.calls[1][0].batchSize).toBe(undefined);
174+
});
175+
176+
it('uses maxRetries value of 5', () => {
177+
const processor = createBatchEventProcessor({ });
178+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
179+
expect(mockGetBatchEventProcessor.mock.calls[0][0].retryOptions?.maxRetries).toBe(5);
180+
});
181+
182+
it('uses the default failedEventRetryInterval', () => {
183+
const processor = createBatchEventProcessor({ });
184+
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
185+
expect(mockGetBatchEventProcessor.mock.calls[0][0].failedEventRetryInterval).toBe(FAILED_EVENT_RETRY_INTERVAL);
186+
});
187+
});

lib/event_processor/event_processor_factory.browser.spec.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ vi.mock('./event_processor_factory', () => {
3030
const getBatchEventProcessor = vi.fn().mockImplementation(() => {
3131
return {};
3232
});
33-
return { getBatchEventProcessor };
33+
return { getBatchEventProcessor, EVENT_STORE_PREFIX: 'test_prefix', FAILED_EVENT_RETRY_INTERVAL: 1000 };
3434
});
3535

3636
vi.mock('../utils/cache/local_storage_cache.browser', () => {
@@ -89,16 +89,8 @@ describe('createBatchEventProcessor', () => {
8989
MockSyncPrefixCache.mockClear();
9090
});
9191

92-
it('uses localStorageCache and SyncPrefixCache to create eventStore', () => {
93-
const options = {
94-
eventDispatcher: {
95-
dispatchEvent: vi.fn(),
96-
},
97-
flushInterval: 1000,
98-
batchSize: 10,
99-
};
100-
101-
const processor = createBatchEventProcessor(options);
92+
it('uses LocalStorageCache and SyncPrefixCache to create eventStore', () => {
93+
const processor = createBatchEventProcessor({});
10294
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
10395
const eventStore = mockGetBatchEventProcessor.mock.calls[0][0].eventStore;
10496
expect(Object.is(eventStore, MockSyncPrefixCache.mock.results[0].value)).toBe(true);
@@ -122,7 +114,7 @@ describe('createBatchEventProcessor', () => {
122114
expect(mockGetBatchEventProcessor.mock.calls[0][0].eventDispatcher).toBe(eventDispatcher);
123115
});
124116

125-
it('uses the default broser event dispatcher if none is provided', () => {
117+
it('uses the default browser event dispatcher if none is provided', () => {
126118
const processor = createBatchEventProcessor({ });
127119
expect(Object.is(processor, mockGetBatchEventProcessor.mock.results[0].value)).toBe(true);
128120
expect(mockGetBatchEventProcessor.mock.calls[0][0].eventDispatcher).toBe(defaultEventDispatcher);

0 commit comments

Comments
 (0)