Skip to content

Commit

Permalink
Fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vlacerda committed Jun 19, 2024
1 parent ea62f11 commit a43d02c
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,25 @@ export const createInstanceMock = jest.fn(() => ({
notificationCenter: {
addNotificationListener: addNotificationListenerMock
},
activate: activateMock,
createUserContext: optimizelyUserContextMock
}))

export const decideMock = jest.fn((toggleKey) => ({
enabled: toggleKey === 'foo'
}))
export const decideMock = jest.fn((toggleKey) => {
switch (toggleKey) {
case 'foo':
return {variationKey: 'b'}
case 'bax':
return {variationKey: 'c'}
default:
return {variationKey: undefined}
}
})
export const optimizelyUserContextMock = jest.fn(() => ({
decide: decideMock
}))

export const isFeatureEnabledMock = jest.fn((toggleId) => toggleId === 'foo')

export const activateMock = jest.fn((toggleId, userId) => {
const shouldReturnB =
(toggleId === 'foo' && userId === 'fooBSide') ||
(toggleId === 'bar' && userId === 'barBSide')

return shouldReturnB && 'b'
})

const originalModule = jest.requireActual('@optimizely/optimizely-sdk')

const mock = {
Expand Down
37 changes: 9 additions & 28 deletions packages/lib/src/integrations/optimizely.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import Optimizely, {
// @ts-expect-error
isFeatureEnabledMock,
// @ts-expect-error
activateMock,
// @ts-expect-error
decideMock,
// @ts-expect-error
optimizelyUserContextMock
Expand All @@ -44,16 +42,12 @@ const testAudienceSegmentationCacheBusting = (toggleFn, fn) => {

toggleFn('foo', 'a', 'b', 'c') // call 1
expect(fn).toHaveBeenCalledTimes(1)
expect(fn).toHaveBeenCalledWith('foo', 'fooBSide', {
foo: 'baz'
})
expect(fn).toHaveBeenCalledWith('foo')
toggleFn('foo', 'a', 'b', 'c') // cached
toggleFn('bar', 'a', 'b', 'c') // call 2
toggleFn('bar', 'a', 'b', 'c') // cached
expect(fn).toHaveBeenCalledTimes(2)
expect(fn).toHaveBeenCalledWith('bar', 'fooBSide', {
foo: 'baz'
})
expect(fn).toHaveBeenCalledWith('bar')
})
}

Expand Down Expand Up @@ -82,7 +76,7 @@ describe('Optimizely Integration', () => {
expect(addNotificationListenerMock).toHaveBeenCalledWith(
NOTIFICATION_TYPES.DECISION,
// 'DECISION:type, userId, attributes, decisionInfo',
activateHandler
expect.any(Function)
)
})
})
Expand Down Expand Up @@ -141,14 +135,9 @@ describe('Optimizely Integration', () => {

it('Forwards toggle reading and audienceSegmentationAttributes to Optimizely', () => {
toggle('foo', 'a', 'b', 'c')
expect(activateMock).toHaveBeenCalledWith('foo', 'fooBSide', {})
toggle('foo')
expect(decideMock).toHaveBeenCalledWith(
'foo'
)
expect(optimizelyUserContextMock).toHaveBeenCalledWith(
'fooBSide', {}
)
expect(decideMock).toHaveBeenCalledWith('foo')
expect(optimizelyUserContextMock).toHaveBeenCalledWith('fooBSide', {})
})
})

Expand All @@ -166,15 +155,6 @@ describe('Optimizely Integration', () => {

it('Forwards toggle reading and audienceSegmentationAttributes to Optimizely', () => {
toggle('foo', 'a', 'b', 'c')
expect(activateMock).toHaveBeenCalledWith('foo', 'fooBSide', {
thisWillNotBeOverwritten: 'foo',
deviceType: 'mobile',
isLoggedIn: false
})
})

it('Forwards toggle reading and audienceSegmentationAttributes to Optimizely', () => {
toggle('foo')
expect(optimizelyUserContextMock).toHaveBeenCalledWith('fooBSide', {
thisWillNotBeOverwritten: 'foo',
deviceType: 'mobile',
Expand All @@ -192,7 +172,8 @@ describe('Optimizely Integration', () => {

it('Forwards correct audience segmentation attributes', () => {
toggle('foo', 'a', 'b', 'c')
expect(activateMock).toHaveBeenCalledWith('foo', 'fooBSide', {

expect(optimizelyUserContextMock).toHaveBeenCalledWith('fooBSide', {
valueAfterReset: true
})

Expand All @@ -208,7 +189,7 @@ describe('Optimizely Integration', () => {
})
})

testAudienceSegmentationCacheBusting(toggle, activateMock)
testAudienceSegmentationCacheBusting(toggle, decideMock)

it("Returns Optimizely's value when no arguments supplied", () => {
// maps to a, b, c
Expand Down Expand Up @@ -252,7 +233,7 @@ describe('Optimizely Integration', () => {
})

it('makes sure Toggles return defaults if forced values are of wrong type', () => {
expect(toggle('baz', 'a', 'b', 'c')).toEqual('a')
expect(toggle('boz', 'a', 'b', 'c')).toEqual('a')
})

describe('Clearing forced toggles', () => {
Expand Down
35 changes: 28 additions & 7 deletions packages/lib/src/integrations/optimizely.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type AudienceSegmentationAttributesType = {
[key in AudienceSegmentationAttributeKeyType]?: AudienceSegmentationAttributeValueType
}

type ExperimentToggleValueType = boolean | string
type ExperimentToggleValueType = string | boolean
type ToggleValueType = ExperimentToggleValueType

export type OptimizelyDatafileType = object
Expand Down Expand Up @@ -53,7 +53,9 @@ export const registerLibrary = (lib) => {
optimizely = lib
}

const clearExperimentCache = () => (experimentCache = {})
const clearExperimentCache = () => {
experimentCache = {}
}

/**
* Adds / removes Toggles to force from the forcedToggles list
Expand All @@ -66,6 +68,15 @@ export const forceToggles = (toggleKeyValues: {
Object.keys(toggleKeyValues).forEach((toggleId) => {
const value = toggleKeyValues[toggleId]

/**
* Keeping the old behaviour of using boolean values for toggles to represent `a` and `b` versions
*/
const isBoolean = typeof value === 'boolean'
if (isBoolean) {
forcedToggles[toggleId] = value ? 'b' : 'a'
return
}

if (value === null) {
delete forcedToggles[toggleId]
} else {
Expand All @@ -85,7 +96,7 @@ const invalidateCaches = () => {
* @param id
*/
export const setUserId = (id: UserIdType) => {
invalidateCaches()
if (userId !== id) invalidateCaches()
userId = id
}

Expand All @@ -98,11 +109,20 @@ export const setUserId = (id: UserIdType) => {
export const setAudienceSegmentationAttributes = (
attributes: AudienceSegmentationAttributesType = {}
) => {
invalidateCaches()
audienceSegmentationAttributes = {
const newSegmentationAttributes = {
...audienceSegmentationAttributes,
...attributes
}

const shouldInvalidateCache =
JSON.stringify(newSegmentationAttributes) !==
JSON.stringify(audienceSegmentationAttributes || {})

if (shouldInvalidateCache) {
invalidateCaches()
}

audienceSegmentationAttributes = newSegmentationAttributes
}

/**
Expand Down Expand Up @@ -132,7 +152,7 @@ export enum ExperimentType {
* It would be best if Opticks abstracts this difference from the client in future versions.
*/
interface ActivateNotificationPayload extends ListenerPayload {
type: ExperimentType.mvt
type: ExperimentType
decisionInfo: {
experimentKey: ToggleIdType
variationKey: VariantType
Expand Down Expand Up @@ -316,7 +336,8 @@ const getToggle = (toggleId: ToggleIdType): ExperimentToggleValueType => {

// Assuming the variation keys follow a, b, c, etc. convention
// TODO: Enforce ^ ?
return (experimentCache[toggleId] = decision || DEFAULT)
experimentCache[toggleId] = decision || DEFAULT
return decision || DEFAULT
}

/**
Expand Down

0 comments on commit a43d02c

Please sign in to comment.