mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
optionally scan tutorials directory recursively (#712)
Squashed commit of the following:
commit 5be2cb3103521d2ca1a14c24d4ccd776c1f2a5d9
Author: Jeff Williams <jeffrey.l.williams@gmail.com>
Date: Mon Nov 3 14:29:29 2014 -0800
make tutorials respect the --recurse option; refactor modules to facilitate testing; improve tests
commit 9af57751385439ceee3fac8f698a747a745c7c2b
Merge: 5399745 97a8ab0
Author: Jeff Williams <jeffrey.l.williams@gmail.com>
Date: Sat Nov 1 19:00:43 2014 -0700
Merge remote-tracking branch 'koalazak/master' into 712
Conflicts:
lib/jsdoc/opts/args.js
commit 97a8ab000b567c220525cc179c2f45b626236933
Author: zak <zak@ultra>
Date: Mon Jul 21 15:28:20 2014 -0300
Removed command-line option -U to recursive. Now is default. Added tests.
commit a79c9c9dac4eeb784e3f22b1da073c2af5b014cc
Author: zak <zak@ultra>
Date: Thu Jul 17 13:28:38 2014 -0300
Recurse 5 levels
commit 349d10e528d6ba797fd745e31e1e358ddcf26857
Author: koalazak <facu@Cacahuate.local>
Date: Wed Jul 16 22:30:41 2014 -0300
Travis CI ready ready
commit ffde2bf4bdc2bd0ba2daa20a58540e4a2dd099e8
Author: koalazak <facu@Cacahuate.local>
Date: Wed Jul 16 22:22:56 2014 -0300
Travis CI ready
commit 3e439151fb58d530abe294f1cc499e5fab7b8fe8
Author: koalazak <facu@Cacahuate.local>
Date: Wed Jul 16 21:47:22 2014 -0300
Optionally scan tutorials directory recursively
I do not want to have a directory of tutorials. I need to have the
tutorials distributed throughout the project. I have one in each
"package" folder.
This commit is contained in:
parent
5399745a97
commit
06acc6697a
@ -80,9 +80,9 @@ argParser.addOption('T', 'test', false, 'Run all tests and quit.');
|
||||
argParser.addOption('d', 'destination', true, 'The path to the output folder. Use "console" to dump data to the console. Default: ./out/');
|
||||
argParser.addOption('p', 'private', false, 'Display symbols marked with the @private tag. Default: false');
|
||||
argParser.addOption('r', 'recurse', false, 'Recurse into subdirectories when scanning for source code files.');
|
||||
argParser.addOption('h', 'help', false, 'Print this message and quit.');
|
||||
argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.');
|
||||
argParser.addOption('q', 'query', true, 'A query string to parse and store in env.opts.query. Example: foo=bar&baz=true', false, parseQuery);
|
||||
argParser.addOption('h', 'help', false, 'Print this message and quit.');
|
||||
argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.');
|
||||
argParser.addOption('q', 'query', true, 'A query string to parse and store in env.opts.query. Example: foo=bar&baz=true', false, parseQuery);
|
||||
argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should search for tutorials.');
|
||||
argParser.addOption('P', 'package', true, 'The path to the project\'s package file. Default: path/to/sourcefiles/package.json');
|
||||
argParser.addOption('R', 'readme', true, 'The path to the project\'s README file. Default: path/to/sourcefiles/README.md');
|
||||
|
||||
@ -6,6 +6,9 @@
|
||||
'use strict';
|
||||
|
||||
var markdown = require('jsdoc/util/markdown');
|
||||
var util = require('util');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
/** Removes child tutorial from the parent. Does *not* unset child.parent though.
|
||||
@param {Tutorial} parent - parent tutorial.
|
||||
@ -99,6 +102,35 @@ exports.Tutorial.prototype.parse = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Represents the root tutorial.
|
||||
* @extends {module:jsdoc/tutorial.Tutorial}
|
||||
*/
|
||||
exports.RootTutorial = function() {
|
||||
exports.RootTutorial.super_.call(this, '', '');
|
||||
|
||||
this._tutorials = {};
|
||||
};
|
||||
util.inherits(exports.RootTutorial, exports.Tutorial);
|
||||
|
||||
/**
|
||||
* Retrieve a tutorial by name.
|
||||
* @param {string} name - Tutorial name.
|
||||
* @return {module:jsdoc/tutorial.Tutorial} Tutorial instance.
|
||||
*/
|
||||
exports.RootTutorial.prototype.getByName = function(name) {
|
||||
return hasOwnProp.call(this._tutorials, name) && this._tutorials[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a child tutorial to the root.
|
||||
* @param {module:jsdoc/tutorial.Tutorial} child - Child tutorial.
|
||||
*/
|
||||
exports.RootTutorial.prototype._addTutorial = function(child) {
|
||||
this._tutorials[child.name] = child;
|
||||
};
|
||||
|
||||
/** Tutorial source types.
|
||||
@enum {number}
|
||||
*/
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
@overview
|
||||
@author Rafał Wrzeszcz <rafal.wrzeszcz@wrzasq.pl>
|
||||
@ -17,9 +16,9 @@ var tutorial = require('jsdoc/tutorial');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
// TODO: make this an instance member of `RootTutorial`?
|
||||
var conf = {};
|
||||
var finder = /^(.*)\.(x(?:ht)?ml|html?|md|markdown|json)$/i;
|
||||
var tutorials = {};
|
||||
|
||||
/** checks if `conf` is the metadata for a single tutorial.
|
||||
* A tutorial's metadata has a property 'title' and/or a property 'children'.
|
||||
@ -31,6 +30,12 @@ function isTutorialJSON(json) {
|
||||
return (hasOwnProp.call(json, 'title') || hasOwnProp.call(json, 'children'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Root tutorial.
|
||||
* @type {module:jsdoc/tutorial.Root}
|
||||
*/
|
||||
exports.root = new tutorial.RootTutorial();
|
||||
|
||||
/** Helper function that adds tutorial configuration to the `conf` variable.
|
||||
* This helps when multiple tutorial configurations are specified in one object,
|
||||
* or when a tutorial's children are specified as tutorial configurations as
|
||||
@ -49,13 +54,16 @@ function isTutorialJSON(json) {
|
||||
* OR an object giving the configuration for the child tutorials.
|
||||
*/
|
||||
function addTutorialConf(name, meta) {
|
||||
var names, i;
|
||||
var i;
|
||||
var l;
|
||||
var names;
|
||||
|
||||
if (isTutorialJSON(meta)) {
|
||||
// if the children are themselves tutorial defintions as opposed to an
|
||||
// array of strings, add each child.
|
||||
if (hasOwnProp.call(meta, 'children') && !Array.isArray(meta.children)) {
|
||||
names = Object.keys(meta.children);
|
||||
for (i = 0; i < names.length; ++i) {
|
||||
for (i = 0, l = names.length; i < l; ++i) {
|
||||
addTutorialConf(names[i], meta.children[names[i]]);
|
||||
}
|
||||
// replace with an array of names.
|
||||
@ -68,51 +76,40 @@ function addTutorialConf(name, meta) {
|
||||
conf[name] = meta;
|
||||
}
|
||||
} else {
|
||||
// it's an object of tutorials, the keys are th etutorial names.
|
||||
// keys are tutorial names, values are `Tutorial` instances
|
||||
names = Object.keys(meta);
|
||||
for (i = 0; i < names.length; ++i) {
|
||||
for (i = 0, l = names.length; i < l; ++i) {
|
||||
addTutorialConf(names[i], meta[names[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds new tutorial.
|
||||
@param {tutorial.Tutorial} current - New tutorial.
|
||||
/**
|
||||
* Add a tutorial.
|
||||
* @param {module:jsdoc/tutorial.Tutorial} current - Tutorial to add.
|
||||
*/
|
||||
exports.addTutorial = function(current) {
|
||||
if (hasOwnProp.call(tutorials, current.name)) {
|
||||
if (exports.root.getByName(current.name)) {
|
||||
logger.warn('The tutorial %s is defined more than once. Only the first definition will be used.', current.name);
|
||||
} else {
|
||||
tutorials[current.name] = current;
|
||||
|
||||
// default temporary parent
|
||||
// by default, the root tutorial is the parent
|
||||
current.setParent(exports.root);
|
||||
|
||||
exports.root._addTutorial(current);
|
||||
}
|
||||
};
|
||||
|
||||
/** Root tutorial.
|
||||
@type tutorial.Tutorial
|
||||
/**
|
||||
* Load tutorials from the given path.
|
||||
* @param {string} filepath - Tutorials directory.
|
||||
*/
|
||||
exports.root = new tutorial.Tutorial('', '');
|
||||
|
||||
/** Additional instance method for root node.
|
||||
@param {string} name - Tutorial name.
|
||||
@return {tutorial.Tutorial} Tutorial instance.
|
||||
*/
|
||||
exports.root.getByName = function(name) {
|
||||
return hasOwnProp.call(tutorials, name) && tutorials[name];
|
||||
};
|
||||
|
||||
/** Load tutorials from given path.
|
||||
@param {string} _path - Tutorials directory.
|
||||
*/
|
||||
exports.load = function(_path) {
|
||||
var match,
|
||||
type,
|
||||
name,
|
||||
content,
|
||||
current,
|
||||
files = fs.ls(_path);
|
||||
exports.load = function(filepath) {
|
||||
var content;
|
||||
var current;
|
||||
var files = fs.ls(filepath, global.env.opts.recurse ? 10 : undefined);
|
||||
var name;
|
||||
var match;
|
||||
var type;
|
||||
|
||||
// tutorials handling
|
||||
files.forEach(function(file) {
|
||||
@ -121,7 +118,7 @@ exports.load = function(_path) {
|
||||
// any filetype that can apply to tutorials
|
||||
if (match) {
|
||||
name = path.basename(match[1]);
|
||||
content = fs.readFileSync(file, env.opts.encoding);
|
||||
content = fs.readFileSync(file, global.env.opts.encoding);
|
||||
|
||||
switch (match[2].toLowerCase()) {
|
||||
// HTML type
|
||||
@ -160,34 +157,36 @@ exports.load = function(_path) {
|
||||
/** Resolves hierarchical structure.
|
||||
*/
|
||||
exports.resolve = function() {
|
||||
var item,
|
||||
current;
|
||||
for (var name in conf) {
|
||||
if ( hasOwnProp.call(conf, name) ) {
|
||||
// TODO: should we complain about this?
|
||||
if (!hasOwnProp.call(tutorials, name)) {
|
||||
continue;
|
||||
}
|
||||
var item;
|
||||
var current;
|
||||
|
||||
item = conf[name];
|
||||
current = tutorials[name];
|
||||
Object.keys(conf).forEach(function(name) {
|
||||
current = exports.root.getByName(name);
|
||||
|
||||
// set title
|
||||
if (item.title) {
|
||||
current.title = item.title;
|
||||
}
|
||||
|
||||
// add children
|
||||
if (item.children) {
|
||||
item.children.forEach(function(child) {
|
||||
if (!hasOwnProp.call(tutorials, child)) {
|
||||
logger.error('Missing child tutorial: %s', child);
|
||||
}
|
||||
else {
|
||||
tutorials[child].setParent(current);
|
||||
}
|
||||
});
|
||||
}
|
||||
// TODO: should we complain about this?
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
item = conf[name];
|
||||
|
||||
// set title
|
||||
if (item.title) {
|
||||
current.title = item.title;
|
||||
}
|
||||
|
||||
// add children
|
||||
if (item.children) {
|
||||
item.children.forEach(function(child) {
|
||||
var childTutorial = exports.root.getByName(child);
|
||||
|
||||
if (!childTutorial) {
|
||||
logger.error('Missing child tutorial: %s', child);
|
||||
}
|
||||
else {
|
||||
childTutorial.setParent(current);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/*global afterEach, beforeEach, describe, expect, it */
|
||||
'use strict';
|
||||
|
||||
describe('jsdoc/tutorial', function() {
|
||||
var tutorial = require('jsdoc/tutorial');
|
||||
|
||||
@ -24,6 +25,11 @@ describe('jsdoc/tutorial', function() {
|
||||
expect(typeof tutorial.Tutorial).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a RootTutorial function', function() {
|
||||
expect(tutorial.RootTutorial).toBeDefined();
|
||||
expect(typeof tutorial.RootTutorial).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a TYPES object', function() {
|
||||
expect(tutorial.TYPES).toBeDefined();
|
||||
expect(typeof tutorial.TYPES).toBe('object');
|
||||
@ -239,4 +245,40 @@ describe('jsdoc/tutorial', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('RootTutorial', function() {
|
||||
it('should inherit from Tutorial', function() {
|
||||
var root = new tutorial.RootTutorial();
|
||||
|
||||
expect(root instanceof tutorial.Tutorial).toBe(true);
|
||||
});
|
||||
|
||||
it('should have a "getByName" method', function() {
|
||||
expect(tutorial.RootTutorial.prototype.getByName).toBeDefined();
|
||||
expect(typeof tutorial.RootTutorial.prototype.getByName).toBe('function');
|
||||
});
|
||||
|
||||
describe('getByName', function() {
|
||||
var root;
|
||||
|
||||
beforeEach(function() {
|
||||
root = new tutorial.RootTutorial();
|
||||
});
|
||||
|
||||
it('can retrieve tutorials by name', function() {
|
||||
var myTutorial = new tutorial.Tutorial('myTutorial', '', tutorial.TYPES.HTML);
|
||||
root._addTutorial(myTutorial);
|
||||
|
||||
expect(root.getByName('myTutorial')).toBe(myTutorial);
|
||||
});
|
||||
|
||||
it('returns nothing for non-existent tutorials', function() {
|
||||
expect(root.getByName('asdf')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('uses hasOwnProperty when it checks for the tutorial', function() {
|
||||
expect(root.getByName('prototype')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,84 +1,113 @@
|
||||
/*global beforeEach, describe, env, expect, it, spyOn */
|
||||
describe("jsdoc/tutorial/resolver", function() {
|
||||
'use strict';
|
||||
|
||||
describe('jsdoc/tutorial/resolver', function() {
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var resolver = require('jsdoc/tutorial/resolver');
|
||||
var tutorial = require('jsdoc/tutorial');
|
||||
|
||||
it("should exist", function() {
|
||||
var childNames;
|
||||
var constr;
|
||||
var test;
|
||||
var test2;
|
||||
var test3;
|
||||
var test4;
|
||||
var test6;
|
||||
|
||||
function resetRootTutorial() {
|
||||
resolver.root = new tutorial.RootTutorial();
|
||||
}
|
||||
|
||||
function loadTutorials() {
|
||||
resetRootTutorial();
|
||||
|
||||
resolver.load(global.env.dirname + '/test/tutorials/tutorials');
|
||||
|
||||
childNames = resolver.root.children.map(function (t) { return t.name; });
|
||||
test = resolver.root.getByName('test');
|
||||
test2 = resolver.root.getByName('test2');
|
||||
test3 = resolver.root.getByName('test3');
|
||||
test4 = resolver.root.getByName('test4');
|
||||
test6 = resolver.root.getByName('test6');
|
||||
constr = resolver.root.getByName('constructor');
|
||||
}
|
||||
|
||||
it('should exist', function() {
|
||||
expect(resolver).toBeDefined();
|
||||
expect(typeof resolver).toBe('object');
|
||||
});
|
||||
|
||||
it("should export a 'addTutorial' function", function() {
|
||||
it('should export an "addTutorial" function', function() {
|
||||
expect(resolver.addTutorial).toBeDefined();
|
||||
expect(typeof resolver.addTutorial).toBe("function");
|
||||
expect(typeof resolver.addTutorial).toBe('function');
|
||||
});
|
||||
|
||||
it("should export a 'load' function", function() {
|
||||
it('should export a "load" function', function() {
|
||||
expect(resolver.load).toBeDefined();
|
||||
expect(typeof resolver.load).toBe("function");
|
||||
expect(typeof resolver.load).toBe('function');
|
||||
});
|
||||
|
||||
it("should export a 'resolve' function", function() {
|
||||
it('should export a "resolve" function', function() {
|
||||
expect(resolver.resolve).toBeDefined();
|
||||
expect(typeof resolver.resolve).toBe("function");
|
||||
expect(typeof resolver.resolve).toBe('function');
|
||||
});
|
||||
|
||||
it("should export a 'root' tutorial", function() {
|
||||
it('should export a "root" tutorial', function() {
|
||||
expect(resolver.root).toBeDefined();
|
||||
expect(resolver.root instanceof tutorial.Tutorial).toBe(true);
|
||||
expect(resolver.root instanceof tutorial.RootTutorial).toBe(true);
|
||||
});
|
||||
|
||||
it("exported 'root' tutorial should export a 'getByName' function", function() {
|
||||
it('exported "root" tutorial should export a "getByName" function', function() {
|
||||
expect(resolver.root.getByName).toBeDefined();
|
||||
expect(typeof resolver.root.getByName).toBe("function");
|
||||
expect(typeof resolver.root.getByName).toBe('function');
|
||||
});
|
||||
|
||||
// note: every time we addTutorial or run the resolver, we are *adding*
|
||||
// to the root tutorial.
|
||||
describe('addTutorial', function() {
|
||||
var tute;
|
||||
|
||||
// addTutorial
|
||||
var tute = new tutorial.Tutorial('myTutorial', '', tutorial.TYPES.HTML);
|
||||
resolver.addTutorial(tute);
|
||||
describe("addTutorial", function() {
|
||||
beforeEach(function() {
|
||||
resetRootTutorial();
|
||||
|
||||
it("should add a default parent of the root tutorial", function() {
|
||||
tute = new tutorial.Tutorial('myTutorial', '', tutorial.TYPES.HTML);
|
||||
resolver.addTutorial(tute);
|
||||
});
|
||||
|
||||
afterEach(resetRootTutorial);
|
||||
|
||||
it('should add a default parent of the root tutorial', function() {
|
||||
expect(tute.parent).toBe(resolver.root);
|
||||
});
|
||||
|
||||
it("should be added to the root tutorial as a child", function() {
|
||||
it('should be added to the root tutorial as a child', function() {
|
||||
expect(resolver.root.children).toContain(tute);
|
||||
});
|
||||
});
|
||||
|
||||
// root.getByName
|
||||
describe("root.getByName", function() {
|
||||
it("can retrieve tutorials by name", function() {
|
||||
expect(resolver.root.getByName('myTutorial')).toBe(tute);
|
||||
describe('load', function() {
|
||||
beforeEach(loadTutorials);
|
||||
|
||||
afterEach(resetRootTutorial);
|
||||
|
||||
it('does not, by default, recurse into subdirectories', function() {
|
||||
expect(resolver.root.getByName('test_recursive')).toBeFalsy();
|
||||
});
|
||||
|
||||
it("returns nothing for non-existent tutorials", function() {
|
||||
expect(resolver.root.getByName('asdf')).toBeFalsy();
|
||||
it('recurses into subdirectories when the --recurse flag is used', function() {
|
||||
var recurse = global.env.opts.recurse;
|
||||
var recursiveTute;
|
||||
|
||||
global.env.opts.recurse = true;
|
||||
loadTutorials();
|
||||
recursiveTute = resolver.root.getByName('test_recursive');
|
||||
|
||||
expect(recursiveTute).toBeDefined();
|
||||
expect(recursiveTute instanceof tutorial.Tutorial).toBe(true);
|
||||
|
||||
global.env.opts.recurse = recurse;
|
||||
});
|
||||
|
||||
it("is careful with tutorials whose names are reserved keywords in JS", function() {
|
||||
expect(resolver.root.getByName('prototype')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
// load
|
||||
resolver.load(env.dirname + "/test/tutorials/tutorials");
|
||||
var childNames = resolver.root.children.map(function (t) { return t.name; }),
|
||||
test = resolver.root.getByName('test'),
|
||||
test2 = resolver.root.getByName('test2'),
|
||||
test3 = resolver.root.getByName('test3'),
|
||||
test4 = resolver.root.getByName('test4'),
|
||||
test6 = resolver.root.getByName('test6'),
|
||||
constr = resolver.root.getByName('constructor');
|
||||
|
||||
describe("load", function() {
|
||||
|
||||
it("all tutorials are added, initially as top-level tutorials", function() {
|
||||
it('all tutorials are added, initially as top-level tutorials', function() {
|
||||
// check they were added
|
||||
expect(test).toBeDefined();
|
||||
expect(test2).toBeDefined();
|
||||
@ -94,16 +123,16 @@ describe("jsdoc/tutorial/resolver", function() {
|
||||
expect(childNames).toContain('test6');
|
||||
});
|
||||
|
||||
it("tutorials with names equal to reserved keywords in JS still function as expected", function() {
|
||||
it('tutorials with names equal to reserved keywords in JS still function as expected', function() {
|
||||
expect(constr instanceof tutorial.Tutorial).toBe(true);
|
||||
});
|
||||
|
||||
it("non-tutorials are skipped", function() {
|
||||
it('non-tutorials are skipped', function() {
|
||||
expect(resolver.root.getByName('multiple')).toBeFalsy();
|
||||
expect(resolver.root.getByName('test5')).toBeFalsy();
|
||||
});
|
||||
|
||||
it("tutorial types are determined correctly", function() {
|
||||
it('tutorial types are determined correctly', function() {
|
||||
// test.html, test2.markdown, test3.html, test4.md, test6.xml
|
||||
expect(test.type).toBe(tutorial.TYPES.HTML);
|
||||
expect(test2.type).toBe(tutorial.TYPES.MARKDOWN);
|
||||
@ -112,7 +141,6 @@ describe("jsdoc/tutorial/resolver", function() {
|
||||
expect(test6.type).toBe(tutorial.TYPES.HTML);
|
||||
expect(constr.type).toBe(tutorial.TYPES.MARKDOWN);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// resolve
|
||||
@ -123,11 +151,19 @@ describe("jsdoc/tutorial/resolver", function() {
|
||||
// |- test6
|
||||
// |- test3
|
||||
// |- test4
|
||||
describe("resolve", function() {
|
||||
resolver.resolve();
|
||||
it("hierarchy is resolved properly no matter how the children property is defined", function() {
|
||||
describe('resolve', function() {
|
||||
beforeEach(function() {
|
||||
spyOn(logger, 'error');
|
||||
spyOn(logger, 'warn');
|
||||
loadTutorials();
|
||||
resolver.resolve();
|
||||
});
|
||||
|
||||
afterEach(resetRootTutorial);
|
||||
|
||||
it('hierarchy is resolved properly no matter how the children property is defined', function() {
|
||||
// root has child 'test'
|
||||
expect(resolver.root.children.length).toBe(3);
|
||||
expect(resolver.root.children.length).toBe(2);
|
||||
expect(resolver.root.children).toContain(test);
|
||||
expect(resolver.root.children).toContain(constr);
|
||||
expect(test.parent).toBe(resolver.root);
|
||||
@ -151,50 +187,44 @@ describe("jsdoc/tutorial/resolver", function() {
|
||||
expect(test4.parent).toBe(test3);
|
||||
});
|
||||
|
||||
it("tutorials without configuration files have titles matching filenames", function() {
|
||||
it('tutorials without configuration files have titles matching filenames', function() {
|
||||
// test6.xml didn't have a metadata
|
||||
expect(test6.title).toBe('test6');
|
||||
});
|
||||
|
||||
it("tutorials with configuration files have titles as specified in configuration", function() {
|
||||
it('tutorials with configuration files have titles as specified in configuration', function() {
|
||||
// test.json had info for just test.json
|
||||
expect(test.title).toBe("Test tutorial");
|
||||
expect(test.title).toBe('Test tutorial');
|
||||
});
|
||||
|
||||
it("multiple tutorials can appear in a configuration file", function() {
|
||||
expect(test2.title).toBe("Test 2");
|
||||
expect(test3.title).toBe("Test 3");
|
||||
expect(test4.title).toBe("Test 4");
|
||||
});
|
||||
});
|
||||
|
||||
// error reporting.
|
||||
describe("Error reporting", function() {
|
||||
beforeEach(function() {
|
||||
spyOn(logger, 'error');
|
||||
spyOn(logger, 'warn');
|
||||
it('multiple tutorials can appear in a configuration file', function() {
|
||||
expect(test2.title).toBe('Test 2');
|
||||
expect(test3.title).toBe('Test 3');
|
||||
expect(test4.title).toBe('Test 4');
|
||||
});
|
||||
|
||||
it("logs an error for missing tutorials", function() {
|
||||
resolver.load(env.dirname + "/test/tutorials/incomplete");
|
||||
it('logs an error for missing tutorials', function() {
|
||||
resolver.load(global.env.dirname + '/test/tutorials/incomplete');
|
||||
resolver.resolve();
|
||||
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs a warning for duplicate-named tutorials (e.g. test.md, test.html)", function() {
|
||||
it('logs a warning for duplicate-named tutorials (e.g. test.md, test.html)', function() {
|
||||
var tute = new tutorial.Tutorial('myTutorial', '', tutorial.TYPES.HTML);
|
||||
resolver.addTutorial(tute);
|
||||
resolver.addTutorial(tute);
|
||||
|
||||
expect(logger.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs an error for tutorials defined twice in .json files", function() {
|
||||
// can't have a tutorial's metadata defined twice in .json files
|
||||
resolver.load(env.dirname + "/test/tutorials/duplicateDefined");
|
||||
it('allows tutorials to be defined in a .json file and redefined in another; the last one wins', function() {
|
||||
resolver.load(global.env.dirname + '/test/tutorials/duplicateDefined');
|
||||
resolver.resolve();
|
||||
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
expect(logger.error).not.toHaveBeenCalled();
|
||||
expect(logger.warn).toHaveBeenCalled();
|
||||
expect(resolver.root.getByName('asdf').title).toBe('Conflicting title');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
1
test/tutorials/tutorials/recursive/test_recursive.md
Normal file
1
test/tutorials/tutorials/recursive/test_recursive.md
Normal file
@ -0,0 +1 @@
|
||||
# test_recursive.md
|
||||
Loading…
x
Reference in New Issue
Block a user