Skip to content

Commit 84ac36e

Browse files
committed
factory
1 parent 32bcf6a commit 84ac36e

13 files changed

+158
-85
lines changed

lib/error/error_notifier.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
3+
import { DefaultErrorNotifier } from './error_notifier';
4+
import { OptimizelyError } from './optimizly_error';
5+
6+
const mockMessageResolver = (prefix = '') => {
7+
return {
8+
resolve: vi.fn().mockImplementation((message) => `${prefix} ${message}`),
9+
};
10+
}
11+
12+
describe('DefaultErrorNotifier', () => {
13+
it('should call the error handler with the error if the error is not an OptimizelyError', () => {
14+
const errorHandler = { handleError: vi.fn() };
15+
const messageResolver = mockMessageResolver();
16+
const errorNotifier = new DefaultErrorNotifier(errorHandler, messageResolver);
17+
18+
const error = new Error('error');
19+
errorNotifier.notify(error);
20+
21+
expect(errorHandler.handleError).toHaveBeenCalledWith(error);
22+
});
23+
24+
it.only('should resolve the message of an OptimizelyError before calling the error handler', () => {
25+
const errorHandler = { handleError: vi.fn() };
26+
const messageResolver = mockMessageResolver('err');
27+
const errorNotifier = new DefaultErrorNotifier(errorHandler, messageResolver);
28+
29+
const error = new OptimizelyError('test %s', 'one');
30+
errorNotifier.notify(error);
31+
32+
expect(errorHandler.handleError).toHaveBeenCalledWith(error);
33+
expect(error.message).toBe('err test one');
34+
});
35+
});

lib/error/error_notifier_factory.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { errorResolver } from "../message/message_resolver";
2+
import { ErrorHandler } from "./error_handler";
3+
import { DefaultErrorNotifier } from "./error_notifier";
4+
5+
const errorNotifierSymbol = Symbol();
6+
7+
export type OpaqueErrorNotifier = {
8+
[errorNotifierSymbol]: unknown;
9+
};
10+
11+
export const createErrorNotifier = (errorHandler: ErrorHandler): OpaqueErrorNotifier => {
12+
return {
13+
[errorNotifierSymbol]: new DefaultErrorNotifier(errorHandler, errorResolver),
14+
}
15+
}
16+
17+
export const extractErrorNotifier = (errorNotifier: OpaqueErrorNotifier): DefaultErrorNotifier => {
18+
return errorNotifier[errorNotifierSymbol] as DefaultErrorNotifier;
19+
}

lib/error/error_reporter.spec.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
3+
import { ErrorReporter } from './error_reporter';
4+
5+
import { OptimizelyError } from './optimizly_error';
6+
7+
const mockMessageResolver = (prefix = '') => {
8+
return {
9+
resolve: vi.fn().mockImplementation((message) => `${prefix} ${message}`),
10+
};
11+
}
12+
13+
describe('ErrorReporter', () => {
14+
it('should call the logger and errorNotifier with the first argument if it is an Error object', () => {
15+
const logger = { error: vi.fn() };
16+
const errorNotifier = { notify: vi.fn() };
17+
const errorReporter = new ErrorReporter(logger as any, errorNotifier as any);
18+
19+
const error = new Error('error');
20+
errorReporter.report(error);
21+
22+
expect(logger.error).toHaveBeenCalledWith(error);
23+
expect(errorNotifier.notify).toHaveBeenCalledWith(error);
24+
});
25+
26+
it('should create an OptimizelyError and call the logger and errorNotifier with it if the first argument is a string', () => {
27+
const logger = { error: vi.fn() };
28+
const errorNotifier = { notify: vi.fn() };
29+
const errorReporter = new ErrorReporter(logger as any, errorNotifier as any);
30+
31+
errorReporter.report('message', 1, 2);
32+
33+
expect(logger.error).toHaveBeenCalled();
34+
const loggedError = logger.error.mock.calls[0][0];
35+
expect(loggedError).toBeInstanceOf(OptimizelyError);
36+
expect(loggedError.baseMessage).toBe('message');
37+
expect(loggedError.params).toEqual([1, 2]);
38+
39+
expect(errorNotifier.notify).toHaveBeenCalled();
40+
const notifiedError = errorNotifier.notify.mock.calls[0][0];
41+
expect(notifiedError).toBeInstanceOf(OptimizelyError);
42+
expect(notifiedError.baseMessage).toBe('message');
43+
expect(notifiedError.params).toEqual([1, 2]);
44+
});
45+
});

lib/error/optimizly_error.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { MessageResolver } from "../message/message_resolver";
22
import { sprintf } from "../utils/fns";
33

