From 7ccf049edb90ec60d47f27e93c12eae7da6ef9bd Mon Sep 17 00:00:00 2001 From: Leangseu Kim Date: Thu, 2 Mar 2023 15:25:29 -0500 Subject: [PATCH] fix: credit banner link --- .../CreditBanner/views/EligibleContent.jsx | 4 +- .../views/EligibleContent.test.jsx | 7 +--- .../CreditBanner/views/PendingContent.jsx | 21 ++++------ .../views/PendingContent.test.jsx | 18 ++------- src/data/services/lms/api.js | 3 +- src/data/services/lms/api.test.js | 5 +++ src/tracking/trackers/credit.js | 7 ++-- src/tracking/trackers/credit.test.js | 38 +++++++++++++++++++ 8 files changed, 65 insertions(+), 38 deletions(-) create mode 100644 src/tracking/trackers/credit.test.js diff --git a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.jsx b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.jsx index 2a48f5b..b38fdec 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.jsx +++ b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.jsx @@ -11,10 +11,10 @@ import messages from './messages'; export const EligibleContent = ({ cardId }) => { const { formatMessage } = useIntl(); - const { providerName, creditPurchaseUrl: href } = reduxHooks.useCardCreditData(cardId); + const { providerName } = reduxHooks.useCardCreditData(cardId); const { courseId } = reduxHooks.useCardCourseRunData(cardId); - const onClick = track.credit.purchase(courseId, href); + const onClick = track.credit.purchase(courseId); const getCredit = formatMessage(messages.getCredit); const message = providerName ? formatMessage(messages.eligibleFromProvider, { providerName }) diff --git a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.test.jsx b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.test.jsx index 87c4cd7..6dac70a 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.test.jsx +++ b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.test.jsx @@ -27,7 +27,6 @@ let component; const cardId = 'test-card-id'; const courseId = 'test-course-id'; const credit = { - creditPurchaseUrl: 'test-credit-purchase-url', providerName: 'test-credit-provider-name', }; reduxHooks.useCardCreditData.mockReturnValue(credit); @@ -58,16 +57,14 @@ describe('EligibleContent component', () => { }); test('action.onClick sends credit purchase track event', () => { expect(component.props().action.onClick).toEqual( - track.credit.purchase(courseId, credit.creditPurchaseUrl), + track.credit.purchase(courseId), ); }); test('action.message is formatted getCredit message', () => { expect(component.props().action.message).toEqual(formatMessage(messages.getCredit)); }); test('message is formatted eligible message if no provider', () => { - reduxHooks.useCardCreditData.mockReturnValueOnce({ - creditPurchaseUrl: credit.creditPurchaseUrl, - }); + reduxHooks.useCardCreditData.mockReturnValueOnce({}); render(); loadComponent(); expect(component.props().message).toEqual(formatMessage( diff --git a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.jsx b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.jsx index af3c680..1cfe552 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.jsx +++ b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.jsx @@ -6,23 +6,18 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { reduxHooks } from 'hooks'; import CreditContent from './components/CreditContent'; import messages from './messages'; -import hooks from './hooks'; export const PendingContent = ({ cardId }) => { - const { providerName } = reduxHooks.useCardCreditData(cardId); + const { providerStatusUrl: href, providerName } = reduxHooks.useCardCreditData(cardId); const { formatMessage } = useIntl(); - const { requestData, createCreditRequest } = hooks.useCreditRequestData(cardId); return ( - <> - - + ); }; PendingContent.propTypes = { diff --git a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.test.jsx b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.test.jsx index 79cd941..ca9ba13 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.test.jsx +++ b/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.test.jsx @@ -5,11 +5,9 @@ import { formatMessage } from 'testUtils'; import { reduxHooks } from 'hooks'; import messages from './messages'; -import hooks from './hooks'; import PendingContent from './PendingContent'; jest.mock('hooks', () => ({ reduxHooks: { useCardCreditData: jest.fn() } })); -jest.mock('./hooks', () => ({ useCreditRequestData: jest.fn() })); jest.mock('./components/CreditContent', () => 'CreditContent'); jest.mock('./components/ProviderLink', () => 'ProviderLink'); @@ -17,11 +15,9 @@ let el; let component; const cardId = 'test-card-id'; -const requestData = { test: 'requestData' }; const providerName = 'test-credit-provider-name'; -const createCreditRequest = jest.fn().mockName('createCreditRequest'); -reduxHooks.useCardCreditData.mockReturnValue({ providerName }); -hooks.useCreditRequestData.mockReturnValue({ requestData, createCreditRequest }); +const providerStatusUrl = 'test-credit-provider-status-url'; +reduxHooks.useCardCreditData.mockReturnValue({ providerName, providerStatusUrl }); const render = () => { el = shallow(); @@ -34,17 +30,14 @@ describe('PendingContent component', () => { it('initializes card credit data with cardId', () => { expect(reduxHooks.useCardCreditData).toHaveBeenCalledWith(cardId); }); - it('initializes credit request data with cardId', () => { - expect(hooks.useCreditRequestData).toHaveBeenCalledWith(cardId); - }); }); describe('render', () => { describe('rendered CreditContent component', () => { beforeEach(() => { component = el.find('CreditContent'); }); - test('action.onClick calls createCreditRequest from useCreditRequestData hook', () => { - expect(component.props().action.onClick).toEqual(createCreditRequest); + test('action.href will go to provider status site', () => { + expect(component.props().action.href).toEqual(providerStatusUrl); }); test('action.message is formatted requestCredit message', () => { expect(component.props().action.message).toEqual(formatMessage(messages.viewDetails)); @@ -54,9 +47,6 @@ describe('PendingContent component', () => { formatMessage(messages.received, { providerName }), ); }); - test('requestData drawn from useCreditRequestData hook', () => { - expect(component.props().requestData).toEqual(requestData); - }); }); }); }); diff --git a/src/data/services/lms/api.js b/src/data/services/lms/api.js index c8109fb..14d80bd 100644 --- a/src/data/services/lms/api.js +++ b/src/data/services/lms/api.js @@ -66,7 +66,6 @@ export const logShare = ({ courseId, site }) => module.logEvent({ }, }); -export const formDataHeaders = { 'Content-Type': 'multipart/form-data' }; export const createCreditRequest = ({ providerId, courseId, username }) => post( urls.creditRequestUrl(providerId), { course_key: courseId, username }, @@ -78,6 +77,8 @@ export default { updateEmailSettings, updateEntitlementEnrollment, deleteEntitlementEnrollment, + logEvent, logUpgrade, logShare, + createCreditRequest, }; diff --git a/src/data/services/lms/api.test.js b/src/data/services/lms/api.test.js index a59bf4c..cd3c179 100644 --- a/src/data/services/lms/api.test.js +++ b/src/data/services/lms/api.test.js @@ -32,6 +32,11 @@ describe('lms api methods', () => { beforeEach(() => { jest.clearAllMocks(); }); + test('keys identical to module', () => { + /* eslint-disable-next-line global-require */ + const { default: defaultApi, ...rest } = require('./api'); + expect(Object.keys(rest).sort()).toMatchObject(Object.keys(defaultApi).sort()); + }); describe('initializeList', () => { test('calls get with the correct url and user', () => { const userArg = { diff --git a/src/tracking/trackers/credit.js b/src/tracking/trackers/credit.js index 12982c7..b14175e 100644 --- a/src/tracking/trackers/credit.js +++ b/src/tracking/trackers/credit.js @@ -1,4 +1,5 @@ import { createEventTracker, createLinkTracker } from 'data/services/segment/utils'; +import { creditPurchaseUrl } from 'data/services/lms/urls'; import { categories, eventNames } from '../constants'; /** @@ -6,12 +7,12 @@ import { categories, eventNames } from '../constants'; * @param {string} fromCourseRun - course run identifier for leaving course * @return {callback} - callback that triggers the event tracker */ -export const purchase = (courseKey, href) => createLinkTracker( +export const purchase = (courseId) => createLinkTracker( createEventTracker(eventNames.purchaseCredit, { - label: courseKey, + label: courseId, category: categories.credit, }), - href, + creditPurchaseUrl(courseId), ); export default { diff --git a/src/tracking/trackers/credit.test.js b/src/tracking/trackers/credit.test.js new file mode 100644 index 0000000..69b536c --- /dev/null +++ b/src/tracking/trackers/credit.test.js @@ -0,0 +1,38 @@ +import { createEventTracker, createLinkTracker } from 'data/services/segment/utils'; +import { creditPurchaseUrl } from 'data/services/lms/urls'; + +import { eventNames, categories } from '../constants'; +import * as trackers from './credit'; + +jest.mock('data/services/segment/utils', () => ({ + createEventTracker: jest.fn(args => ({ createEventTracker: args })), + createLinkTracker: jest.fn((cb, href) => ({ createLinkTracker: { cb, href } })), +})); + +jest.mock('data/services/lms/urls', () => ({ + creditPurchaseUrl: jest.fn(courseId => `credit-purchase-url/${courseId}`), +})); + +const courseId = 'test-course-id'; + +describe('credit trackers', () => { + describe('purchase', () => { + it('creates a link tracker for purchase credit event with category and label', () => { + const purchasedEvent = trackers.purchase(courseId); + + expect(creditPurchaseUrl).toHaveBeenCalledWith(courseId); + expect(createEventTracker).toHaveBeenCalledWith(eventNames.purchaseCredit, { + label: courseId, + category: categories.credit, + }); + + expect(purchasedEvent).toEqual(createLinkTracker( + createEventTracker(eventNames.purchaseCredit, { + label: courseId, + category: categories.credit, + }), + creditPurchaseUrl(courseId), + )); + }); + }); +});