-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(app): Send intercom event on no-cal-block selected (#6893)
When the user selects and saves the trash surface as their tip length calibration target, send an event to intercom so that support can follow up about fulfilling a calibration block. This also brings back the intercom event epics and bindings removed in #6781, without the calibration check session end bindings.
- Loading branch information
Showing
8 changed files
with
283 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// @flow | ||
// support profile epic test | ||
import { TestScheduler } from 'rxjs/testing' | ||
import { configInitialized } from '../../config' | ||
import * as Profile from '../profile' | ||
import * as Event from '../intercom-event' | ||
import { supportEpic } from '../epic' | ||
|
||
import type { Action, State } from '../../types' | ||
import type { Config } from '../../config/types' | ||
import type { | ||
SupportConfig, | ||
SupportProfileUpdate, | ||
IntercomEvent, | ||
} from '../types' | ||
|
||
jest.mock('../profile') | ||
jest.mock('../intercom-event') | ||
|
||
const makeProfileUpdate: JestMockFn< | ||
[Action, State], | ||
SupportProfileUpdate | null | ||
> = Profile.makeProfileUpdate | ||
|
||
const makeIntercomEvent: JestMockFn<[Action, State], IntercomEvent | null> = | ||
Event.makeIntercomEvent | ||
|
||
const sendEvent: JestMockFn<[IntercomEvent], void> = Event.sendEvent | ||
|
||
const initializeProfile: JestMockFn<[SupportConfig], void> = | ||
Profile.initializeProfile | ||
|
||
const updateProfile: JestMockFn<[SupportProfileUpdate], void> = | ||
Profile.updateProfile | ||
|
||
const MOCK_ACTION: Action = ({ type: 'MOCK_ACTION' }: any) | ||
const MOCK_PROFILE_STATE: $Shape<{| ...State, config: $Shape<Config> |}> = { | ||
config: { | ||
support: { userId: 'foo', createdAt: 42, name: 'bar', email: null }, | ||
}, | ||
} | ||
|
||
const MOCK_EVENT_STATE: $Shape<{| ...State |}> = {} | ||
|
||
describe('support profile epic', () => { | ||
let testScheduler | ||
|
||
beforeEach(() => { | ||
makeProfileUpdate.mockReturnValue(null) | ||
|
||
testScheduler = new TestScheduler((actual, expected) => { | ||
expect(actual).toEqual(expected) | ||
}) | ||
}) | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks() | ||
}) | ||
|
||
it('should initialize support profile on config:INITIALIZED', () => { | ||
testScheduler.run(({ hot, expectObservable, flush }) => { | ||
const action$ = hot('-a', { | ||
a: configInitialized(MOCK_PROFILE_STATE.config), | ||
}) | ||
const state$ = hot('--') | ||
const result$ = supportEpic(action$, state$) | ||
|
||
expectObservable(result$, '--') | ||
flush() | ||
|
||
expect(initializeProfile).toHaveBeenCalledWith( | ||
MOCK_PROFILE_STATE.config.support | ||
) | ||
}) | ||
}) | ||
|
||
it('should do nothing with actions that do not map to a profile update', () => { | ||
testScheduler.run(({ hot, expectObservable, flush }) => { | ||
const action$ = hot('-a', { a: MOCK_ACTION }) | ||
const state$ = hot('s-', { s: MOCK_PROFILE_STATE }) | ||
const result$ = supportEpic(action$, state$) | ||
|
||
expectObservable(result$, '--') | ||
flush() | ||
|
||
expect(makeProfileUpdate).toHaveBeenCalledWith( | ||
MOCK_ACTION, | ||
MOCK_PROFILE_STATE | ||
) | ||
}) | ||
}) | ||
|
||
it('should call a profile update ', () => { | ||
const profileUpdate = { someProp: 'value' } | ||
makeProfileUpdate.mockReturnValueOnce(profileUpdate) | ||
|
||
testScheduler.run(({ hot, expectObservable, flush }) => { | ||
const action$ = hot('-a', { a: MOCK_ACTION }) | ||
const state$ = hot('s-', { s: MOCK_PROFILE_STATE }) | ||
const result$ = supportEpic(action$, state$) | ||
|
||
expectObservable(result$) | ||
flush() | ||
|
||
expect(updateProfile).toHaveBeenCalledWith(profileUpdate) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('support event epic', () => { | ||
let testScheduler | ||
|
||
beforeEach(() => { | ||
makeIntercomEvent.mockReturnValue(null) | ||
|
||
testScheduler = new TestScheduler((actual, expected) => { | ||
expect(actual).toEqual(expected) | ||
}) | ||
}) | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks() | ||
}) | ||
|
||
it('should do nothing with actions that do not map to an event', () => { | ||
testScheduler.run(({ hot, expectObservable, flush }) => { | ||
const action$ = hot('-a', { a: MOCK_ACTION }) | ||
const state$ = hot('s-', { s: MOCK_EVENT_STATE }) | ||
const result$ = supportEpic(action$, state$) | ||
|
||
expectObservable(result$, '--') | ||
flush() | ||
|
||
expect(makeIntercomEvent).toHaveBeenCalledWith( | ||
MOCK_ACTION, | ||
MOCK_EVENT_STATE | ||
) | ||
expect(sendEvent).not.toHaveBeenCalled() | ||
}) | ||
}) | ||
|
||
it('should send an event', () => { | ||
const eventPayload = { | ||
eventName: 'completed-robot-calibration-check', | ||
metadata: { someProp: 'value' }, | ||
} | ||
makeIntercomEvent.mockReturnValueOnce(eventPayload) | ||
|
||
testScheduler.run(({ hot, expectObservable, flush }) => { | ||
const action$ = hot('-a', { a: MOCK_ACTION }) | ||
const state$ = hot('s-', { s: MOCK_PROFILE_STATE }) | ||
const result$ = supportEpic(action$, state$) | ||
|
||
expectObservable(result$) | ||
flush() | ||
|
||
expect(sendEvent).toHaveBeenCalledWith(eventPayload) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// @flow | ||
|
||
import type { IntercomPayload } from '../types' | ||
import type { State } from '../../types' | ||
import * as Binding from '../intercom-binding' | ||
import * as Calibration from '../../calibration' | ||
import * as Config from '../../config' | ||
import { makeIntercomEvent, sendEvent } from '../intercom-event' | ||
import * as Constants from '../constants' | ||
|
||
jest.mock('../intercom-binding') | ||
jest.mock('../../sessions/selectors') | ||
|
||
const sendIntercomEvent: JestMockFn<[string, IntercomPayload], void> = | ||
Binding.sendIntercomEvent | ||
|
||
const MOCK_STATE: $Shape<{| ...State |}> = {} | ||
|
||
describe('support event tests', () => { | ||
afterEach(() => { | ||
jest.resetAllMocks() | ||
}) | ||
|
||
it('makeIntercomEvent should ignore unhandled events', () => { | ||
const built = makeIntercomEvent( | ||
Config.toggleConfigValue('some-random-path'), | ||
MOCK_STATE | ||
) | ||
expect(built).toBeNull() | ||
}) | ||
|
||
it('makeIntercomEvent should send an event for no cal block selected', () => { | ||
expect( | ||
makeIntercomEvent( | ||
Calibration.setUseTrashSurfaceForTipCal(true), | ||
MOCK_STATE | ||
) | ||
).toEqual({ | ||
eventName: Constants.INTERCOM_EVENT_NO_CAL_BLOCK, | ||
metadata: {}, | ||
}) | ||
}) | ||
it('makeIntercomEvent should not send an event for cal block present', () => { | ||
expect( | ||
makeIntercomEvent( | ||
Calibration.setUseTrashSurfaceForTipCal(false), | ||
MOCK_STATE | ||
) | ||
).toBe(null) | ||
}) | ||
|
||
it('sendEvent should pass on its arguments', () => { | ||
const props = { | ||
eventName: Constants.INTERCOM_EVENT_NO_CAL_BLOCK, | ||
metadata: { | ||
someKey: true, | ||
someOtherKey: 'hi', | ||
}, | ||
} | ||
sendEvent(props) | ||
expect(sendIntercomEvent).toHaveBeenCalledWith( | ||
props.eventName, | ||
props.metadata | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// @flow | ||
// functions for sending events to intercom, both for enriching user profiles | ||
// and for triggering contextual support conversations | ||
import type { Action, State } from '../types' | ||
import { sendIntercomEvent } from './intercom-binding' | ||
import type { IntercomEvent } from './types' | ||
import { INTERCOM_EVENT_NO_CAL_BLOCK } from './constants' | ||
import * as Config from '../config' | ||
|
||
export function makeIntercomEvent( | ||
action: Action, | ||
state: State | ||
): IntercomEvent | null { | ||
switch (action.type) { | ||
case Config.UPDATE_VALUE: { | ||
const { path, value } = action.payload | ||
if (path !== 'calibration.useTrashSurfaceForTipCal' || value !== true) { | ||
return null | ||
} | ||
return { | ||
eventName: INTERCOM_EVENT_NO_CAL_BLOCK, | ||
metadata: {}, | ||
} | ||
} | ||
} | ||
return null | ||
} | ||
|
||
export function sendEvent(event: IntercomEvent): void { | ||
sendIntercomEvent(event.eventName, event?.metadata ?? {}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters