Skip to content

Commit

Permalink
fix: Small refactor on useDecision hook
Browse files Browse the repository at this point in the history
  • Loading branch information
rijuma committed Jul 18, 2024
1 parent 7cf1004 commit 7ef94c0
Show file tree
Hide file tree
Showing 12 changed files with 56 additions and 48 deletions.
7 changes: 2 additions & 5 deletions src/components/MessageForm/index.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import PropTypes from 'prop-types';
import React, { useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDecision } from '@optimizely/react-sdk';
import { Button, Form, Icon } from '@openedx/paragon';
import { Send } from '@openedx/paragon/icons';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';

import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY } from '../../data/optimizely';
import {
acknowledgeDisclosure,
addChatMessage,
getChatResponse,
updateCurrentMessage,
} from '../../data/thunks';
import { usePromptExperimentDecision } from '../../experiments';

const MessageForm = ({ courseId, shouldAutofocus, unitId }) => {
const { apiIsLoading, currentMessage, apiError } = useSelector(state => state.learningAssistant);
const dispatch = useDispatch();
const inputRef = useRef();

const { userId } = getAuthenticatedUser();
const [decision] = useDecision(OPTIMIZELY_PROMPT_EXPERIMENT_KEY, { autoUpdate: true }, { id: userId.toString() });
const [decision] = usePromptExperimentDecision();
const { enabled, variationKey } = decision || {};
const promptExperimentVariationKey = enabled ? variationKey : undefined;

Expand Down
10 changes: 5 additions & 5 deletions src/components/MessageForm/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import {
screen, act, fireEvent, waitFor,
} from '@testing-library/react';
import { useDecision } from '@optimizely/react-sdk';
import { usePromptExperimentDecision } from '../../experiments';
import { render as renderComponent } from '../../utils/utils.test';
import { initialState } from '../../data/slice';
import { OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS } from '../../data/optimizely';
Expand Down Expand Up @@ -39,8 +39,8 @@ jest.mock('react-redux', () => ({
useDispatch: () => mockDispatch,
}));

jest.mock('@optimizely/react-sdk', () => ({
useDecision: jest.fn(),
jest.mock('../../experiments', () => ({
usePromptExperimentDecision: jest.fn(),
}));

jest.mock('../../data/thunks', () => ({
Expand Down Expand Up @@ -80,7 +80,7 @@ const render = async (props = {}, sliceState = {}) => {
describe('<MessageForm />', () => {
beforeEach(() => {
jest.resetAllMocks();
useDecision.mockReturnValue([]);
usePromptExperimentDecision.mockReturnValue([]);
});

describe('when rendered', () => {
Expand Down Expand Up @@ -157,7 +157,7 @@ describe('<MessageForm />', () => {

describe('prmpt experiment', () => {
beforeEach(() => {
useDecision.mockReturnValue([{
usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
Expand Down
6 changes: 2 additions & 4 deletions src/components/Sidebar/index.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React, { useRef, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { useDecision } from '@optimizely/react-sdk';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import {
Button,
Icon,
Expand All @@ -20,6 +18,7 @@ import ChatBox from '../ChatBox';
import Disclosure from '../Disclosure';
import MessageForm from '../MessageForm';
import './Sidebar.scss';
import { usePromptExperimentDecision } from '../../experiments';

const Sidebar = ({
courseId,
Expand All @@ -35,8 +34,7 @@ const Sidebar = ({
const chatboxContainerRef = useRef(null);
const dispatch = useDispatch();

const { userId } = getAuthenticatedUser();
const [decision] = useDecision(OPTIMIZELY_PROMPT_EXPERIMENT_KEY, { autoUpdate: true }, { id: userId.toString() });
const [decision] = usePromptExperimentDecision();
const { enabled: enabledExperiment, variationKey } = decision || {};
const experimentPayload = enabledExperiment ? {
experiment_name: OPTIMIZELY_PROMPT_EXPERIMENT_KEY,
Expand Down
13 changes: 7 additions & 6 deletions src/components/Sidebar/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { screen, act } from '@testing-library/react';
import { useDecision } from '@optimizely/react-sdk';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';

import { usePromptExperimentDecision } from '../../experiments';
import { render as renderComponent } from '../../utils/utils.test';
import { initialState } from '../../data/slice';
import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY, OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS } from '../../data/optimizely';
Expand Down Expand Up @@ -33,8 +34,8 @@ jest.mock('react-redux', () => ({
useDispatch: () => mockDispatch,
}));

jest.mock('@optimizely/react-sdk', () => ({
useDecision: jest.fn(),
jest.mock('../../experiments', () => ({
usePromptExperimentDecision: jest.fn(),
}));

const clearMessagesAction = 'clear-messages-action';
Expand Down Expand Up @@ -72,7 +73,7 @@ const render = async (props = {}, sliceState = {}) => {
describe('<Sidebar />', () => {
beforeEach(() => {
jest.resetAllMocks();
useDecision.mockReturnValue([]);
usePromptExperimentDecision.mockReturnValue([]);
});

describe('when it\'s open', () => {
Expand Down Expand Up @@ -124,7 +125,7 @@ describe('<Sidebar />', () => {
};

it('should call showVariationSurvey if experiment is enabled', () => {
useDecision.mockReturnValue([{
usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
Expand Down Expand Up @@ -154,7 +155,7 @@ describe('<Sidebar />', () => {
});

it('should dispatch clearMessages() and call sendTrackEvent() with the expected props on clear', () => {
useDecision.mockReturnValue([{
usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
Expand Down
4 changes: 2 additions & 2 deletions src/components/ToggleXpertButton/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import { useDecision } from '@optimizely/react-sdk';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import {
Expand All @@ -15,6 +14,7 @@ import { Close } from '@openedx/paragon/icons';
import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY } from '../../data/optimizely';
import { ReactComponent as XpertLogo } from '../../assets/xpert-logo.svg';
import './index.scss';
import { usePromptExperimentDecision } from '../../experiments';

const ToggleXpert = ({
isOpen,
Expand All @@ -27,7 +27,7 @@ const ToggleXpert = ({
const [target, setTarget] = useState(null);
const { userId } = getAuthenticatedUser();

const [decision] = useDecision(OPTIMIZELY_PROMPT_EXPERIMENT_KEY, { autoUpdate: true }, { id: userId.toString() });
const [decision] = usePromptExperimentDecision();
const { enabled, variationKey } = decision || {};
const experimentPayload = enabled ? {
experiment_name: OPTIMIZELY_PROMPT_EXPERIMENT_KEY,
Expand Down
11 changes: 6 additions & 5 deletions src/components/ToggleXpertButton/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { screen, waitFor } from '@testing-library/react';
import { useDecision } from '@optimizely/react-sdk';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';

import { usePromptExperimentDecision } from '../../experiments';
import { render as renderComponent } from '../../utils/utils.test';
import { initialState } from '../../data/slice';
import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY, OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS } from '../../data/optimizely';
Expand All @@ -17,8 +18,8 @@ jest.mock('@edx/frontend-platform/auth', () => ({
getAuthenticatedUser: () => mockedAuthenticatedUser,
}));

jest.mock('@optimizely/react-sdk', () => ({
useDecision: jest.fn(),
jest.mock('../../experiments', () => ({
usePromptExperimentDecision: jest.fn(),
}));

const defaultProps = {
Expand Down Expand Up @@ -52,7 +53,7 @@ describe('<ToggleXpert />', () => {
beforeEach(() => {
window.localStorage.clear();
jest.clearAllMocks();
useDecision.mockReturnValue([]);
usePromptExperimentDecision.mockReturnValue([]);
});

describe('when it\'s closed', () => {
Expand Down Expand Up @@ -120,7 +121,7 @@ describe('<ToggleXpert />', () => {

describe('prompt experiment', () => {
beforeEach(() => {
useDecision.mockReturnValue([{
usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
Expand Down
File renamed without changes.
17 changes: 17 additions & 0 deletions src/experiments/experimentHooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { useDecision } from '@optimizely/react-sdk';

import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY } from '../data/optimizely';

// eslint-disable-next-line import/prefer-default-export
export function usePromptExperimentDecision() {
const { userId } = getAuthenticatedUser();

const [decision] = useDecision(
OPTIMIZELY_PROMPT_EXPERIMENT_KEY,
{ autoUpdate: true },
{ overrideUserId: userId.toString() },
);

return [decision];
}
5 changes: 5 additions & 0 deletions src/experiments/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ExperimentsProvider from './ExperimentsProvider';

export * from './experimentHooks';

export { ExperimentsProvider };
3 changes: 0 additions & 3 deletions src/optimizely/index.jsx

This file was deleted.

3 changes: 2 additions & 1 deletion src/widgets/Xpert.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import PropTypes from 'prop-types';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { updateSidebarIsOpen, getIsEnabled } from '../data/thunks';
import ToggleXpert from '../components/ToggleXpertButton';
import Sidebar from '../components/Sidebar';
import ExperimentsProvider from '../optimizely';
import { ExperimentsProvider } from '../experiments';

const Xpert = ({ courseId, contentToolsEnabled, unitId }) => {
const dispatch = useDispatch();
Expand Down
25 changes: 8 additions & 17 deletions src/widgets/Xpert.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,18 @@ import Xpert from './Xpert';
import * as surveyMonkey from '../utils/surveyMonkey';
import { render, createRandomResponseForTesting } from '../utils/utils.test';
import { OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS } from '../data/optimizely';
import { usePromptExperimentDecision } from '../experiments';

jest.mock('@edx/frontend-platform/analytics');
jest.mock('@edx/frontend-platform/auth', () => ({
getAuthenticatedUser: jest.fn(() => ({ userId: 1 })),
}));

jest.mock('@optimizely/react-sdk', () => ({
useDecision: jest.fn(),
jest.mock('../experiments', () => ({
ExperimentsProvider: ({ children }) => children,
usePromptExperimentDecision: jest.fn(),
}));

jest.mock('../optimizely', () => ({ children }) => children);

// import useDecision here, after mocking, so that it can be used in tests
import { useDecision } from '@optimizely/react-sdk'; // eslint-disable-line

const initialState = {
learningAssistant: {
currentMessage: '',
Expand All @@ -34,7 +31,6 @@ const initialState = {
// I will remove this and write tests in a future pull request.
disclosureAcknowledged: true,
sidebarIsOpen: false,
experiments: {},
},
};
const courseId = 'course-v1:edX+DemoX+Demo_Course';
Expand All @@ -53,7 +49,7 @@ beforeEach(() => {
const responseMessage = createRandomResponseForTesting();
jest.spyOn(api, 'default').mockResolvedValue(responseMessage);
jest.spyOn(api, 'fetchLearningAssistantEnabled').mockResolvedValue({ enabled: true });
useDecision.mockReturnValue([]);
usePromptExperimentDecision.mockReturnValue([]);

window.localStorage.clear();
// Popup modal should be ignored for all tests unless explicitly enabled. This is because
Expand Down Expand Up @@ -254,7 +250,6 @@ test('error message should disappear upon succesful api call', async () => {
// I will remove this and write tests in a future pull request.
disclosureAcknowledged: true,
sidebarIsOpen: false,
experiments: {},
},
};
render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: errorState });
Expand Down Expand Up @@ -289,7 +284,6 @@ test('error message should disappear when dismissed', async () => {
// I will remove this and write tests in a future pull request.
disclosureAcknowledged: true,
sidebarIsOpen: false,
experiments: {},
},
};
render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: errorState });
Expand Down Expand Up @@ -319,7 +313,6 @@ test('error message should disappear when messages cleared', async () => {
// I will remove this and write tests in a future pull request.
disclosureAcknowledged: true,
sidebarIsOpen: false,
experiments: {},
},
};
render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: errorState });
Expand Down Expand Up @@ -387,13 +380,12 @@ test('survey monkey survey should appear after closing sidebar', async () => {
currentMessage: '',
messageList: [
{ role: 'user', content: 'hi', timestamp: new Date() },
{ role: 'user', content: 'hi', timestamp: new Date() },
{ role: 'user', content: 'hi', timestamp: new Date() + 1 },
],
apiIsLoading: false,
apiError: false,
disclosureAcknowledged: true,
sidebarIsOpen: false,
experiments: {},
},
};
render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: surveyState });
Expand All @@ -415,7 +407,7 @@ test('survey monkey variation survey should appear if user is in experiment', as
const variationSurvey = jest.spyOn(surveyMonkey, 'showVariationSurvey').mockReturnValueOnce(1);
const user = userEvent.setup();

useDecision.mockReturnValue([{
usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
Expand All @@ -425,13 +417,12 @@ test('survey monkey variation survey should appear if user is in experiment', as
currentMessage: '',
messageList: [
{ role: 'user', content: 'hi', timestamp: new Date() },
{ role: 'user', content: 'hi', timestamp: new Date() },
{ role: 'user', content: 'hi', timestamp: new Date() + 1 },
],
apiIsLoading: false,
apiError: false,
disclosureAcknowledged: true,
sidebarIsOpen: false,
experiments: {},
},
};
render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: surveyState });
Expand Down

0 comments on commit 7ef94c0

Please sign in to comment.