-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default uninitialized EppoClient instance #48
Conversation
**Signature:** | ||
|
||
```typescript | ||
static initialized: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs got updated because the way index.ts
is structured, initialized
has to be public π
@@ -4,7 +4,7 @@ | |||
|
|||
## IClientConfig.throwOnFailedInitialization property | |||
|
|||
Throw on error if unable to fetch an initial configuration during initialization. (default: true) | |||
Throw an error if unable to fetch an initial configuration during initialization. (default: true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Grammar! π
package.json
Outdated
@@ -58,7 +58,7 @@ | |||
"xhr-mock": "^2.5.1" | |||
}, | |||
"dependencies": { | |||
"@eppo/js-client-sdk-common": "2.1.0", | |||
"@eppo/js-client-sdk-common": "file:../js-client-sdk-common", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be replaced with "2.1.1"
once published
@@ -379,7 +382,7 @@ describe('EppoJSClient E2E test', () => { | |||
flags: { | |||
[hashedFlagKey]: mockExperimentConfig, | |||
}, | |||
}; | |||
} as unknown as Record<string, IExperimentConfiguration>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeScript insisted on the double as
because we are wiling out with our types here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I've seen typescript do this to me before
jest.isolateModules(() => { | ||
// Isolate and re-require so that the static instance is reset to it's default state | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const reloadedModule = require('./index'); | ||
init = reloadedModule.init; | ||
getInstance = reloadedModule.getInstance; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isolateModules()
and require()
combo to reset the static EppoJSClient instance took me a bit to figure out and it had weird side effects, such as making test double (td
) not work (hence me using returnRac()
instead of mocking a response like other tests cases). Also, using this outside of a beforeEach()
--which I did at first because I just have one test case--results in console.log()
not actually logging anything π€―
TL;DR; use singletons and jest.isolateModules()
with extreme caution, but it is a potentially useful tool to have your toolbox.
@@ -69,12 +69,15 @@ export interface IClientConfig { | |||
|
|||
export { IAssignmentLogger, IAssignmentEvent, IEppoClient } from '@eppo/js-client-sdk-common'; | |||
|
|||
const localStorage = new EppoLocalStorage(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this back to the module-level (where it was) so it can be used in the static initialization of EppoJSClient.instance
@@ -83,6 +86,7 @@ export class EppoJSClient extends EppoClient { | |||
subjectAttributes?: Record<string, any>, | |||
assignmentHooks?: IAssignmentHooks, | |||
): string | null { | |||
EppoJSClient.getAssignmentInitializationCheck(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we do want to warn people who request assignments on uninitialized instances.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, we can mute it in the future if requested. Currently the greater issue seems to be confusion about unexpected null returns
if (!EppoJSClient.instance) { | ||
throw Error('init() must first be called to initialize a client instance'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Farewell...for now... π’
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the intention of alerting if the SDK is functioning in an unintended way, but I won't miss the risk of throwing exceptions in client code
@@ -379,7 +382,7 @@ describe('EppoJSClient E2E test', () => { | |||
flags: { | |||
[hashedFlagKey]: mockExperimentConfig, | |||
}, | |||
}; | |||
} as unknown as Record<string, IExperimentConfiguration>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I've seen typescript do this to me before
let getInstance: Function; | ||
beforeEach(() => { | ||
jest.isolateModules(() => { | ||
// Isolate and re-require so that the static instance is reset to it's default state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment
@@ -83,6 +86,7 @@ export class EppoJSClient extends EppoClient { | |||
subjectAttributes?: Record<string, any>, | |||
assignmentHooks?: IAssignmentHooks, | |||
): string | null { | |||
EppoJSClient.getAssignmentInitializationCheck(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, we can mute it in the future if requested. Currently the greater issue seems to be confusion about unexpected null returns
if (!EppoJSClient.instance) { | ||
throw Error('init() must first be called to initialize a client instance'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the intention of alerting if the SDK is functioning in an unintended way, but I won't miss the risk of throwing exceptions in client code
ποΈ (Eppo Internal) FF-1557 - JS Client SDK should return null when not initialized
π― Related PR:
js-client-sdk
#37#45 introduced a change of behavior, where calls to
getInstance()
before the client was initialized would throw an error instead of returning an uninitialized client. This Pull request reverts that behavior change so that there will always be a client, and if uninitialized, it will just returnnull
on any assignment calls.This is done by instantiating a client statically at import time--as we were previously doing (link)--as opposed to during
init()
.So that we can still leverage the client handling polling for configuration requests, we use
EppoClient
s newly-added (see the related PR)setConfigurationRequestParameters()
where we can pass in the configuration request parameters duringinit()
instead of needing the when constructing the instance.