Skip to content

Commit

Permalink
feat: added waffle flag state for Courseware Search
Browse files Browse the repository at this point in the history
  • Loading branch information
rijuma committed Oct 10, 2023
1 parent 5604def commit 1036dce
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/course-home/courseware-search/CoursewareSearch.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React 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 { useModel } from '../../generic/model-store';
import messages from './messages';

const CoursewareSearch = ({ intl, ...rest }) => {
const { courseId } = useParams();
const { enabled } = useModel('coursewareSearch', 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);
49 changes: 49 additions & 0 deletions src/course-home/courseware-search/CoursewareSearch.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import {
initializeMockApp,
render,
screen,
} from '../../setupTest';
import { useModel } from '../../generic/model-store';
import { CoursewareSearch } from './index';

jest.mock('../../generic/model-store', () => ({
useModel: jest.fn(),
}));

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

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

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

describe('When rendered by default', () => {
beforeEach(() => {
useModel.mockReturnValue({ enabled: false });
renderComponent();
});

it('Should not show', () => {
expect(screen.queryByTestId('courseware-search-button')).not.toBeInTheDocument();
});
});

describe('When rendered with the waffle flag enabled', () => {
beforeEach(() => {
useModel.mockReturnValue({ enabled: true });
renderComponent();
});

it('Should show', () => {
expect(screen.getByTestId('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 = `${getConfig().LMS_BASE_URL}/courses/${courseId}/courseware-search/enabled/`;
const { data } = await getAuthenticatedHttpClient().get(url);
return { enabled: data.enabled || false };
}
11 changes: 11 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 @@ -52,6 +53,16 @@ export function fetchTab(courseId, tab, getTabData, targetUserId) {
},
}));
}

const { enabled } = await getCoursewareSearchEnabledFlag(courseId);
dispatch(addModel({
modelType: 'coursewareSearch',
model: {
id: courseId,
enabled,
},
}));

// Disable the access-denied path for now - it caused a regression
if (!courseHomeCourseMetadata.courseAccess.hasAccess) {
dispatch(fetchTabDenied({ courseId }));
Expand Down
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 data-testid="courseware-search" />
</div>
<div className="container-xl">
<Tabs
className="nav-underline-tabs"
Expand Down
19 changes: 19 additions & 0 deletions src/course-tabs/CourseTabsNavigation.test.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import React from 'react';
import { initializeMockApp, render, screen } from '../setupTest';
import { CourseTabsNavigation } from './index';
import { useModel } from '../generic/model-store';

jest.mock('../generic/model-store', () => ({
useModel: jest.fn(),
}));

describe('Course Tabs Navigation', () => {
beforeAll(async () => {
useModel.mockReturnValue({ enabled: false });
initializeMockApp();
});

Expand All @@ -29,4 +35,17 @@ describe('Course Tabs Navigation', () => {
expect(screen.getByRole('link', { name: tabs[1].title })).toHaveAttribute('href', tabs[1].url);
expect(screen.getByRole('link', { name: tabs[1].title })).not.toHaveClass('active');
});

it('does not render the CoursewareSearch component by default', () => {
render(<CourseTabsNavigation tabs={[]} />);

expect(screen.queryByTestId('courseware-search')).not.toBeInTheDocument();
});

it('renders the CoursewareSearch component if the waffle flag is enabled', () => {
useModel.mockReturnValue({ enabled: true });
render(<CourseTabsNavigation tabs={[]} />);

expect(screen.getByTestId('courseware-search')).toBeInTheDocument();
});
});

0 comments on commit 1036dce

Please sign in to comment.