refactor: de-dupe factories between courseware and course-home (#400)
This commit is contained in:
59
src/shared/data/__factories__/block.factory.js
Normal file
59
src/shared/data/__factories__/block.factory.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
Factory.define('block')
|
||||
.option('courseId', 'course-v1:edX+DemoX+Demo_Course')
|
||||
.option('host', 'http://localhost:18000')
|
||||
// Generating block_id that is similar to md5 hash, but still deterministic
|
||||
.sequence('block_id', id => ('abcd'.repeat(8) + id).slice(-32))
|
||||
.attrs({
|
||||
complete: false,
|
||||
description: null,
|
||||
due: null,
|
||||
graded: false,
|
||||
icon: null,
|
||||
showLink: true,
|
||||
type: 'course',
|
||||
children: [],
|
||||
})
|
||||
.attr('display_name', ['display_name', 'block_id'], (displayName, blockId) => {
|
||||
if (displayName) {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
return blockId;
|
||||
})
|
||||
.attr(
|
||||
'id',
|
||||
['id', 'block_id', 'type', 'courseId'],
|
||||
(id, blockId, type, courseId) => {
|
||||
if (id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const courseInfo = courseId.split(':')[1];
|
||||
|
||||
return `block-v1:${courseInfo}+type@${type}+block@${blockId}`;
|
||||
},
|
||||
)
|
||||
.attr(
|
||||
'student_view_url',
|
||||
['student_view_url', 'host', 'id'],
|
||||
(url, host, id) => {
|
||||
if (url) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return `${host}/xblock/${id}`;
|
||||
},
|
||||
)
|
||||
.attr(
|
||||
'lms_web_url',
|
||||
['lms_web_url', 'host', 'courseId', 'id'],
|
||||
(url, host, courseId, id) => {
|
||||
if (url) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return `${host}/courses/${courseId}/jump_to/${id}`;
|
||||
},
|
||||
);
|
||||
142
src/shared/data/__factories__/courseBlocks.factory.js
Normal file
142
src/shared/data/__factories__/courseBlocks.factory.js
Normal file
@@ -0,0 +1,142 @@
|
||||
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import './block.factory';
|
||||
|
||||
// Generates an Array of block IDs, either from a single block or an array of blocks.
|
||||
const getIds = (attr) => {
|
||||
const blocks = Array.isArray(attr) ? attr : [attr];
|
||||
return blocks.map(block => block.id);
|
||||
};
|
||||
|
||||
// Generates an Object in { [block.id]: block } format, either from a single block or an array of blocks.
|
||||
const getBlocks = (attr) => {
|
||||
const blocks = Array.isArray(attr) ? attr : [attr];
|
||||
// eslint-disable-next-line no-return-assign,no-sequences
|
||||
return blocks.reduce((acc, block) => (acc[block.id] = block, acc), {});
|
||||
};
|
||||
|
||||
Factory.define('courseBlocks')
|
||||
.option('courseId', 'course-v1:edX+DemoX+Demo_Course')
|
||||
.option('units', ['courseId'], courseId => ([
|
||||
Factory.build(
|
||||
'block',
|
||||
{ type: 'vertical' },
|
||||
{ courseId },
|
||||
),
|
||||
]))
|
||||
.option('sequence', ['courseId', 'units'], (courseId, child) => Factory.build(
|
||||
'block',
|
||||
{ type: 'sequential', children: getIds(child) },
|
||||
{ courseId },
|
||||
))
|
||||
.option('section', ['courseId', 'sequence'], (courseId, child) => Factory.build(
|
||||
'block',
|
||||
{ type: 'chapter', children: getIds(child) },
|
||||
{ courseId },
|
||||
))
|
||||
.option('course', ['courseId', 'section'], (courseId, child) => Factory.build(
|
||||
'block',
|
||||
{ type: 'course', children: getIds(child) },
|
||||
{ courseId },
|
||||
))
|
||||
.attr(
|
||||
'blocks',
|
||||
['course', 'section', 'sequence', 'units'],
|
||||
(course, section, sequence, units) => ({
|
||||
[course.id]: course,
|
||||
...getBlocks(section),
|
||||
...getBlocks(sequence),
|
||||
...getBlocks(units),
|
||||
}),
|
||||
)
|
||||
.attr('root', ['course'], course => course.id);
|
||||
|
||||
/**
|
||||
* Builds a course with a single chapter, sequence, and unit.
|
||||
*/
|
||||
export function buildSimpleCourseBlocks(courseId, title, options = {}) {
|
||||
const unitBlocks = options.unitBlocks || [Factory.build(
|
||||
'block',
|
||||
{ type: 'vertical' },
|
||||
{ courseId },
|
||||
)];
|
||||
const sequenceBlock = options.sequenceBlock || [Factory.build(
|
||||
'block',
|
||||
{ type: 'sequential', children: unitBlocks.map(block => block.id) },
|
||||
{ courseId },
|
||||
)];
|
||||
const sectionBlock = options.sectionBlock || Factory.build(
|
||||
'block',
|
||||
{ type: 'chapter', children: sequenceBlock.map(block => block.id) },
|
||||
{ courseId },
|
||||
);
|
||||
const courseBlock = options.courseBlocks || Factory.build(
|
||||
'block',
|
||||
{ type: 'course', display_name: title, children: [sectionBlock.id] },
|
||||
{ courseId },
|
||||
);
|
||||
return {
|
||||
courseBlocks: options.courseBlocks || Factory.build(
|
||||
'courseBlocks',
|
||||
{
|
||||
courseId,
|
||||
hasScheduledContent: options.hasScheduledContent || false,
|
||||
title: 'Demo Course',
|
||||
},
|
||||
{
|
||||
units: unitBlocks,
|
||||
sequence: sequenceBlock,
|
||||
section: sectionBlock,
|
||||
course: courseBlock,
|
||||
},
|
||||
),
|
||||
unitBlocks,
|
||||
sequenceBlock,
|
||||
sectionBlock,
|
||||
courseBlock,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a course with a single chapter and sequence, but no units.
|
||||
*/
|
||||
export function buildMinimalCourseBlocks(courseId, title, options = {}) {
|
||||
const sequenceBlock = options.sequenceBlock || [Factory.build(
|
||||
'block',
|
||||
{ display_name: 'Title of Sequence', type: 'sequential' },
|
||||
{ courseId },
|
||||
)];
|
||||
const sectionBlock = options.sectionBlock || Factory.build(
|
||||
'block',
|
||||
{
|
||||
type: 'chapter',
|
||||
display_name: 'Title of Section',
|
||||
complete: options.complete || false,
|
||||
effort_time: 15,
|
||||
effort_activities: 2,
|
||||
resume_block: options.resumeBlock || false,
|
||||
children: sequenceBlock.map(block => block.id),
|
||||
},
|
||||
{ courseId },
|
||||
);
|
||||
const courseBlock = options.courseBlock || Factory.build(
|
||||
'block',
|
||||
{ type: 'course', display_name: title, children: [sectionBlock.id] },
|
||||
{ courseId },
|
||||
);
|
||||
return {
|
||||
courseBlocks: options.courseBlocks || Factory.build(
|
||||
'courseBlocks',
|
||||
{ courseId },
|
||||
{
|
||||
sequence: sequenceBlock,
|
||||
section: sectionBlock,
|
||||
course: courseBlock,
|
||||
units: [],
|
||||
},
|
||||
),
|
||||
unitBlocks: [],
|
||||
sequenceBlock,
|
||||
sectionBlock,
|
||||
courseBlock,
|
||||
};
|
||||
}
|
||||
83
src/shared/data/__factories__/courseMetadataBase.factory.js
Normal file
83
src/shared/data/__factories__/courseMetadataBase.factory.js
Normal file
@@ -0,0 +1,83 @@
|
||||
/* A basic course metadata factory, to be specialized in courseware and course-home., */
|
||||
|
||||
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
import './tab.factory';
|
||||
|
||||
export default new Factory()
|
||||
.sequence('id', (i) => `course-v1:edX+DemoX+Demo_Course_${i}`)
|
||||
.option('host')
|
||||
.attrs({
|
||||
is_staff: false,
|
||||
original_user_is_staff: false,
|
||||
number: 'DemoX',
|
||||
org: 'edX',
|
||||
})
|
||||
.attr(
|
||||
'tabs', ['id', 'host'], (id, host) => {
|
||||
const tabs = [
|
||||
Factory.build(
|
||||
'tab',
|
||||
{
|
||||
title: 'Course',
|
||||
priority: 0,
|
||||
slug: 'courseware',
|
||||
type: 'courseware',
|
||||
},
|
||||
{ courseId: id, host, path: 'course/' },
|
||||
),
|
||||
Factory.build(
|
||||
'tab',
|
||||
{
|
||||
title: 'Discussion',
|
||||
priority: 1,
|
||||
slug: 'discussion',
|
||||
type: 'discussion',
|
||||
},
|
||||
{ courseId: id, host, path: 'discussion/forum/' },
|
||||
),
|
||||
Factory.build(
|
||||
'tab',
|
||||
{
|
||||
title: 'Wiki',
|
||||
priority: 2,
|
||||
slug: 'wiki',
|
||||
type: 'wiki',
|
||||
},
|
||||
{ courseId: id, host, path: 'course_wiki' },
|
||||
),
|
||||
Factory.build(
|
||||
'tab',
|
||||
{
|
||||
title: 'Progress',
|
||||
priority: 3,
|
||||
slug: 'progress',
|
||||
type: 'progress',
|
||||
},
|
||||
{ courseId: id, host, path: 'progress' },
|
||||
),
|
||||
Factory.build(
|
||||
'tab',
|
||||
{
|
||||
title: 'Instructor',
|
||||
priority: 4,
|
||||
slug: 'instructor',
|
||||
type: 'instructor',
|
||||
},
|
||||
{ courseId: id, host, path: 'instructor' },
|
||||
),
|
||||
Factory.build(
|
||||
'tab',
|
||||
{
|
||||
title: 'Dates',
|
||||
priority: 5,
|
||||
slug: 'dates',
|
||||
type: 'dates',
|
||||
},
|
||||
{ courseId: id, host, path: 'dates' },
|
||||
),
|
||||
];
|
||||
|
||||
return tabs;
|
||||
},
|
||||
);
|
||||
4
src/shared/data/__factories__/index.js
Normal file
4
src/shared/data/__factories__/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import './block.factory';
|
||||
import './courseBlocks.factory';
|
||||
import './courseMetadataBase.factory';
|
||||
import './tab.factory';
|
||||
18
src/shared/data/__factories__/tab.factory.js
Normal file
18
src/shared/data/__factories__/tab.factory.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
Factory.define('tab')
|
||||
.option('courseId', 'course-v1:edX+DemoX+Demo_Course')
|
||||
.option('path', 'course/')
|
||||
.option('host', 'http://localhost:18000')
|
||||
.attrs({
|
||||
title: 'Course',
|
||||
priority: 0,
|
||||
slug: 'courseware',
|
||||
type: 'courseware',
|
||||
})
|
||||
.attr('tab_id', ['slug'], (slug) => slug)
|
||||
.attr(
|
||||
'url',
|
||||
['courseId', 'path', 'host'],
|
||||
(courseId, path, host) => `${host}/courses/${courseId}/${path}`,
|
||||
);
|
||||
Reference in New Issue
Block a user