Clean up spec and feature; both pass lint and run in Karma
This commit is contained in:
@@ -170,7 +170,8 @@ function junitSettings(config) {
|
||||
* @param {String} pattern
|
||||
* @return {String}
|
||||
*/
|
||||
var defaultNormalizeFunc = function(appRoot, pattern) {
|
||||
// I'd like to change fix the no-shadow violation on the next line, but it would break this shared conf's API.
|
||||
function defaultNormalizeFunc(appRoot, pattern) { // eslint-disable-line no-shadow
|
||||
if (pattern.match(/^common\/js/)) {
|
||||
pattern = path.join(appRoot, '/common/static/' + pattern);
|
||||
} else if (pattern.match(/^xmodule_js\/common_static/)) {
|
||||
@@ -178,9 +179,9 @@ var defaultNormalizeFunc = function(appRoot, pattern) {
|
||||
pattern.replace(/^xmodule_js\/common_static\//, ''));
|
||||
}
|
||||
return pattern;
|
||||
};
|
||||
}
|
||||
|
||||
var normalizePathsForCoverage = function(files, normalizeFunc, preprocessors) {
|
||||
function normalizePathsForCoverage(files, normalizeFunc, preprocessors) {
|
||||
var normalizeFn = normalizeFunc || defaultNormalizeFunc,
|
||||
normalizedFile,
|
||||
filesForCoverage = {};
|
||||
@@ -193,7 +194,7 @@ var normalizePathsForCoverage = function(files, normalizeFunc, preprocessors) {
|
||||
});
|
||||
|
||||
return filesForCoverage;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets defaults for each file pattern.
|
||||
@@ -202,7 +203,7 @@ var normalizePathsForCoverage = function(files, normalizeFunc, preprocessors) {
|
||||
* @param {Object} files
|
||||
* @return {Object}
|
||||
*/
|
||||
var setDefaults = function(files) {
|
||||
function setDefaults(files) {
|
||||
return files.map(function(f) {
|
||||
var file = _.isObject(f) ? f : {pattern: f};
|
||||
if (!file.included && !file.webpack) {
|
||||
@@ -210,9 +211,9 @@ var setDefaults = function(files) {
|
||||
}
|
||||
return file;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
var getBaseConfig = function(config, useRequireJs) {
|
||||
function getBaseConfig(config, useRequireJs) {
|
||||
var getFrameworkFiles = function() {
|
||||
var files = [
|
||||
'node_modules/jquery/dist/jquery.js',
|
||||
@@ -347,9 +348,9 @@ var getBaseConfig = function(config, useRequireJs) {
|
||||
|
||||
webpack: webpackConfig
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
var configure = function(config, options) {
|
||||
function configure(config, options) {
|
||||
var useRequireJs = options.useRequireJs === undefined ? true : useRequireJs,
|
||||
baseConfig = getBaseConfig(config, useRequireJs);
|
||||
|
||||
@@ -397,7 +398,7 @@ var configure = function(config, options) {
|
||||
files: files,
|
||||
preprocessors: preprocessors
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
configure: configure,
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
import * as constants from 'edx-ui-toolkit/src/js/utils/constants';
|
||||
import log from 'logger';
|
||||
/* globals Logger */
|
||||
|
||||
export class CourseOutline {
|
||||
constructor(root) {
|
||||
document.querySelector(root).addEventListener('keydown', (event) => {
|
||||
const focusable = [...document.querySelectorAll('.outline-item.focusable')];
|
||||
const currentFocusIndex = focusable.indexOf(event.target);
|
||||
// import constants from 'edx-ui-toolkit/src/js/utils/constants';
|
||||
|
||||
switch (event.keyCode) { // eslint-disable-line default-case
|
||||
case constants.keyCodes.down:
|
||||
// @TODO: Figure out how to make webpack handle default exports when libraryTarget: 'window'
|
||||
export class CourseOutline { // eslint-disable-line import/prefer-default-export
|
||||
constructor() {
|
||||
const focusable = [...document.querySelectorAll('.outline-item.focusable')];
|
||||
|
||||
focusable.forEach(el => el.addEventListener('keydown', (event) => {
|
||||
const index = focusable.indexOf(event.target);
|
||||
|
||||
switch (event.key) { // eslint-disable-line default-case
|
||||
case 'ArrowDown': // @TODO: Get these from the UI Toolkit
|
||||
event.preventDefault();
|
||||
focusable[Math.min(currentFocusIndex + 1, focusable.length - 1)].focus();
|
||||
focusable[Math.min(index + 1, focusable.length - 1)].focus();
|
||||
break;
|
||||
case constants.keyCodes.up:
|
||||
case 'ArrowUp': // @TODO: Get these from the UI Toolkit
|
||||
event.preventDefault();
|
||||
focusable[Math.max(currentFocusIndex - 1, 0)].focus();
|
||||
focusable[Math.max(index - 1, 0)].focus();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
document.querySelectorAll('a:not([href^="#"])').addEventListener('click', (event) => {
|
||||
log(
|
||||
'edx.ui.lms.link_clicked',
|
||||
{
|
||||
current_url: window.location.href,
|
||||
target_url: event.currentTarget.href
|
||||
}
|
||||
document.querySelectorAll('a:not([href^="#"])')
|
||||
.forEach(link => link.addEventListener('click', (event) => {
|
||||
Logger.log(
|
||||
'edx.ui.lms.link_clicked',
|
||||
{
|
||||
current_url: window.location.href,
|
||||
target_url: event.currentTarget.href,
|
||||
},
|
||||
);
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +1,64 @@
|
||||
import * as constants from "edx-ui-toolkit/js/utils/constants";
|
||||
import log from 'logger';
|
||||
import { CourseOutline } from "../CourseOutline";
|
||||
/* globals Logger, loadFixtures */
|
||||
|
||||
// import constants from 'edx-ui-toolkit/src/js/utils/constants';
|
||||
|
||||
import { CourseOutline } from '../CourseOutline';
|
||||
|
||||
describe('Course outline factory', () => {
|
||||
let outline; // eslint-disable-line no-unused-vars
|
||||
|
||||
// Our block IDs are invalid DOM selectors unless we first escape `:`, `+` and `@`
|
||||
const escapeIds = idObj => Object.assign({}, ...Object.keys(idObj).map(key => ({
|
||||
[key]: idObj[key]
|
||||
.replace(/@/g, '\\@')
|
||||
.replace(/:/, '\\:')
|
||||
.replace(/\+/g, '\\+'),
|
||||
})));
|
||||
|
||||
const outlineIds = escapeIds({
|
||||
homeworkLabsAndDemos: 'a#block-v1:edX+DemoX+Demo_Course+type@sequential+block@graded_simulations',
|
||||
homeworkEssays: 'a#block-v1:edX+DemoX+Demo_Course+type@sequential+block@175e76c4951144a29d46211361266e0e',
|
||||
lesson3BeSocial: 'a#block-v1:edX+DemoX+Demo_Course+type@sequential+block@48ecb924d7fe4b66a230137626bfa93e',
|
||||
exampleWeek3BeSocial: 'li#block-v1:edX+DemoX+Demo_Course+type@chapter+block@social_integration',
|
||||
});
|
||||
|
||||
describe('keyboard listener', () => {
|
||||
const triggerKeyListener = (current, destination, keyCode) => {
|
||||
const triggerKeyListener = (current, destination, key) => {
|
||||
current.focus();
|
||||
spyOn(destination, 'focus');
|
||||
|
||||
$('.block-tree').trigger(
|
||||
$.Event('keydown', {
|
||||
keyCode,
|
||||
target: current,
|
||||
}),
|
||||
);
|
||||
current.dispatchEvent(new KeyboardEvent('keydown', { key }));
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
loadFixtures('course_experience/fixtures/course-outline-fragment.html');
|
||||
new CourseOutline('.block-tree');
|
||||
outline = new CourseOutline();
|
||||
});
|
||||
|
||||
describe('when the down arrow is pressed', () => {
|
||||
it('moves focus from a subsection to the next subsection in the outline', () => {
|
||||
const current = $('a.focusable:contains("Homework - Labs and Demos")')[0];
|
||||
const destination = $('a.focusable:contains("Homework - Essays")')[0];
|
||||
const current = document.querySelector(outlineIds.homeworkLabsAndDemos);
|
||||
const destination = document.querySelector(outlineIds.homeworkEssays);
|
||||
|
||||
triggerKeyListener(current, destination, constants.keyCodes.down);
|
||||
triggerKeyListener(current, destination, 'ArrowDown'); // @TODO: Get these from the UI Toolkit
|
||||
|
||||
expect(destination.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('moves focus to the section list if at a section boundary', () => {
|
||||
const current = $('li.focusable:contains("Example Week 3: Be Social")')[0];
|
||||
const destination = $('ol.focusable:contains("Lesson 3 - Be Social")')[0];
|
||||
it('moves focus to the subsection list if at the top of a section', () => {
|
||||
const current = document.querySelector(outlineIds.exampleWeek3BeSocial);
|
||||
const destination = document.querySelector(`${outlineIds.exampleWeek3BeSocial} > ol`);
|
||||
|
||||
triggerKeyListener(current, destination, constants.keyCodes.down);
|
||||
triggerKeyListener(current, destination, 'ArrowDown'); // @TODO: Get these from the UI Toolkit
|
||||
|
||||
expect(destination.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('moves focus to the next section if on the last subsection', () => {
|
||||
const current = $('a.focusable:contains("Homework - Essays")')[0];
|
||||
const destination = $('li.focusable:contains("Example Week 3: Be Social")')[0];
|
||||
const current = document.querySelector(outlineIds.homeworkEssays);
|
||||
const destination = document.querySelector(outlineIds.exampleWeek3BeSocial);
|
||||
|
||||
triggerKeyListener(current, destination, constants.keyCodes.down);
|
||||
triggerKeyListener(current, destination, 'ArrowDown'); // @TODO: Get these from the UI Toolkit
|
||||
|
||||
expect(destination.focus).toHaveBeenCalled();
|
||||
});
|
||||
@@ -52,53 +66,48 @@ describe('Course outline factory', () => {
|
||||
|
||||
describe('when the up arrow is pressed', () => {
|
||||
it('moves focus from a subsection to the previous subsection in the outline', () => {
|
||||
const current = $('a.focusable:contains("Homework - Essays")')[0];
|
||||
const destination = $('a.focusable:contains("Homework - Labs and Demos")')[0];
|
||||
const current = document.querySelector(outlineIds.homeworkEssays);
|
||||
const destination = document.querySelector(outlineIds.homeworkLabsAndDemos);
|
||||
|
||||
triggerKeyListener(current, destination, constants.keyCodes.up);
|
||||
triggerKeyListener(current, destination, 'ArrowUp'); // @TODO: Get these from the UI Toolkit
|
||||
|
||||
expect(destination.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('moves focus to the section group if at the first subsection', () => {
|
||||
const current = $('a.focusable:contains("Lesson 3 - Be Social")')[0];
|
||||
const destination = $('ol.focusable:contains("Lesson 3 - Be Social")')[0];
|
||||
it('moves focus to the section list if at the first subsection', () => {
|
||||
const current = document.querySelector(outlineIds.lesson3BeSocial);
|
||||
const destination = document.querySelector(`${outlineIds.exampleWeek3BeSocial} > ol`);
|
||||
|
||||
triggerKeyListener(current, destination, constants.keyCodes.up);
|
||||
triggerKeyListener(current, destination, 'ArrowUp'); // @TODO: Get these from the UI Toolkit
|
||||
|
||||
expect(destination.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('moves focus last subsection of the previous section if at a section boundary', () => {
|
||||
const current = $('li.focusable:contains("Example Week 3: Be Social")')[0];
|
||||
const destination = $('a.focusable:contains("Homework - Essays")')[0];
|
||||
const current = document.querySelector(outlineIds.exampleWeek3BeSocial);
|
||||
const destination = document.querySelector(outlineIds.homeworkEssays);
|
||||
|
||||
triggerKeyListener(current, destination, constants.keyCodes.up);
|
||||
triggerKeyListener(current, destination, 'ArrowUp'); // @TODO: Get these from the UI Toolkit
|
||||
|
||||
expect(destination.focus).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("eventing", function() {
|
||||
beforeEach(function() {
|
||||
loadFixtures("course_experience/fixtures/course-outline-fragment.html");
|
||||
CourseOutlineFactory(".block-tree");
|
||||
spyOn(Logger, "log");
|
||||
describe('eventing', () => {
|
||||
beforeEach(() => {
|
||||
loadFixtures('course_experience/fixtures/course-outline-fragment.html');
|
||||
outline = new CourseOutline();
|
||||
spyOn(Logger, 'log');
|
||||
});
|
||||
|
||||
it("sends an event when an outline section is clicked", function() {
|
||||
$('a.focusable:contains("Homework - Labs and Demos")').click();
|
||||
it('sends an event when an outline section is clicked', () => {
|
||||
document.querySelector(outlineIds.homeworkLabsAndDemos).dispatchEvent(new Event('click'));
|
||||
|
||||
expect(Logger.log).toHaveBeenCalledWith("edx.ui.lms.link_clicked", {
|
||||
target_url: (
|
||||
window.location.origin +
|
||||
"/courses/course-v1:edX+DemoX+Demo_Course/jump_to/block-v1:edX+DemoX+Demo_Course+type" +
|
||||
"@sequential+block@graded_simulations"
|
||||
),
|
||||
current_url: window.location.toString()
|
||||
expect(Logger.log).toHaveBeenCalledWith('edx.ui.lms.link_clicked', {
|
||||
target_url: `${window.location.origin}/courses/course-v1:edX+DemoX+Demo_Course/jump_to/block-v1:edX+DemoX+Demo_Course+type@sequential+block@graded_simulations`,
|
||||
current_url: window.location.toString(),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -161,5 +161,5 @@ from openedx.core.djangolib.markup import HTML, Text
|
||||
</%static:require_module_async>
|
||||
|
||||
<%static:webpack entry="CourseOutline">
|
||||
new CourseOutline('.block-tree');
|
||||
new CourseOutline();
|
||||
</%static:webpack>
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const BundleTracker = require('webpack-bundle-tracker');
|
||||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
var BundleTracker = require('webpack-bundle-tracker');
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
var isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
const wpconfig = {
|
||||
context: __dirname,
|
||||
var wpconfig = {
|
||||
context: __dirname,
|
||||
|
||||
entry: {
|
||||
CourseOutline: './openedx/features/course_experience/static/course_experience/js/CourseOutline.js',
|
||||
},
|
||||
entry: {
|
||||
CourseOutline: './openedx/features/course_experience/static/course_experience/js/CourseOutline.js'
|
||||
},
|
||||
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'common/static/bundles'),
|
||||
filename: '[name]-[hash].js',
|
||||
libraryTarget: 'window',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'common/static/bundles'),
|
||||
filename: '[name]-[hash].js',
|
||||
libraryTarget: 'window'
|
||||
},
|
||||
|
||||
devtool: isProd ? false : 'cheap-eval-source-map',
|
||||
devtool: isProd ? false : 'eval-source-map',
|
||||
|
||||
plugins: [
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
new webpack.NamedModulesPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: !isProd,
|
||||
}),
|
||||
new BundleTracker({
|
||||
filename: './webpack-stats.json'
|
||||
}),
|
||||
],
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: 'babel-loader',
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
new webpack.NamedModulesPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: !isProd
|
||||
}),
|
||||
new BundleTracker({
|
||||
filename: './webpack-stats.json'
|
||||
})
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.json'],
|
||||
}
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: 'babel-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: ['.js', '.json']
|
||||
}
|
||||
};
|
||||
|
||||
if (isProd) {
|
||||
wpconfig.plugins = [
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true,
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin(),
|
||||
...wpconfig.plugins,
|
||||
];
|
||||
wpconfig.plugins = wpconfig.plugins.concat([
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin()
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = wpconfig;
|
||||
|
||||
Reference in New Issue
Block a user