Skip to content

Commit

Permalink
feat: gate visibility of chat component by active attempt (openedx#1282)
Browse files Browse the repository at this point in the history
  • Loading branch information
alangsto authored Feb 12, 2024
1 parent efd57c3 commit db1fc77
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 32 deletions.
9 changes: 9 additions & 0 deletions src/courseware/course/chat/Chat.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createPortal } from 'react-dom';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import { Xpert } from '@edx/frontend-lib-learning-assistant';
Expand All @@ -13,6 +14,10 @@ const Chat = ({
unitId,
endDate,
}) => {
const {
activeAttempt, exam,
} = useSelector(state => state.specialExams);

const VERIFIED_MODES = [
'professional',
'verified',
Expand Down Expand Up @@ -41,6 +46,10 @@ const Chat = ({
enabled
&& (hasVerifiedEnrollment || isStaff) // display only to verified learners or staff
&& !endDatePassed()
// it is necessary to check both whether the user is in an exam, and whether or not they are viewing an exam
// this will prevent the learner from interacting with the tool at any point of the exam flow, even at the
// entrance interstitial.
&& !(activeAttempt?.attempt_id || exam?.id)
);

return (
Expand Down
76 changes: 45 additions & 31 deletions src/courseware/course/chat/Chat.test.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { BrowserRouter } from 'react-router-dom';
import { configureStore } from '@reduxjs/toolkit';
import React from 'react';

import { reducer as learningAssistantReducer } from '@edx/frontend-lib-learning-assistant';

import { initializeMockApp, render, screen } from '../../../setupTest';
import {
initializeMockApp,
initializeTestStore,
render,
screen,
} from '../../../setupTest';

import Chat from './Chat';

Expand Down Expand Up @@ -39,6 +41,21 @@ const disabledModes = [null, undefined, 'xyz', 'audit', 'honor', 'unpaid-executi
const currentTime = new Date();

describe('Chat', () => {
let store;

beforeAll(async () => {
store = await initializeTestStore({
specialExams: {
activeAttempt: {
attempt_id: null,
},
exam: {
id: null,
},
},
});
});

// Generate test cases.
enabledTestCases = enabledModes.map((mode) => ({ enrollmentMode: mode, isVisible: true }));
disabledTestCases = disabledModes.map((mode) => ({ enrollmentMode: mode, isVisible: false }));
Expand All @@ -48,12 +65,6 @@ describe('Chat', () => {
it(
`visibility determined by ${test.enrollmentMode} enrollment mode when enabled and not isStaff`,
async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand Down Expand Up @@ -82,12 +93,6 @@ describe('Chat', () => {
testCases = enabledModes.concat(disabledModes).map((mode) => ({ enrollmentMode: mode, isVisible: true }));
testCases.forEach(test => {
it('visibility determined by isStaff when enabled and any enrollment mode', async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand Down Expand Up @@ -144,12 +149,6 @@ describe('Chat', () => {
`visibility determined by ${test.enabled} enabled when ${test.isStaff} isStaff
and ${test.enrollmentMode} enrollment mode`,
async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand All @@ -175,12 +174,6 @@ describe('Chat', () => {
});

it('if course end date has passed, component should not be visible', async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand All @@ -200,9 +193,30 @@ describe('Chat', () => {
});

it('if course has no end date, component should be visible', async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
render(
<BrowserRouter>
<Chat
enrollmentMode="verified"
isStaff
enabled
courseId={courseId}
contentToolsEnabled={false}
endDate={null}
/>
</BrowserRouter>,
{ store },
);

const chat = screen.queryByTestId(mockXpertTestId);
expect(chat).toBeInTheDocument();
});

it('if learner has active exam attempt, component should not be visible', async () => {
store = await initializeTestStore({
specialExams: {
activeAttempt: {
attempt_id: 1,
},
},
});

Expand Down
2 changes: 1 addition & 1 deletion src/store.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { reducer as learningAssistantReducer } from '@edx/frontend-lib-learning-assistant';
import { configureStore } from '@reduxjs/toolkit';
import { reducer as specialExamsReducer } from '@edx/frontend-lib-special-exams';
import { configureStore } from '@reduxjs/toolkit';
import { reducer as courseHomeReducer } from './course-home/data';
import { reducer as coursewareReducer } from './courseware/data/slice';
import { reducer as recommendationsReducer } from './courseware/course/course-exit/data/slice';
Expand Down

0 comments on commit db1fc77

Please sign in to comment.