Skip to content

Commit

Permalink
feat: added waffle flag state for Courseware Search (#1199)
Browse files Browse the repository at this point in the history
  • Loading branch information
rijuma authored Oct 12, 2023
1 parent 165097d commit 62465ec
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/course-home/courseware-search/CoursewareSearch.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Button, Icon } from '@edx/paragon';
import { Search } from '@edx/paragon/icons';
import messages from './messages';
import { fetchCoursewareSearchSettings } from '../data/thunks';

const CoursewareSearch = ({ intl, ...rest }) => {
const { courseId } = useParams();
const [enabled, setEnabled] = useState(false);

useEffect(() => {
fetchCoursewareSearchSettings(courseId).then(response => setEnabled(response.enabled));
}, [courseId]);

if (!enabled) { return null; }

return (
<Button variant="tertiary" size="sm" className="p-1 mt-2 mr-2 rounded-lg" aria-label={intl.formatMessage(messages.searchOpenAction)} data-testid="courseware-search-button" {...rest}>
<Icon src={Search} />
</Button>
);
};

CoursewareSearch.propTypes = {
intl: intlShape.isRequired,
};

export default injectIntl(CoursewareSearch);
46 changes: 46 additions & 0 deletions src/course-home/courseware-search/CoursewareSearch.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import {
act,
initializeMockApp,
render,
screen,
waitFor,
} from '../../setupTest';
import { fetchCoursewareSearchSettings } from '../data/thunks';
import { CoursewareSearch } from './index';

jest.mock('../data/thunks');

function renderComponent() {
const { container } = render(<CoursewareSearch />);
return container;
}

describe('CoursewareSearch', () => {
beforeAll(async () => {
initializeMockApp();
});

beforeEach(() => {
jest.clearAllMocks();
});

it('Should not render when the waffle flag is disabled', async () => {
fetchCoursewareSearchSettings.mockImplementation(() => Promise.resolve({ enabled: false }));

await act(async () => renderComponent());
await waitFor(() => {
expect(fetchCoursewareSearchSettings).toHaveBeenCalledTimes(1);
expect(screen.queryByTestId('courseware-search-button')).not.toBeInTheDocument();
});
});

it('Should render when the waffle flag is enabled', async () => {
fetchCoursewareSearchSettings.mockImplementation(() => Promise.resolve({ enabled: true }));
await act(async () => renderComponent());
await waitFor(() => {
expect(fetchCoursewareSearchSettings).toHaveBeenCalledTimes(1);
expect(screen.queryByTestId('courseware-search-button')).toBeInTheDocument();
});
});
});
2 changes: 2 additions & 0 deletions src/course-home/courseware-search/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* eslint-disable import/prefer-default-export */
export { default as CoursewareSearch } from './CoursewareSearch';
11 changes: 11 additions & 0 deletions src/course-home/courseware-search/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
searchOpenAction: {
id: 'learn.coursewareSerch.openAction',
defaultMessage: 'Search within this course',
description: 'Aria-label for a button that will pop up Courseware Search.',
},
});

export default messages;
6 changes: 6 additions & 0 deletions src/course-home/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,9 @@ export async function unsubscribeFromCourseGoal(token) {
return getAuthenticatedHttpClient().post(url.href)
.then(res => camelCaseObject(res));
}

export async function getCoursewareSearchEnabledFlag(courseId) {
const url = new URL(`${getConfig().LMS_BASE_URL}/courses/${courseId}/courseware-search/enabled/`);
const { data } = await getAuthenticatedHttpClient().get(url.href);
return { enabled: data.enabled || false };
}
32 changes: 32 additions & 0 deletions src/course-home/data/redux.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,36 @@ describe('Data layer integration tests', () => {
expect(axiosMock.history.post[0].data).toEqual(`{"course_id":"${courseId}"}`);
});
});

describe('Test fetchCoursewareSearchSettings', () => {
it('Should return enabled as true when enabled', async () => {
const apiUrl = `${getConfig().LMS_BASE_URL}/courses/${courseId}/courseware-search/enabled/`;
axiosMock.onGet(apiUrl).reply(200, { enabled: true });

const { enabled } = await thunks.fetchCoursewareSearchSettings(courseId);

expect(axiosMock.history.get[0].url).toEqual(apiUrl);
expect(enabled).toBe(true);
});

it('Should return enabled as false when disabled', async () => {
const apiUrl = `${getConfig().LMS_BASE_URL}/courses/${courseId}/courseware-search/enabled/`;
axiosMock.onGet(apiUrl).reply(200, { enabled: false });

const { enabled } = await thunks.fetchCoursewareSearchSettings(courseId);

expect(axiosMock.history.get[0].url).toEqual(apiUrl);
expect(enabled).toBe(false);
});

it('Should return enabled as false on error', async () => {
const apiUrl = `${getConfig().LMS_BASE_URL}/courses/${courseId}/courseware-search/enabled/`;
axiosMock.onGet(apiUrl).networkError();

const { enabled } = await thunks.fetchCoursewareSearchSettings(courseId);

expect(axiosMock.history.get[0].url).toEqual(apiUrl);
expect(enabled).toBe(false);
});
});
});
10 changes: 10 additions & 0 deletions src/course-home/data/thunks.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
postDismissWelcomeMessage,
postRequestCert,
getLiveTabIframe,
getCoursewareSearchEnabledFlag,
} from './api';

import {
Expand Down Expand Up @@ -139,3 +140,12 @@ export function processEvent(eventData, getTabData) {
}
};
}

export async function fetchCoursewareSearchSettings(courseId) {
try {
const { enabled } = await getCoursewareSearchEnabledFlag(courseId);
return { enabled };
} catch (e) {
return { enabled: false };
}
}
4 changes: 4 additions & 0 deletions src/course-tabs/CourseTabsNavigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import classNames from 'classnames';

import messages from './messages';
import Tabs from '../generic/tabs/Tabs';
import { CoursewareSearch } from '../course-home/courseware-search';

const CourseTabsNavigation = ({
activeTabSlug, className, tabs, intl,
}) => (
<div id="courseTabsNavigation" className={classNames('course-tabs-navigation', className)}>
<div className="float-right">
<CoursewareSearch />
</div>
<div className="container-xl">
<Tabs
className="nav-underline-tabs"
Expand Down

0 comments on commit 62465ec

Please sign in to comment.