test: add pact tests for courseware and course-home (#598)

This commit is contained in:
Ali Akbar
2021-08-23 20:02:31 +05:00
committed by GitHub
parent 2171c28825
commit 5087353e88
4 changed files with 541 additions and 49 deletions

View File

@@ -0,0 +1,222 @@
import { Pact, Matchers } from '@pact-foundation/pact';
import path from 'path';
import { mergeConfig, getConfig } from '@edx/frontend-platform';
import {
getCourseHomeCourseMetadata,
getDatesTabData,
} from '../api';
import { initializeMockApp } from '../../../setupTest';
import {
courseId, dateRegex, opaqueKeysRegex, dateTypeRegex,
} from '../../../pacts/constants';
const {
somethingLike: like, term, boolean, string, eachLike,
} = Matchers;
const provider = new Pact({
consumer: 'frontend-app-learning',
provider: 'lms',
log: path.resolve(process.cwd(), 'src/course-home/data/pact-tests/logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'src/pacts'),
pactfileWriteMode: 'merge',
logLevel: 'DEBUG',
cors: true,
});
describe('Course Home Service', () => {
beforeAll(async () => {
initializeMockApp();
await provider
.setup()
.then((options) => mergeConfig({
LMS_BASE_URL: `http://localhost:${options.port}`,
}, 'Custom app config for pact tests'));
});
afterEach(() => provider.verify());
afterAll(() => provider.finalize());
describe('When a request to fetch tab is made', () => {
it('returns tab data for a course_id', async () => {
await provider.addInteraction({
state: `Tab data exists for course_id ${courseId}`,
uponReceiving: 'a request to fetch tab',
withRequest: {
method: 'GET',
path: `/api/course_home/v1/course_metadata/${courseId}`,
},
willRespondWith: {
status: 200,
body: {
can_show_upgrade_sock: boolean(false),
verified_mode: like({
access_expiration_date: null,
currency: 'USD',
currency_symbol: '$',
price: 149,
sku: '8CF08E5',
upgrade_url: `${getConfig().ECOMMERCE_BASE_URL}/basket/add/?sku=8CF08E5`,
}),
can_load_courseware: boolean(true),
celebrations: like({
first_section: false,
streak_length_to_celebrate: null,
streak_discount_experiment_enabled: false,
}),
course_access: {
has_access: boolean(true),
error_code: null,
developer_message: null,
user_message: null,
additional_context_user_message: null,
user_fragment: null,
},
course_id: term({
generate: 'course-v1:edX+DemoX+Demo_Course',
matcher: opaqueKeysRegex,
}),
is_enrolled: boolean(true),
is_self_paced: boolean(false),
is_staff: boolean(true),
number: string('DemoX'),
org: string('edX'),
original_user_is_staff: boolean(true),
start: term({
generate: '2013-02-05T05:00:00Z',
matcher: dateRegex,
}),
tabs: eachLike({
tab_id: 'courseware',
title: 'Course',
url: `${getConfig().BASE_URL}/course/course-v1:edX+DemoX+Demo_Course/home`,
}),
title: string('Demonstration Course'),
username: string('edx'),
},
},
});
const normalizedTabData = {
canShowUpgradeSock: false,
verifiedMode: {
accessExpirationDate: null,
currency: 'USD',
currencySymbol: '$',
price: 149,
sku: '8CF08E5',
upgradeUrl: `${getConfig().ECOMMERCE_BASE_URL}/basket/add/?sku=8CF08E5`,
},
canLoadCourseware: true,
celebrations: {
firstSection: false,
streakLengthToCelebrate: null,
streakDiscountExperimentEnabled: false,
},
courseAccess: {
hasAccess: true,
errorCode: null,
developerMessage: null,
userMessage: null,
additionalContextUserMessage: null,
userFragment: null,
},
courseId: 'course-v1:edX+DemoX+Demo_Course',
isEnrolled: true,
isSelfPaced: false,
isStaff: true,
number: 'DemoX',
org: 'edX',
originalUserIsStaff: true,
start: '2013-02-05T05:00:00Z',
tabs: [
{
slug: 'outline',
title: 'Course',
url: `${getConfig().BASE_URL}/course/course-v1:edX+DemoX+Demo_Course/home`,
},
],
title: 'Demonstration Course',
username: 'edx',
};
const response = await getCourseHomeCourseMetadata(courseId);
expect(response).toBeTruthy();
expect(response).toEqual(normalizedTabData);
});
});
describe('When a request to fetch dates tab is made', () => {
it('returns course date blocks for a course_id', async () => {
await provider.addInteraction({
state: `course date blocks exist for course_id ${courseId}`,
uponReceiving: 'a request to fetch dates tab',
withRequest: {
method: 'GET',
path: `/api/course_home/v1/dates/${courseId}`,
},
willRespondWith: {
status: 200,
body: {
dates_banner_info: like({
missed_deadlines: false,
content_type_gating_enabled: false,
missed_gated_content: false,
verified_upgrade_link: `${getConfig().ECOMMERCE_BASE_URL}/basket/add/?sku=8CF08E5`,
}),
course_date_blocks: eachLike({
assignment_type: null,
complete: null,
date: term({
generate: '2013-02-05T05:00:00Z',
matcher: dateRegex,
}),
date_type: term({
generate: 'verified-upgrade-deadline',
matcher: dateTypeRegex,
}),
description: 'You are still eligible to upgrade to a Verified Certificate! Pursue it to highlight the knowledge and skills you gain in this course.',
learner_has_access: true,
link: `${getConfig().ECOMMERCE_BASE_URL}/basket/add/?sku=8CF08E5`,
link_text: 'Upgrade to Verified Certificate',
title: 'Verification Upgrade Deadline',
extra_info: null,
first_component_block_id: '',
}),
has_ended: boolean(false),
learner_is_full_access: boolean(true),
user_timezone: null,
},
},
});
const camelCaseResponse = {
datesBannerInfo: {
missedDeadlines: false,
contentTypeGatingEnabled: false,
missedGatedContent: false,
verifiedUpgradeLink: `${getConfig().ECOMMERCE_BASE_URL}/basket/add/?sku=8CF08E5`,
},
courseDateBlocks: [
{
assignmentType: null,
complete: null,
date: '2013-02-05T05:00:00Z',
dateType: 'verified-upgrade-deadline',
description: 'You are still eligible to upgrade to a Verified Certificate! Pursue it to highlight the knowledge and skills you gain in this course.',
learnerHasAccess: true,
link: `${getConfig().ECOMMERCE_BASE_URL}/basket/add/?sku=8CF08E5`,
linkText: 'Upgrade to Verified Certificate',
title: 'Verification Upgrade Deadline',
extraInfo: null,
firstComponentBlockId: '',
},
],
hasEnded: false,
learnerIsFullAccess: true,
userTimezone: null,
};
const response = await getDatesTabData(courseId);
expect(response).toBeTruthy();
expect(response).toEqual(camelCaseResponse);
});
});
});

View File

@@ -4,9 +4,19 @@ import { mergeConfig, getConfig } from '@edx/frontend-platform';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import {
getCourseBlocks, getCourseMetadata, getSequenceMetadata, postSequencePosition, getBlockCompletion,
getCourseBlocks,
getCourseMetadata,
getSequenceMetadata,
postSequencePosition,
getBlockCompletion,
getResumeBlock,
sendActivationEmail,
} from '../api';
import { initializeMockApp } from '../../../setupTest';
import {
courseId, dateRegex, opaqueKeysRegex, sequenceId, usageId,
} from '../../../pacts/constants';
const {
somethingLike: like, term, boolean, string, eachLike, integer,
@@ -15,17 +25,13 @@ const provider = new Pact({
consumer: 'frontend-app-learning',
provider: 'lms',
log: path.resolve(process.cwd(), 'src/courseware/data/pact-tests/logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'src/courseware/data/pact-tests'),
dir: path.resolve(process.cwd(), 'src/pacts'),
pactfileWriteMode: 'merge',
logLevel: 'DEBUG',
cors: true,
});
describe('Courseware Service', () => {
const courseId = 'course-v1:edX+DemoX+Demo_Course';
const sequenceId = 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions';
const usageId = 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@47dbd5f836544e61877a483c0b75606c';
const dateRegex = '^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:Z|[+-][01]\\d:[0-5]\\d)$';
const opaqueKeysRegex = '[\\w\\-~.:]';
let authenticatedUser;
beforeAll(async () => {
initializeMockApp();
@@ -57,8 +63,7 @@ describe('Courseware Service', () => {
},
willRespondWith: {
status: 200,
body:
{
body: {
root: string('block-v1:edX+DemoX+Demo_Course+type@course+block@course'),
blocks: like({
'block-v1:edX+DemoX+Demo_Course+type@course+block@course': {
@@ -105,8 +110,7 @@ describe('Courseware Service', () => {
},
willRespondWith: {
status: 200,
body:
{
body: {
access_expiration: {
expiration_date: term({
generate: '2013-02-05T05:00:00Z',
@@ -170,7 +174,10 @@ describe('Courseware Service', () => {
}),
user_timezone: null,
verified_mode: like({
access_expiration_date: null,
access_expiration_date: term({
generate: '2013-02-05T05:00:00Z',
matcher: dateRegex,
}),
currency: 'USD',
currency_symbol: '$',
price: 149,
@@ -182,7 +189,7 @@ describe('Courseware Service', () => {
can_view_legacy_courseware: boolean(true),
is_staff: boolean(true),
course_access: like({
has_access: boolean(true),
has_access: true,
error_code: null,
developer_message: null,
user_message: null,
@@ -192,7 +199,7 @@ describe('Courseware Service', () => {
notes: { enabled: boolean(false), visible: boolean(true) },
marketing_url: null,
celebrations: {
irst_section: boolean(false),
first_section: boolean(false),
streak_length_to_celebrate: null,
streak_discount_experiment_enabled: boolean(false),
},
@@ -251,28 +258,26 @@ describe('Courseware Service', () => {
isStaff: true,
license: 'all-rights-reserved',
verifiedMode: {
accessExpirationDate: null,
accessExpirationDate: '2013-02-05T05:00:00Z',
currency: 'USD',
currencySymbol: '$',
price: 149,
sku: '8CF08E5',
upgradeUrl: `${getConfig().ECOMMERCE_BASE_URL}/basket/add/?sku=8CF08E5`,
},
tabs: [
{
title: 'Course',
slug: 'courseware',
priority: 0,
type: 'courseware',
url: `${getConfig().BASE_URL}/course/course-v1:edX+DemoX+Demo_Course/home`,
},
],
tabs: [{
title: 'Course',
slug: 'courseware',
priority: 0,
type: 'courseware',
url: `${getConfig().BASE_URL}/course/course-v1:edX+DemoX+Demo_Course/home`,
}],
userTimezone: null,
showCalculator: false,
notes: { enabled: false, visible: true },
marketingUrl: null,
celebrations: {
irstSection: false,
firstSection: false,
streakLengthToCelebrate: null,
streakDiscountExperimentEnabled: false,
},
@@ -311,8 +316,7 @@ describe('Courseware Service', () => {
},
willRespondWith: {
status: 200,
body:
{
body: {
items: eachLike({
content: '',
page_title: 'Pointing on a Picture',
@@ -368,18 +372,16 @@ describe('Courseware Service', () => {
showCompletion: false,
allowProctoringOptOut: undefined,
},
units: [
{
id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@2152d4a4aadc4cb0af5256394a3d1fc7',
sequenceId: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions',
bookmarked: false,
complete: undefined,
title: 'Pointing on a Picture',
contentType: 'problem',
graded: true,
containsContentTypeGatedContent: false,
},
],
units: [{
id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@2152d4a4aadc4cb0af5256394a3d1fc7',
sequenceId: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions',
bookmarked: false,
complete: undefined,
title: 'Pointing on a Picture',
contentType: 'problem',
graded: true,
containsContentTypeGatedContent: false,
}],
};
const response = await getSequenceMetadata(sequenceId);
expect(response).toBeTruthy();
@@ -399,8 +401,7 @@ describe('Courseware Service', () => {
},
willRespondWith: {
status: 200,
body:
{
body: {
success: boolean(true),
},
},
@@ -423,8 +424,7 @@ describe('Courseware Service', () => {
},
willRespondWith: {
status: 200,
body:
{
body: {
complete: boolean(true),
},
},
@@ -434,4 +434,51 @@ describe('Courseware Service', () => {
expect(response).toEqual(true);
});
});
describe('When a request to get resume block is made', () => {
it('returns block id, section id and unit id of the resume block', async () => {
await provider.addInteraction({
state: `Resume block exists for course_id ${courseId}`,
uponReceiving: 'a request to get Resume block',
withRequest: {
method: 'GET',
path: `/api/courseware/resume/${courseId}`,
},
willRespondWith: {
status: 200,
body: {
block_id: string('642fadf46d074aabb637f20af320fb31'),
section_id: string('642fadf46d074aabb637f20af320fb87'),
unit_id: string('642fadf46d074aabb637f20af320fb99'),
},
},
});
const camelCaseResponse = {
blockId: '642fadf46d074aabb637f20af320fb31',
sectionId: '642fadf46d074aabb637f20af320fb87',
unitId: '642fadf46d074aabb637f20af320fb99',
};
const response = await getResumeBlock(courseId);
expect(response).toBeTruthy();
expect(response).toEqual(camelCaseResponse);
});
});
describe('When a request to send activation email is made', () => {
it('returns status code 200', async () => {
await provider.addInteraction({
state: 'A logged-in user may or may not be active',
uponReceiving: 'a request to send activation email',
withRequest: {
method: 'POST',
path: '/api/send_account_activation_email',
},
willRespondWith: {
status: 200,
},
});
const response = await sendActivationEmail();
expect(response).toEqual('');
});
});
});

6
src/pacts/constants.js Normal file
View File

@@ -0,0 +1,6 @@
export const courseId = 'course-v1:edX+DemoX+Demo_Course';
export const dateRegex = '^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:Z|[+-][01]\\d:[0-5]\\d)$';
export const opaqueKeysRegex = '[\\w\\-~.:]';
export const sequenceId = 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions';
export const usageId = 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@47dbd5f836544e61877a483c0b75606c';
export const dateTypeRegex = '^(event|todays-date|course-start-date|course-end-date|assignment-due-date|course-expired-date|certificate-available-date|verified-upgrade-deadline|verification-deadline-date)$';

View File

@@ -6,6 +6,180 @@
"name": "lms"
},
"interactions": [
{
"description": "a request to fetch tab",
"providerState": "Tab data exists for course_id course-v1:edX+DemoX+Demo_Course",
"request": {
"method": "GET",
"path": "/api/course_home/v1/course_metadata/course-v1:edX+DemoX+Demo_Course"
},
"response": {
"status": 200,
"headers": {
},
"body": {
"can_show_upgrade_sock": false,
"verified_mode": {
"access_expiration_date": null,
"currency": "USD",
"currency_symbol": "$",
"price": 149,
"sku": "8CF08E5",
"upgrade_url": "http://localhost:18130/basket/add/?sku=8CF08E5"
},
"can_load_courseware": true,
"celebrations": {
"first_section": false,
"streak_length_to_celebrate": null,
"streak_discount_experiment_enabled": false
},
"course_access": {
"has_access": true,
"error_code": null,
"developer_message": null,
"user_message": null,
"additional_context_user_message": null,
"user_fragment": null
},
"course_id": "course-v1:edX+DemoX+Demo_Course",
"is_enrolled": true,
"is_self_paced": false,
"is_staff": true,
"number": "DemoX",
"org": "edX",
"original_user_is_staff": true,
"start": "2013-02-05T05:00:00Z",
"tabs": [
{
"tab_id": "courseware",
"title": "Course",
"url": "http://localhost:2000/course/course-v1:edX+DemoX+Demo_Course/home"
}
],
"title": "Demonstration Course",
"username": "edx"
},
"matchingRules": {
"$.body.can_show_upgrade_sock": {
"match": "type"
},
"$.body.verified_mode": {
"match": "type"
},
"$.body.can_load_courseware": {
"match": "type"
},
"$.body.celebrations": {
"match": "type"
},
"$.body.course_access.has_access": {
"match": "type"
},
"$.body.course_id": {
"match": "regex",
"regex": "[\\w\\-~.:]"
},
"$.body.is_enrolled": {
"match": "type"
},
"$.body.is_self_paced": {
"match": "type"
},
"$.body.is_staff": {
"match": "type"
},
"$.body.number": {
"match": "type"
},
"$.body.org": {
"match": "type"
},
"$.body.original_user_is_staff": {
"match": "type"
},
"$.body.start": {
"match": "regex",
"regex": "^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:Z|[+-][01]\\d:[0-5]\\d)$"
},
"$.body.tabs": {
"min": 1
},
"$.body.tabs[*].*": {
"match": "type"
},
"$.body.title": {
"match": "type"
},
"$.body.username": {
"match": "type"
}
}
}
},
{
"description": "a request to fetch dates tab",
"providerState": "course date blocks exist for course_id course-v1:edX+DemoX+Demo_Course",
"request": {
"method": "GET",
"path": "/api/course_home/v1/dates/course-v1:edX+DemoX+Demo_Course"
},
"response": {
"status": 200,
"headers": {
},
"body": {
"dates_banner_info": {
"missed_deadlines": false,
"content_type_gating_enabled": false,
"missed_gated_content": false,
"verified_upgrade_link": "http://localhost:18130/basket/add/?sku=8CF08E5"
},
"course_date_blocks": [
{
"assignment_type": null,
"complete": null,
"date": "2013-02-05T05:00:00Z",
"date_type": "verified-upgrade-deadline",
"description": "You are still eligible to upgrade to a Verified Certificate! Pursue it to highlight the knowledge and skills you gain in this course.",
"learner_has_access": true,
"link": "http://localhost:18130/basket/add/?sku=8CF08E5",
"link_text": "Upgrade to Verified Certificate",
"title": "Verification Upgrade Deadline",
"extra_info": null,
"first_component_block_id": ""
}
],
"has_ended": false,
"learner_is_full_access": true,
"user_timezone": null
},
"matchingRules": {
"$.body.dates_banner_info": {
"match": "type"
},
"$.body.course_date_blocks": {
"min": 1
},
"$.body.course_date_blocks[*].*": {
"match": "type"
},
"$.body.course_date_blocks[*].date": {
"match": "regex",
"regex": "^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:Z|[+-][01]\\d:[0-5]\\d)$"
},
"$.body.course_date_blocks[*].date_type": {
"match": "regex",
"regex": "^(event|todays-date|course-start-date|course-end-date|assignment-due-date|course-expired-date|certificate-available-date|verified-upgrade-deadline|verification-deadline-date)$"
},
"$.body.has_ended": {
"match": "type"
},
"$.body.learner_is_full_access": {
"match": "type"
}
}
}
},
{
"description": "a request to get course blocks",
"providerState": "Blocks data exists for course_id course-v1:edX+DemoX+Demo_Course",
@@ -97,7 +271,7 @@
],
"user_timezone": null,
"verified_mode": {
"access_expiration_date": null,
"access_expiration_date": "2013-02-05T05:00:00Z",
"currency": "USD",
"currency_symbol": "$",
"price": 149,
@@ -122,7 +296,7 @@
},
"marketing_url": null,
"celebrations": {
"irst_section": false,
"first_section": false,
"streak_length_to_celebrate": null,
"streak_discount_experiment_enabled": false
},
@@ -232,6 +406,10 @@
"$.body.verified_mode": {
"match": "type"
},
"$.body.verified_mode.access_expiration_date": {
"match": "regex",
"regex": "^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:Z|[+-][01]\\d:[0-5]\\d)$"
},
"$.body.show_calculator": {
"match": "type"
},
@@ -247,16 +425,13 @@
"$.body.course_access": {
"match": "type"
},
"$.body.course_access.has_access": {
"match": "type"
},
"$.body.notes.enabled": {
"match": "type"
},
"$.body.notes.visible": {
"match": "type"
},
"$.body.celebrations.irst_section": {
"$.body.celebrations.first_section": {
"match": "type"
},
"$.body.celebrations.streak_discount_experiment_enabled": {
@@ -413,6 +588,48 @@
}
}
}
},
{
"description": "a request to get Resume block",
"providerState": "Resume block exists for course_id course-v1:edX+DemoX+Demo_Course",
"request": {
"method": "GET",
"path": "/api/courseware/resume/course-v1:edX+DemoX+Demo_Course"
},
"response": {
"status": 200,
"headers": {
},
"body": {
"block_id": "642fadf46d074aabb637f20af320fb31",
"section_id": "642fadf46d074aabb637f20af320fb87",
"unit_id": "642fadf46d074aabb637f20af320fb99"
},
"matchingRules": {
"$.body.block_id": {
"match": "type"
},
"$.body.section_id": {
"match": "type"
},
"$.body.unit_id": {
"match": "type"
}
}
}
},
{
"description": "a request to send activation email",
"providerState": "A logged-in user may or may not be active",
"request": {
"method": "POST",
"path": "/api/send_account_activation_email"
},
"response": {
"status": 200,
"headers": {
}
}
}
],
"metadata": {