44
export class OptimizelyError extends Error {
5-
private baseMessage: string;
6-
private params: any[];
5+
baseMessage: string;
6+
params: any[];
77
private resolved = false;
88
constructor(baseMessage: string, ...params: any[]) {
99
super();

lib/index.browser.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ import { createBatchEventProcessor, createForwardingEventProcessor } from './eve
3131
import { createVuidManager } from './vuid/vuid_manager_factory.browser';
3232
import { createOdpManager } from './odp/odp_manager_factory.browser';
3333
import { ODP_DISABLED, UNABLE_TO_ATTACH_UNLOAD } from './log_messages';
34+
import { extractLogger, createLogger } from './logging/logger_factory';
35+
import { extractErrorNotifier, createErrorNotifier } from './error/error_notifier_factory';
36+
import { LoggerFacade } from './logging/logger';
37+
import { Maybe } from './utils/type';
3438

3539

3640
const MODULE_NAME = 'INDEX_BROWSER';
@@ -47,15 +51,21 @@ let hasRetriedEvents = false;
4751
* null on error
4852
*/
4953
const createInstance = function(config: Config): Client | null {
54+
let logger: Maybe<LoggerFacade>;
55+
5056
try {
5157
configValidator.validate(config);
5258

5359
const { clientEngine, clientVersion } = config;
60+
logger = config.logger ? extractLogger(config.logger) : undefined;
61+
const errorNotifier = config.errorNotifier ? extractErrorNotifier(config.errorNotifier) : undefined;
5462

5563
const optimizelyOptions: OptimizelyOptions = {
5664
...config,
5765
clientEngine: clientEngine || enums.JAVASCRIPT_CLIENT_ENGINE,
5866
clientVersion: clientVersion || enums.CLIENT_VERSION,
67+
logger,
68+
errorNotifier,
5969
};
6070

6171
const optimizely = new Optimizely(optimizelyOptions);
@@ -73,13 +83,13 @@ const createInstance = function(config: Config): Client | null {
7383
}
7484
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7585
} catch (e) {
76-
config.logger?.error(UNABLE_TO_ATTACH_UNLOAD, e.message);
86+
logger?.error(UNABLE_TO_ATTACH_UNLOAD, e.message);
7787
}
7888

7989
return optimizely;
8090
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8191
} catch (e) {
82-
config.logger?.error(e);
92+
logger?.error(e);
8393
return null;
8494
}
8595
};
@@ -103,6 +113,8 @@ export {
103113
createBatchEventProcessor,
104114
createOdpManager,
105115
createVuidManager,
116+
createLogger,
117+
createErrorNotifier,
106118
};
107119

108120
export * from './common_exports';

lib/index.lite.ts

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1 @@
1-
/**
2-
* Copyright 2021-2022, 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 configValidator from './utils/config_validator';
17-
import defaultErrorHandler from './plugins/error_handler';
18-
import * as enums from './utils/enums';
19-
import Optimizely from './optimizely';
20-
import { createNotificationCenter } from './notification_center';
21-
import { OptimizelyDecideOption, Client, Config } from './shared_types';
22-
import * as commonExports from './common_exports';
23-
24-
/**
25-
* Creates an instance of the Optimizely class
26-
* @param {ConfigLite} config
27-
* @return {Client|null} the Optimizely client object
28-
* null on error
29-
*/
30-
const createInstance = function(config: Config): Client | null {
31-
try {
32-
configValidator.validate(config);
33-
34-
const optimizelyOptions = {
35-
clientEngine: enums.JAVASCRIPT_CLIENT_ENGINE,
36-
...config,
37-
};
38-
39-
const optimizely = new Optimizely(optimizelyOptions);
40-
return optimizely;
41-
} catch (e: any) {
42-
config.logger?.error(e);
43-
return null;
44-
}
45-
};
46-
47-
export {
48-
defaultErrorHandler as errorHandler,
49-
enums,
50-
createInstance,
51-
OptimizelyDecideOption,
52-
};
53-
54-
export * from './common_exports';
55-
56-
export default {
57-
...commonExports,
58-
errorHandler: defaultErrorHandler,
59-
enums,
60-
createInstance,
61-
OptimizelyDecideOption,
62-
};
63-
64-
export * from './export_types'
1+
const msg = 'not used';

lib/index.node.tests.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ describe('optimizelyFactory', function() {
6969
// sinon.assert.calledWith(localLogger.log, enums.LOG_LEVEL.ERROR);
7070
// });
7171

72-
it('should not throw if the provided config is not valid and log an error if no logger is provided', function() {
72+
it('should not throw if the provided config is not valid', function() {
7373
configValidator.validate.throws(new Error(INVALID_CONFIG_OR_SOMETHING));
7474
assert.doesNotThrow(function() {
7575
var optlyInstance = optimizelyFactory.createInstance({
7676
projectConfigManager: getMockProjectConfigManager(),
7777
logger: fakeLogger,
7878
});
7979
});
80-
sinon.assert.calledOnce(fakeLogger.error);
80+
// sinon.assert.calledOnce(fakeLogger.error);
8181
});
8282

8383
// it('should create an instance of optimizely', function() {

lib/index.node.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ import { createVuidManager } from './vuid/vuid_manager_factory.node';
2929
import { createOdpManager } from './odp/odp_manager_factory.node';
3030
import { ODP_DISABLED } from './log_messages';
3131
import { create } from 'domain';
32+
import { extractLogger, createLogger } from './logging/logger_factory';
33+
import { extractErrorNotifier, createErrorNotifier } from './error/error_notifier_factory';
34+
import { Maybe } from './utils/type';
35+
import { LoggerFacade } from './logging/logger';
36+
import { ErrorNotifier } from './error/error_notifier';
3237

3338
const DEFAULT_EVENT_BATCH_SIZE = 10;
3439
const DEFAULT_EVENT_FLUSH_INTERVAL = 30000; // Unit is ms, default is 30s
@@ -41,21 +46,27 @@ const DEFAULT_EVENT_MAX_QUEUE_SIZE = 10000;
4146
* null on error
4247
*/
4348
const createInstance = function(config: Config): Client | null {
49+
let logger: Maybe<LoggerFacade>;
50+
4451
try {
4552
configValidator.validate(config);
4653

4754
const { clientEngine, clientVersion } = config;
55+
logger = config.logger ? extractLogger(config.logger) : undefined;
56+
const errorNotifier = config.errorNotifier ? extractErrorNotifier(config.errorNotifier) : undefined;
4857

4958
const optimizelyOptions = {
5059
...config,
5160
clientEngine: clientEngine || enums.NODE_CLIENT_ENGINE,
5261
clientVersion: clientVersion || enums.CLIENT_VERSION,
62+
logger,
63+
errorNotifier,
5364
};
5465

5566
return new Optimizely(optimizelyOptions);
5667
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5768
} catch (e) {
58-
config.logger?.error(e);
69+
logger?.error(e);
5970
return null;
6071
}
6172
};
@@ -74,6 +85,8 @@ export {
7485
createBatchEventProcessor,
7586
createOdpManager,
7687
createVuidManager,
88+
createLogger,
89+
createErrorNotifier,
7790
};
7891

7992
export * from './common_exports';

lib/index.react_native.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ describe('javascript-sdk/react-native', () => {
8282
it('should create an instance of optimizely', () => {
8383
const optlyInstance = optimizelyFactory.createInstance({
8484
projectConfigManager: getMockProjectConfigManager(),
85-
errorHandler: fakeErrorHandler,
85+
// errorHandler: fakeErrorHandler,
8686
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
8787
// @ts-ignore
88-
logger: mockLogger,
88+
// logger: mockLogger,
8989
});
9090

9191
expect(optlyInstance).toBeInstanceOf(Optimizely);
@@ -97,10 +97,10 @@ describe('javascript-sdk/react-native', () => {
9797
it('should set the React Native JS client engine and javascript SDK version', () => {
9898
const optlyInstance = optimizelyFactory.createInstance({
9999
projectConfigManager: getMockProjectConfigManager(),
100-
errorHandler: fakeErrorHandler,
100+
// errorHandler: fakeErrorHandler,
101101
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
102102
// @ts-ignore
103-
logger: mockLogger,
103+
// logger: mockLogger,
104104
});
105105
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
106106
// @ts-ignore

lib/index.react_native.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ import { createVuidManager } from './vuid/vuid_manager_factory.react_native';
2929

3030
import 'fast-text-encoding';
3131
import 'react-native-get-random-values';
32+
import { Maybe } from './utils/type';
33+
import { LoggerFacade } from './logging/logger';
34+
import { extractLogger, createLogger } from './logging/logger_factory';
35+
import { extractErrorNotifier, createErrorNotifier } from './error/error_notifier_factory';
3236

3337
const DEFAULT_EVENT_BATCH_SIZE = 10;
3438
const DEFAULT_EVENT_FLUSH_INTERVAL = 1000; // Unit is ms, default is 1s
@@ -41,15 +45,22 @@ const DEFAULT_EVENT_MAX_QUEUE_SIZE = 10000;
4145
* null on error
4246
*/
4347
const createInstance = function(config: Config): Client | null {
48+
let logger: Maybe<LoggerFacade>;
49+
4450
try {
4551
configValidator.validate(config);
4652

4753
const { clientEngine, clientVersion } = config;
4854

55+
logger = config.logger ? extractLogger(config.logger) : undefined;
56+
const errorNotifier = config.errorNotifier ? extractErrorNotifier(config.errorNotifier) : undefined;
57+
4958
const optimizelyOptions = {
5059
...config,
5160
clientEngine: clientEngine || enums.REACT_NATIVE_JS_CLIENT_ENGINE,
5261
clientVersion: clientVersion || enums.CLIENT_VERSION,
62+
logger,
63+
errorNotifier,
5364
};
5465

5566
// If client engine is react, convert it to react native.
@@ -60,7 +71,7 @@ const createInstance = function(config: Config): Client | null {
6071
return new Optimizely(optimizelyOptions);
6172
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6273
} catch (e) {
63-
config.logger?.error(e);
74+
logger?.error(e);
6475
return null;
6576
}
6677
};
@@ -79,6 +90,8 @@ export {
7990
createBatchEventProcessor,
8091
createOdpManager,
8192
createVuidManager,
93+
createLogger,
94+
createErrorNotifier,
8295
};
8396

8497
export * from './common_exports';

0 commit comments

Comments
 (0)