fix: initial optimizely and segment events (#170)
This commit is contained in:
1
.env
1
.env
@@ -40,3 +40,4 @@ ACCOUNT_SETTINGS_URL=''
|
||||
ACCOUNT_PROFILE_URL=''
|
||||
ENABLE_NOTICES=''
|
||||
CAREER_LINK_URL=''
|
||||
OPTIMIZELY_FULL_STACK_SDK_KEY=''
|
||||
|
||||
@@ -47,3 +47,4 @@ ACCOUNT_SETTINGS_URL='http://localhost:1997'
|
||||
ACCOUNT_PROFILE_URL='http://localhost:1995'
|
||||
ENABLE_NOTICES=''
|
||||
CAREER_LINK_URL=''
|
||||
OPTIMIZELY_FULL_STACK_SDK_KEY=''
|
||||
|
||||
@@ -46,3 +46,4 @@ ACCOUNT_SETTINGS_URL='http://account-settings-url.test'
|
||||
ACCOUNT_PROFILE_URL='http://account-profile-url.test'
|
||||
ENABLE_NOTICES=''
|
||||
CAREER_LINK_URL=''
|
||||
OPTIMIZELY_FULL_STACK_SDK_KEY='SDK Key'
|
||||
|
||||
151
package-lock.json
generated
151
package-lock.json
generated
@@ -19,6 +19,7 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||
"@fortawesome/react-fontawesome": "^0.1.15",
|
||||
"@optimizely/react-sdk": "^2.9.2",
|
||||
"@redux-beacon/segment": "^1.1.0",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
@@ -4370,6 +4371,135 @@
|
||||
"@octokit/openapi-types": "^17.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/js-sdk-logging": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@optimizely/js-sdk-logging/-/js-sdk-logging-0.3.1.tgz",
|
||||
"integrity": "sha512-K71Jf283FP0E4oXehcXTTM3gvgHZHr7FUrIsw//0mdJlotHJT4Nss4hE0CWPbBxO7LJAtwNnO+VIA/YOcO4vHg==",
|
||||
"dependencies": {
|
||||
"@optimizely/js-sdk-utils": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/js-sdk-utils": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@optimizely/js-sdk-utils/-/js-sdk-utils-0.4.0.tgz",
|
||||
"integrity": "sha512-QG2oytnITW+VKTJK+l0RxjaS5VrA6W+AZMzpeg4LCB4Rn4BEKtF+EcW/5S1fBDLAviGq/0TLpkjM3DlFkJ9/Gw==",
|
||||
"dependencies": {
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/js-sdk-utils/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/optimizely-sdk": {
|
||||
"version": "4.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@optimizely/optimizely-sdk/-/optimizely-sdk-4.9.4.tgz",
|
||||
"integrity": "sha512-aYxndR6RahnLdX7SQR1YO2dklfNjbCGUUvRaYJZ50LIsDqhkAu426vxHwYO+V+QJxqipypPG5SVdG1m32AgDvw==",
|
||||
"dependencies": {
|
||||
"@optimizely/js-sdk-datafile-manager": "^0.9.5",
|
||||
"@optimizely/js-sdk-event-processor": "^0.9.2",
|
||||
"@optimizely/js-sdk-logging": "^0.3.1",
|
||||
"json-schema": "^0.4.0",
|
||||
"murmurhash": "0.0.2",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/optimizely-sdk/node_modules/@optimizely/js-sdk-datafile-manager": {
|
||||
"version": "0.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@optimizely/js-sdk-datafile-manager/-/js-sdk-datafile-manager-0.9.5.tgz",
|
||||
"integrity": "sha512-O4ujr1nBBAQBtx8YoKNpzzaEZgsE+aU4dxubT17ePqv/YVUWE+JOY21tSRrqZy/BlbbyzL+ElT8hrGB5ZzVoIQ==",
|
||||
"dependencies": {
|
||||
"@optimizely/js-sdk-logging": "^0.3.1",
|
||||
"@optimizely/js-sdk-utils": "^0.4.0",
|
||||
"decompress-response": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-native-async-storage/async-storage": "^1.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@react-native-async-storage/async-storage": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/optimizely-sdk/node_modules/@optimizely/js-sdk-event-processor": {
|
||||
"version": "0.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@optimizely/js-sdk-event-processor/-/js-sdk-event-processor-0.9.5.tgz",
|
||||
"integrity": "sha512-g5zqAjJuexxgbNvn7dacFkQXQxH3+OtjELfmSswvhxP9EHkyNR0ZdQF/kBxFxr335F2/RRPvAJ9tQBPkwaBg8g==",
|
||||
"dependencies": {
|
||||
"@optimizely/js-sdk-logging": "^0.3.1",
|
||||
"@optimizely/js-sdk-utils": "^0.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-native-async-storage/async-storage": "^1.2.0",
|
||||
"@react-native-community/netinfo": "5.9.4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@react-native-async-storage/async-storage": {
|
||||
"optional": true
|
||||
},
|
||||
"@react-native-community/netinfo": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/optimizely-sdk/node_modules/decompress-response": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
|
||||
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
|
||||
"dependencies": {
|
||||
"mimic-response": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/optimizely-sdk/node_modules/mimic-response": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
||||
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/optimizely-sdk/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@optimizely/react-sdk": {
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@optimizely/react-sdk/-/react-sdk-2.9.2.tgz",
|
||||
"integrity": "sha512-//OozC59dr5Lsss2H9Jnyb35FMTF8Z+CMFi89kVs1U1Fy1sKOXK7Web1hw18DBZctwKfbb8Sl+Yw7Pgmo3P2fA==",
|
||||
"dependencies": {
|
||||
"@optimizely/js-sdk-logging": "^0.3.1",
|
||||
"@optimizely/optimizely-sdk": "^4.9.1",
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"utility-types": "^2.1.0 || ^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz",
|
||||
@@ -16520,6 +16650,11 @@
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"node_modules/json-schema": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
|
||||
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
@@ -17573,6 +17708,14 @@
|
||||
"multicast-dns": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/murmurhash": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/murmurhash/-/murmurhash-0.0.2.tgz",
|
||||
"integrity": "sha512-LKlwdZKWzvCQpMszb2HO5leJ7P9T4m5XuDKku8bM0uElrzqK9cn0+iozwQS8jO4SNjrp4w7olalgd8WgsIjhWA==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
@@ -27075,6 +27218,14 @@
|
||||
"integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/utility-types": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
|
||||
"integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||
"@fortawesome/react-fontawesome": "^0.1.15",
|
||||
"@optimizely/react-sdk": "^2.9.2",
|
||||
"@redux-beacon/segment": "^1.1.0",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
|
||||
@@ -5,10 +5,12 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
crossProductCourses={
|
||||
Array [
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "executive-education-2u",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -16,14 +18,15 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "bootcamp-2u",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -31,7 +34,6 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
]
|
||||
@@ -39,10 +41,12 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
openCourses={
|
||||
Array [
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "verified-audit",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -50,14 +54,15 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "audit",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -65,14 +70,15 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "verified",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -80,14 +86,15 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "course",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -95,7 +102,6 @@ exports[`ProductRecommendations matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
]
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('ProductRecommendations ProductCard', () => {
|
||||
headerImage,
|
||||
schoolLogo,
|
||||
courseType: courseTypeToProductTypeMap[course.courseType],
|
||||
url: `https://www.edx.org/${course.prospectusPath}`,
|
||||
url: `${course.marketingUrl}&linked_from=recommender`,
|
||||
};
|
||||
|
||||
it('matches snapshot', () => {
|
||||
|
||||
@@ -22,7 +22,7 @@ const ProductCardContainer = ({ finalProductList, courseTypes }) => (
|
||||
.map((item) => (
|
||||
<ProductCard
|
||||
key={item.title}
|
||||
url={`https://www.edx.org/${item.prospectusPath}`}
|
||||
url={`${item.marketingUrl}&linked_from=recommender`}
|
||||
title={item.title}
|
||||
subtitle={item.owners[0].name}
|
||||
headerImage={item.image.src}
|
||||
|
||||
@@ -19,10 +19,12 @@ exports[`ProductRecommendations LoadedView matches snapshot 1`] = `
|
||||
finalProductList={
|
||||
Array [
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "executive-education-2u",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -30,14 +32,15 @@ exports[`ProductRecommendations LoadedView matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "bootcamp-2u",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -45,14 +48,15 @@ exports[`ProductRecommendations LoadedView matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "verified-audit",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -60,14 +64,15 @@ exports[`ProductRecommendations LoadedView matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
Object {
|
||||
"courseRunKey": "course-v1:Test+Course+2022T2",
|
||||
"courseType": "audit",
|
||||
"image": Object {
|
||||
"src": "https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg",
|
||||
},
|
||||
"marketingUrl": "https://www.edx.org/course/some-course?utm_source=source",
|
||||
"owners": Array [
|
||||
Object {
|
||||
"key": "HarvardX",
|
||||
@@ -75,7 +80,6 @@ exports[`ProductRecommendations LoadedView matches snapshot 1`] = `
|
||||
"name": "Harvard University",
|
||||
},
|
||||
],
|
||||
"prospectusPath": "course/introduction-to-computer-sceince",
|
||||
"title": "Introduction to Computer Science",
|
||||
},
|
||||
]
|
||||
|
||||
@@ -4,7 +4,7 @@ exports[`ProductRecommendations ProductCard matches snapshot 1`] = `
|
||||
<Card
|
||||
as="Hyperlink"
|
||||
className="base-card d-flex text-decoration-none"
|
||||
destination="https://www.edx.org/course/introduction-to-computer-sceince"
|
||||
destination="https://www.edx.org/course/some-course?utm_source=source&linked_from=recommender"
|
||||
isClickable={true}
|
||||
>
|
||||
<Card.ImageCap
|
||||
|
||||
@@ -20,7 +20,7 @@ exports[`ProductRecommendations ProductCardContainer matches snapshot 1`] = `
|
||||
schoolLogo="http://www.image.com/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png"
|
||||
subtitle="Harvard University"
|
||||
title="Introduction to Computer Science"
|
||||
url="https://www.edx.org/course/introduction-to-computer-sceince"
|
||||
url="https://www.edx.org/course/some-course?utm_source=source&linked_from=recommender"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,7 +40,7 @@ exports[`ProductRecommendations ProductCardContainer matches snapshot 1`] = `
|
||||
schoolLogo="http://www.image.com/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png"
|
||||
subtitle="Harvard University"
|
||||
title="Introduction to Computer Science"
|
||||
url="https://www.edx.org/course/introduction-to-computer-sceince"
|
||||
url="https://www.edx.org/course/some-course?utm_source=source&linked_from=recommender"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,7 +60,7 @@ exports[`ProductRecommendations ProductCardContainer matches snapshot 1`] = `
|
||||
schoolLogo="http://www.image.com/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png"
|
||||
subtitle="Harvard University"
|
||||
title="Introduction to Computer Science"
|
||||
url="https://www.edx.org/course/introduction-to-computer-sceince"
|
||||
url="https://www.edx.org/course/some-course?utm_source=source&linked_from=recommender"
|
||||
/>
|
||||
<ProductCard
|
||||
courseType="Course"
|
||||
@@ -69,7 +69,7 @@ exports[`ProductRecommendations ProductCardContainer matches snapshot 1`] = `
|
||||
schoolLogo="http://www.image.com/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png"
|
||||
subtitle="Harvard University"
|
||||
title="Introduction to Computer Science"
|
||||
url="https://www.edx.org/course/introduction-to-computer-sceince"
|
||||
url="https://www.edx.org/course/some-course?utm_source=source&linked_from=recommender"
|
||||
/>
|
||||
<ProductCard
|
||||
courseType="Course"
|
||||
@@ -78,7 +78,7 @@ exports[`ProductRecommendations ProductCardContainer matches snapshot 1`] = `
|
||||
schoolLogo="http://www.image.com/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png"
|
||||
subtitle="Harvard University"
|
||||
title="Introduction to Computer Science"
|
||||
url="https://www.edx.org/course/introduction-to-computer-sceince"
|
||||
url="https://www.edx.org/course/some-course?utm_source=source&linked_from=recommender"
|
||||
/>
|
||||
<ProductCard
|
||||
courseType="Course"
|
||||
@@ -87,7 +87,7 @@ exports[`ProductRecommendations ProductCardContainer matches snapshot 1`] = `
|
||||
schoolLogo="http://www.image.com/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png"
|
||||
subtitle="Harvard University"
|
||||
title="Introduction to Computer Science"
|
||||
url="https://www.edx.org/course/introduction-to-computer-sceince"
|
||||
url="https://www.edx.org/course/some-course?utm_source=source&linked_from=recommender"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { RequestStates, RequestKeys } from 'data/constants/requests';
|
||||
import { StrictDict } from 'utils';
|
||||
import { reduxHooks } from 'hooks';
|
||||
import { SortKeys } from 'data/constants/app';
|
||||
import { useWindowSize, breakpoints } from '@edx/paragon';
|
||||
import api from './api';
|
||||
import * as module from './hooks';
|
||||
|
||||
@@ -12,11 +12,15 @@ export const state = StrictDict({
|
||||
data: (val) => useState(val), // eslint-disable-line
|
||||
});
|
||||
|
||||
export const useIsMobile = () => {
|
||||
const { width } = useWindowSize();
|
||||
return width < breakpoints.small.minWidth;
|
||||
};
|
||||
|
||||
export const useShowRecommendationsFooter = () => {
|
||||
const hasAvailableDashboards = reduxHooks.useHasAvailableDashboards();
|
||||
const hasRequestCompleted = reduxHooks.useRequestIsCompleted(RequestKeys.initialize);
|
||||
|
||||
// Hardcoded to not show until experiment related code is implemented
|
||||
return {
|
||||
shouldShowFooter: false,
|
||||
shouldLoadFooter: hasRequestCompleted && !hasAvailableDashboards,
|
||||
@@ -83,4 +87,4 @@ export const useProductRecommendationsData = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export default { useProductRecommendationsData, useShowRecommendationsFooter };
|
||||
export default { useProductRecommendationsData, useShowRecommendationsFooter, useIsMobile };
|
||||
|
||||
@@ -4,6 +4,7 @@ import { waitFor } from '@testing-library/react';
|
||||
import { MockUseState } from 'testUtils';
|
||||
import { RequestStates } from 'data/constants/requests';
|
||||
import { reduxHooks } from 'hooks';
|
||||
import { useWindowSize } from '@edx/paragon';
|
||||
import { wait } from './utils';
|
||||
|
||||
import api from './api';
|
||||
@@ -67,6 +68,23 @@ describe('ProductRecommendations hooks', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIsMobile', () => {
|
||||
it('returns false if the width of the window is greater than or equal to 576px', () => {
|
||||
useWindowSize
|
||||
.mockReturnValueOnce({ width: 576, height: 943 })
|
||||
.mockReturnValueOnce({ width: 1400, height: 943 });
|
||||
|
||||
expect(hooks.useIsMobile()).toBeFalsy();
|
||||
expect(hooks.useIsMobile()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('returns true if the width of the window is less than 576px', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: 575, height: 943 });
|
||||
|
||||
expect(hooks.useIsMobile()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('useShowRecommendationsFooter', () => {
|
||||
// TODO: Update when hardcoded value is removed
|
||||
it('returns whether the footer widget should show and should load', () => {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import React from 'react';
|
||||
import { reduxHooks } from 'hooks';
|
||||
import './index.scss';
|
||||
import { useWindowSize, breakpoints } from '@edx/paragon';
|
||||
import { reduxHooks } from 'hooks';
|
||||
import NoCoursesView from 'containers/CourseList/NoCoursesView';
|
||||
import LoadingView from './components/LoadingView';
|
||||
import LoadedView from './components/LoadedView';
|
||||
import { useProductRecommendationsData } from './hooks';
|
||||
import hooks from './hooks';
|
||||
|
||||
const ProductRecommendations = () => {
|
||||
const checkEmptyResponse = (obj) => {
|
||||
@@ -14,9 +13,8 @@ const ProductRecommendations = () => {
|
||||
return result.length === values.length;
|
||||
};
|
||||
|
||||
const { productRecommendations, isLoading, isLoaded } = useProductRecommendationsData();
|
||||
const { width } = useWindowSize();
|
||||
const isMobile = width < breakpoints.small.minWidth;
|
||||
const { productRecommendations, isLoading, isLoaded } = hooks.useProductRecommendationsData();
|
||||
const isMobile = hooks.useIsMobile();
|
||||
const hasCourses = reduxHooks.useHasCourses();
|
||||
const shouldShowPlaceholder = checkEmptyResponse(productRecommendations);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { useWindowSize } from '@edx/paragon';
|
||||
import { reduxHooks } from 'hooks';
|
||||
import hooks from './hooks';
|
||||
import ProductRecommendations from './index';
|
||||
import LoadingView from './components/LoadingView';
|
||||
@@ -10,7 +10,13 @@ import { mockCrossProductResponse, mockAmplitudeResponse } from './testData';
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
useProductRecommendationsData: jest.fn(),
|
||||
useHasCourses: jest.fn(),
|
||||
useIsMobile: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('hooks', () => ({
|
||||
reduxHooks: {
|
||||
useHasCourses: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('./components/LoadingView', () => 'LoadingView');
|
||||
@@ -31,13 +37,10 @@ describe('ProductRecommendations', () => {
|
||||
productRecommendations: mockCrossProductResponse,
|
||||
};
|
||||
|
||||
const desktopWindowSize = {
|
||||
width: 1400,
|
||||
height: 943,
|
||||
};
|
||||
beforeEach(() => reduxHooks.useHasCourses.mockReturnValueOnce(true));
|
||||
|
||||
it('matches snapshot', () => {
|
||||
useWindowSize.mockReturnValueOnce(desktopWindowSize);
|
||||
hooks.useIsMobile.mockReturnValueOnce(false);
|
||||
hooks.useProductRecommendationsData.mockReturnValueOnce({
|
||||
...successfullLoadValues,
|
||||
});
|
||||
@@ -46,7 +49,7 @@ describe('ProductRecommendations', () => {
|
||||
});
|
||||
|
||||
it('renders the LoadingView if the request is pending', () => {
|
||||
useWindowSize.mockReturnValueOnce(desktopWindowSize);
|
||||
hooks.useIsMobile.mockReturnValueOnce(false);
|
||||
hooks.useProductRecommendationsData.mockReturnValueOnce({
|
||||
...defaultValues,
|
||||
isLoading: true,
|
||||
@@ -57,7 +60,7 @@ describe('ProductRecommendations', () => {
|
||||
);
|
||||
});
|
||||
it('renders nothing if the request has failed', () => {
|
||||
useWindowSize.mockReturnValueOnce(desktopWindowSize);
|
||||
hooks.useIsMobile.mockReturnValueOnce(false);
|
||||
hooks.useProductRecommendationsData.mockReturnValueOnce({
|
||||
...defaultValues,
|
||||
hasFailed: true,
|
||||
@@ -67,8 +70,8 @@ describe('ProductRecommendations', () => {
|
||||
|
||||
expect(wrapper.type()).toBeNull();
|
||||
});
|
||||
it('renders nothing if the width of the screen size is less than 576px (mobile view)', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: 575, height: 976 });
|
||||
it('renders nothing if the user is on the mobile view', () => {
|
||||
hooks.useIsMobile.mockReturnValueOnce(true);
|
||||
hooks.useProductRecommendationsData.mockReturnValueOnce({
|
||||
...successfullLoadValues,
|
||||
});
|
||||
@@ -79,7 +82,7 @@ describe('ProductRecommendations', () => {
|
||||
});
|
||||
|
||||
it('renders NoCoursesView if the request is loaded, user has courses, and the response is empty', () => {
|
||||
useWindowSize.mockReturnValueOnce(desktopWindowSize);
|
||||
hooks.useIsMobile.mockReturnValueOnce(false);
|
||||
hooks.useProductRecommendationsData.mockReturnValueOnce({
|
||||
...successfullLoadValues,
|
||||
productRecommendations: {
|
||||
@@ -87,7 +90,6 @@ describe('ProductRecommendations', () => {
|
||||
crossProductCourses: [],
|
||||
},
|
||||
});
|
||||
hooks.useHasCourses.mockReturnValueOnce(true);
|
||||
|
||||
expect(shallow(<ProductRecommendations />)).toMatchObject(
|
||||
shallow(<NoCoursesView />),
|
||||
@@ -96,11 +98,10 @@ describe('ProductRecommendations', () => {
|
||||
|
||||
describe('LoadedView', () => {
|
||||
it('renders with cross product data if the request completed and the user has courses', () => {
|
||||
useWindowSize.mockReturnValueOnce(desktopWindowSize);
|
||||
hooks.useIsMobile.mockReturnValueOnce(false);
|
||||
hooks.useProductRecommendationsData.mockReturnValueOnce({
|
||||
...successfullLoadValues,
|
||||
});
|
||||
hooks.useHasCourses.mockReturnValueOnce(true);
|
||||
|
||||
expect(shallow(<ProductRecommendations />)).toMatchObject(
|
||||
shallow(
|
||||
@@ -113,12 +114,11 @@ describe('ProductRecommendations', () => {
|
||||
});
|
||||
|
||||
it('renders the LoadedView with Amplitude course data if the request completed', () => {
|
||||
useWindowSize.mockReturnValueOnce(desktopWindowSize);
|
||||
hooks.useIsMobile.mockReturnValueOnce(false);
|
||||
hooks.useProductRecommendationsData.mockReturnValueOnce({
|
||||
...successfullLoadValues,
|
||||
productRecommendations: mockAmplitudeResponse,
|
||||
});
|
||||
hooks.useHasCourses.mockReturnValueOnce(true);
|
||||
|
||||
expect(shallow(<ProductRecommendations />)).toMatchObject(
|
||||
shallow(
|
||||
|
||||
9
src/widgets/ProductRecommendations/optimizely.js
Normal file
9
src/widgets/ProductRecommendations/optimizely.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { createInstance } from '@optimizely/react-sdk';
|
||||
|
||||
const OPTIMIZELY_SDK_KEY = process.env.OPTIMIZELY_FULL_STACK_SDK_KEY;
|
||||
|
||||
const optimizelyClient = createInstance({
|
||||
sdkKey: OPTIMIZELY_SDK_KEY,
|
||||
});
|
||||
|
||||
export default optimizelyClient;
|
||||
13
src/widgets/ProductRecommendations/optimizely.test.js
Normal file
13
src/widgets/ProductRecommendations/optimizely.test.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { createInstance } from '@optimizely/react-sdk';
|
||||
import optimizelyClient from './optimizely';
|
||||
|
||||
jest.mock('@optimizely/react-sdk', () => ({
|
||||
createInstance: jest.fn(() => 'mockedClient'),
|
||||
}));
|
||||
|
||||
describe('optimizelyClient', () => {
|
||||
it('should create an Optimizely client instance with the correct SDK key', () => {
|
||||
expect(optimizelyClient).toBeDefined();
|
||||
expect(createInstance).toHaveBeenCalledWith({ sdkKey: 'SDK Key' });
|
||||
});
|
||||
});
|
||||
38
src/widgets/ProductRecommendations/optimizelyExperiment.js
Normal file
38
src/widgets/ProductRecommendations/optimizelyExperiment.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { StrictDict } from 'utils';
|
||||
import optimizelyClient from './optimizely';
|
||||
|
||||
export const PRODUCT_RECOMMENDATIONS_EXP_KEY = 'learner_dashboard_product_recommendations_exp';
|
||||
export const PRODUCT_RECOMMENDATIONS_EXP_VARIATION = 'learner_dashboard_product_recommendations_enabled';
|
||||
|
||||
export const eventNames = StrictDict({
|
||||
productRecommendationsViewed: 'product_recommendations_viewed',
|
||||
productHeaderClicked: 'product_header_clicked',
|
||||
productCardClicked: 'product_card_clicked',
|
||||
courseCardClicked: 'course_card_clicked',
|
||||
});
|
||||
|
||||
export const activateProductRecommendationsExperiment = (userId, userAttributes) => {
|
||||
const variation = optimizelyClient?.activate(
|
||||
PRODUCT_RECOMMENDATIONS_EXP_KEY,
|
||||
userId,
|
||||
userAttributes,
|
||||
);
|
||||
|
||||
return variation === PRODUCT_RECOMMENDATIONS_EXP_VARIATION;
|
||||
};
|
||||
|
||||
export const trackProductRecommendationsViewed = (userId, userAttributes = {}) => {
|
||||
optimizelyClient.track(eventNames.productRecommendationsViewed, userId, userAttributes);
|
||||
};
|
||||
|
||||
export const trackProductHeaderClicked = (userId, userAttributes = {}) => {
|
||||
optimizelyClient.track(eventNames.productHeaderClicked, userId, userAttributes);
|
||||
};
|
||||
|
||||
export const trackProductCardClicked = (userId, userAttributes = {}) => {
|
||||
optimizelyClient.track(eventNames.productCardClicked, userId, userAttributes);
|
||||
};
|
||||
|
||||
export const trackCourseCardClicked = (userId, userAttributes = {}) => {
|
||||
optimizelyClient.track(eventNames.courseCardClicked, userId, userAttributes);
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
import optimizelyClient from './optimizely';
|
||||
import {
|
||||
eventNames,
|
||||
PRODUCT_RECOMMENDATIONS_EXP_KEY,
|
||||
PRODUCT_RECOMMENDATIONS_EXP_VARIATION,
|
||||
activateProductRecommendationsExperiment,
|
||||
trackProductRecommendationsViewed,
|
||||
trackProductHeaderClicked,
|
||||
trackProductCardClicked,
|
||||
trackCourseCardClicked,
|
||||
} from './optimizelyExperiment';
|
||||
|
||||
jest.mock('./optimizely', () => ({
|
||||
activate: jest.fn(),
|
||||
track: jest.fn(),
|
||||
}));
|
||||
|
||||
const userId = '1';
|
||||
const userAttributes = {
|
||||
is_enterprise_user: false,
|
||||
location: 'us',
|
||||
is_mobile_user: false,
|
||||
};
|
||||
|
||||
describe('Optimizely events', () => {
|
||||
describe('activateProductRecommendationsExperiment', () => {
|
||||
it('activates the experiment and returns in recommendations experiment variant', () => {
|
||||
optimizelyClient.activate.mockReturnValueOnce(PRODUCT_RECOMMENDATIONS_EXP_VARIATION);
|
||||
const inRecommendationsVariant = activateProductRecommendationsExperiment(userId, userAttributes);
|
||||
|
||||
expect(inRecommendationsVariant).toBeTruthy();
|
||||
expect(optimizelyClient.activate).toHaveBeenCalledWith(
|
||||
PRODUCT_RECOMMENDATIONS_EXP_KEY,
|
||||
userId,
|
||||
userAttributes,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('trackProductRecommendationsViewed', () => {
|
||||
it('sends the productRecommendationsViewed event', () => {
|
||||
trackProductRecommendationsViewed(userId);
|
||||
expect(optimizelyClient.track).toHaveBeenCalledWith(
|
||||
eventNames.productRecommendationsViewed,
|
||||
userId,
|
||||
{},
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('trackProductHeaderClicked', () => {
|
||||
it('sends the productHeaderClicked event', () => {
|
||||
trackProductHeaderClicked(userId);
|
||||
expect(optimizelyClient.track).toHaveBeenCalledWith(
|
||||
eventNames.productHeaderClicked,
|
||||
userId,
|
||||
{},
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('trackProductCardClicked', () => {
|
||||
it('sends the productCardClicked event', () => {
|
||||
trackProductCardClicked(userId);
|
||||
expect(optimizelyClient.track).toHaveBeenCalledWith(
|
||||
eventNames.productCardClicked,
|
||||
userId,
|
||||
{},
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('trackCourseCardClicked', () => {
|
||||
it('sends the courseCardClicked event', () => {
|
||||
trackCourseCardClicked(userId);
|
||||
expect(optimizelyClient.track).toHaveBeenCalledWith(
|
||||
eventNames.courseCardClicked,
|
||||
userId,
|
||||
{},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4,10 +4,12 @@ export const getCoursesWithType = (courseTypes) => {
|
||||
courseTypes.forEach((type) => {
|
||||
courses.push({
|
||||
title: 'Introduction to Computer Science',
|
||||
courseRunKey: 'course-v1:Test+Course+2022T2',
|
||||
marketingUrl: 'https://www.edx.org/course/some-course?utm_source=source',
|
||||
courseType: type,
|
||||
image: {
|
||||
src: 'https://www.image-2.com/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg',
|
||||
},
|
||||
prospectusPath: 'course/introduction-to-computer-sceince',
|
||||
owners: [
|
||||
{
|
||||
key: 'HarvardX',
|
||||
@@ -15,7 +17,6 @@ export const getCoursesWithType = (courseTypes) => {
|
||||
logoImageUrl: 'http://www.image.com/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png',
|
||||
},
|
||||
],
|
||||
courseType: type,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
55
src/widgets/ProductRecommendations/track.js
Normal file
55
src/widgets/ProductRecommendations/track.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { StrictDict } from 'utils';
|
||||
import { createLinkTracker, createEventTracker } from 'data/services/segment/utils';
|
||||
import { courseTypeToProductLineMap, convertCourseRunKeyToCourseKey } from './utils';
|
||||
|
||||
export const eventNames = StrictDict({
|
||||
productCardClicked: 'edx.bi.2u-product-card.clicked',
|
||||
discoveryCardClicked: 'edx.bi.user.discovery.card.click',
|
||||
recommendationsHeaderClicked: 'edx.bi.link.recommendations.header.clicked',
|
||||
recommendationsViewed: 'edx.bi.user.recommendations.viewed',
|
||||
});
|
||||
|
||||
export const productCardClicked = (courseRunKey, courseTitle, courseType, href) => {
|
||||
createLinkTracker(
|
||||
createEventTracker(eventNames.productCardClicked, {
|
||||
category: 'recommender',
|
||||
label: courseTitle,
|
||||
courserun_key: courseRunKey,
|
||||
page: 'dashboard',
|
||||
product_line: courseTypeToProductLineMap[courseType],
|
||||
}),
|
||||
href,
|
||||
);
|
||||
};
|
||||
|
||||
export const discoveryCardClicked = (courseRunKey, courseTitle, href) => {
|
||||
createLinkTracker(
|
||||
createEventTracker(eventNames.discoveryCardClicked, {
|
||||
category: 'recommender',
|
||||
label: courseTitle,
|
||||
courserun_key: courseRunKey,
|
||||
page: 'dashboard',
|
||||
product_line: 'open-course',
|
||||
}),
|
||||
href,
|
||||
);
|
||||
};
|
||||
|
||||
export const recommendationsHeaderClicked = (courseType, href) => {
|
||||
createLinkTracker(
|
||||
createEventTracker(eventNames.recommendationsHeaderClicked, {
|
||||
category: 'recommender',
|
||||
page: 'dashboard',
|
||||
product_line: courseTypeToProductLineMap[courseType],
|
||||
}),
|
||||
href,
|
||||
);
|
||||
};
|
||||
|
||||
export const recommendationsViewed = (isControl, courseRunKey) => {
|
||||
createEventTracker(eventNames.recommendationsViewed, {
|
||||
is_control: isControl,
|
||||
page: 'dashboard',
|
||||
course_key: convertCourseRunKeyToCourseKey(courseRunKey),
|
||||
});
|
||||
};
|
||||
98
src/widgets/ProductRecommendations/track.test.js
Normal file
98
src/widgets/ProductRecommendations/track.test.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import { createLinkTracker, createEventTracker } from 'data/services/segment/utils';
|
||||
import {
|
||||
eventNames,
|
||||
productCardClicked,
|
||||
discoveryCardClicked,
|
||||
recommendationsHeaderClicked,
|
||||
recommendationsViewed,
|
||||
} from './track';
|
||||
|
||||
jest.mock('data/services/segment/utils', () => ({
|
||||
createEventTracker: jest.fn((args) => ({ createEventTracker: args })),
|
||||
createLinkTracker: jest.fn((args) => ({ createLinkTracker: args })),
|
||||
}));
|
||||
|
||||
const courseKey = 'MITx+5.0.01';
|
||||
const courseRunKeyNew = `course-v1:${courseKey}+2022T2`;
|
||||
const courseRunKeyOld = 'MITx/5.0.01/2022T2/';
|
||||
const label = 'Web Design';
|
||||
const headerLink = 'https://www.edx.org/search?tab=course?linked_from=recommender';
|
||||
const courseUrl = 'https://www.edx.org/course/some-course';
|
||||
const category = 'recommender';
|
||||
|
||||
describe('product recommendations trackers', () => {
|
||||
describe('recommendationsViewed', () => {
|
||||
describe('with old course run key format', () => {
|
||||
it('creates an event tracker for when cross product recommendations are present', () => {
|
||||
recommendationsViewed(false, courseRunKeyOld);
|
||||
expect(createEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.recommendationsViewed,
|
||||
{
|
||||
is_control: false,
|
||||
page: 'dashboard',
|
||||
course_key: courseKey,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('with new course run key format', () => {
|
||||
it('creates an event tracker for when cross product recommendations are present', () => {
|
||||
recommendationsViewed(false, courseRunKeyNew);
|
||||
expect(createEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.recommendationsViewed,
|
||||
{
|
||||
is_control: false,
|
||||
page: 'dashboard',
|
||||
course_key: courseKey,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('recommendationsHeaderClicked', () => {
|
||||
it('creates a link tracker for when a recommendations header is clicked', () => {
|
||||
const attributes = {
|
||||
category,
|
||||
product_line: 'open-courses',
|
||||
page: 'dashboard',
|
||||
};
|
||||
const args = [eventNames.recommendationsHeaderClicked, attributes];
|
||||
|
||||
recommendationsHeaderClicked('Course', headerLink);
|
||||
expect(createEventTracker).toHaveBeenCalledWith(...args);
|
||||
expect(createLinkTracker).toHaveBeenCalledWith(createEventTracker(...args), headerLink);
|
||||
});
|
||||
});
|
||||
describe('discoveryCardClicked', () => {
|
||||
it('creates a link tracker for when a open course card is clicked', () => {
|
||||
const attributes = {
|
||||
category,
|
||||
label,
|
||||
courserun_key: courseRunKeyNew,
|
||||
page: 'dashboard',
|
||||
product_line: 'open-course',
|
||||
};
|
||||
const args = [eventNames.discoveryCardClicked, attributes];
|
||||
|
||||
discoveryCardClicked(courseRunKeyNew, label, courseUrl);
|
||||
expect(createEventTracker).toHaveBeenCalledWith(...args);
|
||||
expect(createLinkTracker).toHaveBeenCalledWith(createEventTracker(...args), courseUrl);
|
||||
});
|
||||
});
|
||||
describe('productCardClicked', () => {
|
||||
it('creates a link tracker for when a cross product course card is clicked', () => {
|
||||
const attributes = {
|
||||
category,
|
||||
label,
|
||||
courserun_key: courseRunKeyNew,
|
||||
page: 'dashboard',
|
||||
product_line: 'boot-camps',
|
||||
};
|
||||
const args = [eventNames.productCardClicked, attributes];
|
||||
|
||||
productCardClicked(courseRunKeyNew, label, 'Boot Camp', courseUrl);
|
||||
expect(createEventTracker).toHaveBeenCalledWith(...args);
|
||||
expect(createLinkTracker).toHaveBeenCalledWith(createEventTracker(...args), courseUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -36,6 +36,23 @@ export const courseTypeToProductTypeMap = {
|
||||
'masters-verified-audit': "Master's",
|
||||
};
|
||||
|
||||
export const courseTypeToProductLineMap = {
|
||||
'Executive Education': 'executive-education',
|
||||
'Boot Camp': 'boot-camps',
|
||||
Course: 'open-courses',
|
||||
};
|
||||
|
||||
export const convertCourseRunKeyToCourseKey = (courseRunKey) => {
|
||||
const newKeyFormat = courseRunKey.includes('+');
|
||||
if (newKeyFormat) {
|
||||
const splitCourseRunKey = courseRunKey.split(':').slice(-1)[0];
|
||||
const splitCourseKey = splitCourseRunKey.split('+').slice(0, 2);
|
||||
return `${splitCourseKey[0]}+${splitCourseKey[1]}`;
|
||||
}
|
||||
const splitCourseKey = courseRunKey.split('/').slice(0, 2);
|
||||
return `${splitCourseKey[0]}+${splitCourseKey[1]}`;
|
||||
};
|
||||
|
||||
export const wait = (time) => new Promise((resolve) => {
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user