diff --git a/src/components/MessageForm/index.jsx b/src/components/MessageForm/index.jsx
index 566f5113..8d8d92e0 100644
--- a/src/components/MessageForm/index.jsx
+++ b/src/components/MessageForm/index.jsx
@@ -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;
diff --git a/src/components/MessageForm/index.test.jsx b/src/components/MessageForm/index.test.jsx
index 0e9a83f2..6c8dba2b 100644
--- a/src/components/MessageForm/index.test.jsx
+++ b/src/components/MessageForm/index.test.jsx
@@ -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';
@@ -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', () => ({
@@ -80,7 +80,7 @@ const render = async (props = {}, sliceState = {}) => {
describe('', () => {
beforeEach(() => {
jest.resetAllMocks();
- useDecision.mockReturnValue([]);
+ usePromptExperimentDecision.mockReturnValue([]);
});
describe('when rendered', () => {
@@ -157,7 +157,7 @@ describe('', () => {
describe('prmpt experiment', () => {
beforeEach(() => {
- useDecision.mockReturnValue([{
+ usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
diff --git a/src/components/Sidebar/index.jsx b/src/components/Sidebar/index.jsx
index b3358176..8f925154 100644
--- a/src/components/Sidebar/index.jsx
+++ b/src/components/Sidebar/index.jsx
@@ -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,
@@ -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,
@@ -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,
diff --git a/src/components/Sidebar/index.test.jsx b/src/components/Sidebar/index.test.jsx
index db56b160..1f02709c 100644
--- a/src/components/Sidebar/index.test.jsx
+++ b/src/components/Sidebar/index.test.jsx
@@ -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';
@@ -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';
@@ -72,7 +73,7 @@ const render = async (props = {}, sliceState = {}) => {
describe('', () => {
beforeEach(() => {
jest.resetAllMocks();
- useDecision.mockReturnValue([]);
+ usePromptExperimentDecision.mockReturnValue([]);
});
describe('when it\'s open', () => {
@@ -124,7 +125,7 @@ describe('', () => {
};
it('should call showVariationSurvey if experiment is enabled', () => {
- useDecision.mockReturnValue([{
+ usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
@@ -154,7 +155,7 @@ describe('', () => {
});
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,
}]);
diff --git a/src/components/ToggleXpertButton/index.jsx b/src/components/ToggleXpertButton/index.jsx
index 750d2234..08bc570e 100644
--- a/src/components/ToggleXpertButton/index.jsx
+++ b/src/components/ToggleXpertButton/index.jsx
@@ -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 {
@@ -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,
@@ -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,
diff --git a/src/components/ToggleXpertButton/index.test.jsx b/src/components/ToggleXpertButton/index.test.jsx
index 6f4e89d3..e3d32ae9 100644
--- a/src/components/ToggleXpertButton/index.test.jsx
+++ b/src/components/ToggleXpertButton/index.test.jsx
@@ -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';
@@ -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 = {
@@ -52,7 +53,7 @@ describe('', () => {
beforeEach(() => {
window.localStorage.clear();
jest.clearAllMocks();
- useDecision.mockReturnValue([]);
+ usePromptExperimentDecision.mockReturnValue([]);
});
describe('when it\'s closed', () => {
@@ -120,7 +121,7 @@ describe('', () => {
describe('prompt experiment', () => {
beforeEach(() => {
- useDecision.mockReturnValue([{
+ usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);
diff --git a/src/optimizely/ExperimentsProvider.jsx b/src/experiments/ExperimentsProvider.jsx
similarity index 100%
rename from src/optimizely/ExperimentsProvider.jsx
rename to src/experiments/ExperimentsProvider.jsx
diff --git a/src/experiments/experimentHooks.js b/src/experiments/experimentHooks.js
new file mode 100644
index 00000000..1d9c33c5
--- /dev/null
+++ b/src/experiments/experimentHooks.js
@@ -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];
+}
diff --git a/src/experiments/index.jsx b/src/experiments/index.jsx
new file mode 100644
index 00000000..c5b5202f
--- /dev/null
+++ b/src/experiments/index.jsx
@@ -0,0 +1,5 @@
+import ExperimentsProvider from './ExperimentsProvider';
+
+export * from './experimentHooks';
+
+export { ExperimentsProvider };
diff --git a/src/optimizely/index.jsx b/src/optimizely/index.jsx
deleted file mode 100644
index a94cb61d..00000000
--- a/src/optimizely/index.jsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import ExperimentsProvider from './ExperimentsProvider';
-
-export default ExperimentsProvider;
diff --git a/src/widgets/Xpert.jsx b/src/widgets/Xpert.jsx
index 45fb6d23..ade3b1e9 100644
--- a/src/widgets/Xpert.jsx
+++ b/src/widgets/Xpert.jsx
@@ -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();
diff --git a/src/widgets/Xpert.test.jsx b/src/widgets/Xpert.test.jsx
index 2e677f92..81721577 100644
--- a/src/widgets/Xpert.test.jsx
+++ b/src/widgets/Xpert.test.jsx
@@ -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: '',
@@ -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';
@@ -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
@@ -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(, { preloadedState: errorState });
@@ -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(, { preloadedState: errorState });
@@ -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(, { preloadedState: errorState });
@@ -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(, { preloadedState: surveyState });
@@ -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,
}]);
@@ -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(, { preloadedState: surveyState });