pipe('模式:path', function (done) { var router = new Router({ mode: 'path' }); var matched = false; var origin = location.href; router .match('/', function (next) { next('/abc'); }) .match('/abc', function () { matched = true; }); plan .task(function (next) { history.replaceState(null, null, '/'); router.start(); delay(next); }) .task(function (next) { expect(location.pathname).toBe('/abc'); router.destroy(); history.replaceState(null, null, origin); delay(next); }) .serial(done); });
pipe('边界:具名路由销毁之后才完成控制器加载', function (done) { var router = new Router(); var beforeChangeTimes = 0; var afterChangeTimes = 0; router.on('beforeChange', function () { beforeChangeTimes++; }); router.on('afterChange', function () { afterChangeTimes++; }); router.match('/', function (next) { setTimeout(function () { next(); }, 10000); }); router.start(); router.destroy(); plan .task(function (next) { expect(beforeChangeTimes).toBe(1); expect(afterChangeTimes).toBe(0); delay(next); }) .serial(done); });
pipe('边界:同时间内只解析一次', function (done) { var router = new Router(); var matchTimes = 0; router.match(function (next) { matchTimes++; setTimeout(function () { next(); }, 300); }); router.start(); plan .task(function (next) { expect(location.hash.replace('#', '')).toBe(''); location.hash = '#/xxx'; delay(next); }) .task(function (next) { expect(location.hash.replace('#', '')).toBe('/xxx'); expect(matchTimes).toBe(1); router.destroy(); delay(next); }).serial(done); });
pipe('边界:相同路由只触发一次', function (done) { var router = new Router(); var changeTimes = 0; router.match('/a', function () { changeTimes++; }); router.start(); plan .task(function (next) { location.hash = '/a?a=1&b=2&c=3&c=4&c=5'; delay(next); }) .task(function (next) { location.hash = '/a?b=2&a=1&c=3&c=5&c=4'; delay(next); }) .task(function (next) { expect(changeTimes).toBe(1); router.destroy(); delay(next); }) .serial(done); });
pipe('#rewrite base', function (done) { var changeTimes = 0; var router = new Router(); router.on('beforeChange', function () { changeTimes++; }); router.start(); plan .task(function (next) { router.rewrite('/a'); delay(next); }) .task(function (next) { router.destroy(); delay(next); }) .task(function (next) { expect(changeTimes).toEqual(2); expect(location.hash).toEqual('#/a'); delay(next); }) .serial(done); });
pipe('#loader 多次被使用', function (done) { var router = new Router(); var objA = {}; var abcTimes = 0; router.get('/abc/:abc', function (next) { abcTimes++; next(objA); }); router.start(); plan .task(function (next) { location.hash = '#/abc/123'; delay(next); }) .task(function (next) { location.hash = '#/abc/456'; delay(next); }) .task(function (next) { router.destroy(); expect(abcTimes).toBe(1); delay(next); }) .serial(done); });
it('error', function (done) { var app = express(); app.set('views', path.join(__dirname, './')); app.set('view engine', 'html'); app.engine('html', template.express()); app.get('/1', function (req, res, next) { res.render('error.html', { a: 'AaA' }); }); plan .task(function (next) { request(app) .get('/1') .expect('content-type', /html/) .expect(500) .end(function (err, res) { if (err) throw err; expect(res.text).toMatch(/=============================/); next(); }); }) .serial(done); });
pipe('小 route #setQuery', function (done) { var router = new Router(); router.match('/a/b/c/d', function () { this.setQuery({ a: 11, b: 22 }); }); router.start(); plan .task(function (next) { location.hash = '#/a/b/c/d?a=1&b=2&c=3&c=4&c=5'; delay(next); }) .task(function (next) { expect(location.hash.replace('#', '')).toMatch(/a=11&/); expect(location.hash.replace('#', '')).toMatch(/b=22&/); router.destroy(); history.back(); delay(next); }) .task(function (next) { expect(location.hash.replace('#', '')).toBe(''); delay(next); }) .serial(done); });
pipe('小 route #rewrite', function (done) { var router = new Router(); router.match('/a/b/c/d', function () { this.rewrite('../../f'); }); router.start(); plan .task(function (next) { location.hash = '#/a/b/c/d'; delay(next); }) .task(function (next) { expect(location.hash.replace('#', '')).toBe('/a/f'); router.destroy(); history.back(); delay(next); }) .task(function (next) { expect(location.hash.replace('#', '')).toBe(''); delay(next); }) .serial(done); });
pipe('小 route #removeQuery', function (done) { var router = new Router(); router.match('/a/b/c/d', function () { this.removeQuery(['a', 'b', 'c']) }); router.start(); plan .task(function (next) { location.hash = '#/a/b/c/d?a=1&b=2&c=3&c=4&c=5'; delay(next); }) .task(function (next) { expect(location.hash.replace('#', '')).toBe('/a/b/c/d'); router.destroy(); history.back(); delay(next); }) .task(function (next) { expect(location.hash.replace('#', '')).toBe(''); delay(next); }) .serial(done); });
pipe('#get 多次进入', function (done) { var router = new Router(); var directionList = []; router.get('/', function (next) { next({}); }); router.on('afterChange', function (route) { directionList.push(route.direction); }); router.start(); plan .task(function (next) { location.hash = '#/?a=1'; delay(next); }) .task(function (next) { router.destroy(); expect(directionList.length).toBe(2); expect(directionList[0]).toBe('forward'); expect(directionList[1]).toBe('replace'); delay(next); }) .serial(done); });
pipe('#get(loader) + 异步控制器', function (done) { var router = new Router(); var route1 = null; var objA = {a: 'a'}; router .get(function (next) { route1 = this; setTimeout(function () { next(objA); }, 100); }); router.start(); plan .task(function (next) { delay(next); }) .task(function (next) { router.destroy(); expect(route1.controller).toBe(objA); delay(next); }) .serial(done); });
pipe('小 route 多个 meta', function (done) { var router = new Router(); var meta = null; router.match({meta: {a: 1, c: 4}}, function () { }).match({meta: {a: 2, b: 3}}, function () { }).start(); router.on('afterChange', function (route) { meta = route.meta; }); plan .task(function (next) { router.destroy(); delay(next); }) .task(function (next) { expect(meta.a).toEqual(2); expect(meta.b).toEqual(3); expect(meta.c).toEqual(4); next(); }) .serial(done); });
pipe('#match 具名路径', function (done) { var router = new Router(); var change1Times = 0; var change2Times = 0; var change3Times = 0; router .match('/aaa', function (next) { change1Times++; next(); }) .match('/aaa', function () { change2Times++; }) .match('/bbb', function (next) { change3Times++; next(); }); router.start(); plan .task(function (next) { location.hash = '#/aaa'; delay(next); }) .task(function (next) { router.destroy(); expect(change1Times).toBe(1); expect(change2Times).toBe(1); expect(change3Times).toBe(0); delay(next); }) .serial(done); });
pipe('无match无otherwise', function (done) { var router = new Router(); var changeTimes = 0; var routeList = []; router.start(); router.on('afterChange', function (route) { routeList.push(route); changeTimes++; }); plan .task(function (next) { location.hash = '#/a'; delay(next); }) .task(function (next) { router.destroy(); expect(changeTimes).toBe(2); expect(routeList.length).toBe(2); expect(routeList[0].pathname).toBe('/'); expect(routeList[1].pathname).toBe('/a'); delay(next); }) .serial(done); });
pipe('#resolve', function (done) { var changeTimes = 0; var router = new Router(); router.on('beforeChange', function () { changeTimes++; }); router.start(); plan .task(function (next) { var ret = router.resolve('/a/b/c'); expect(ret).toMatch('#/a/b/c'); location.href = ret; delay(next); }) .task(function (next) { var ret = router.resolve('..'); expect(ret).toMatch(/#\/a/); location.href = ret; delay(next); }) .task(function (next) { expect(location.hash).toEqual('#/a'); router.destroy(); delay(next); }) .task(function (next) { expect(changeTimes).toEqual(3); expect(location.hash).toEqual('#/a'); delay(next); }) .serial(done); });
pipe('#match 一直都会执行', function (done) { var router = new Router(); var executedTimes = 0; router.match(function () { executedTimes++; }); router.start(); plan .task(function (next) { location.hash = '#/a'; delay(next); }) .task(function (next) { location.hash = '#/b'; delay(next); }) .task(function (next) { history.back(); delay(next); }) .task(function (next) { history.forward(); delay(next); }) .task(function (next) { router.destroy(); expect(executedTimes).toBe(3); next(); }) .serial(done); });
pipe('#match 历史返回与前进 match 只会进一次', function (done) { var router = new Router(); var abcTimes = 0; router .match('/abc', function (next) { abcTimes++; next(); }) .get('/abc', function () { }); router.start(); plan .task(function (next) { location.href = '#/abc'; delay(next); }) .task(function (next) { location.href = '#/def'; delay(next); }) .task(function (next) { history.back(); delay(next); }) .task(function (next) { router.destroy(); expect(abcTimes).toBe(1); delay(next); }) .serial(done); });
it('cache = false', function (done) { var app = express(); var name = 'cache-false.html'; var file = path.join(__dirname, name); var original = fs.readFileSync(file, 'utf8'); var append = Date.now() + ''; app.set('views', path.join(__dirname, './')); app.set('view engine', 'html'); app.engine('html', template.express({ cache: false })); app.get('/1', function (req, res, next) { res.render(name, { a: 'AaA' }); }); app.get('/2', function (req, res, next) { res.render(name, { a: 'AaA' }); }); plan .task(function (next) { request(app) .get('/1') .expect('content-type', /html/) .expect(200) .end(function (err, res) { if (err) throw err; expect(res.text).toEqual('AaA'); next(); }); }) .taskSync(function () { fs.appendFileSync(file, append, 'utf8'); }) .task(function (next) { request(app) .get('/2') .expect('content-type', /html/) .expect(200) .end(function (err, res) { if (err) throw err; expect(res.text).toEqual('AaA' + append); next(); }); }) .taskSync(function () { fs.writeFileSync(file, original, 'utf8'); }) .serial(done); });
it('async', function (done) { var storeage = {}; var cache = new Cache({ storage: { get: function (key, callback) { setTimeout(function () { callback(null, storeage[key]); }); }, set: function (key, val, exp, callback) { setTimeout(function () { storeage[key] = val; callback(null); }); }, remove: function (key, callback) { setTimeout(function () { delete storeage[key]; callback(null); }); } } }); var key1 = 'myKey1'; var key2 = 'myKey2'; var val1 = {a: 1, b: 2}; plan .task(function (next) { cache.set(key1, val1, next); }) .task(function (next) { cache.get(key1, next); }) .taskSync(function (get1) { expect(get1).toEqual(val1); }) .task(function (next) { cache.get(key2, next); }) .taskSync(function () { expect(get2).toEqual(null); }) .task(function (next) { cache.remove(key1, next); }) .task(function (next) { cache.get(key1, next); }) .taskSync(function (get1) { expect(get1).toEqual(null); }) .serial(done); });
_execAsync: function (/*arguments*/) { var the = this; var args = access.args(arguments); var callback = args.pop(); var errorMiddleware = null; plan .each(the._middlewareStack, function (index, middleware, next) { if (index) { args.shift(); } args.push(function (err) { var err2 = err; // throw string if (typeis.String(err)) { err2 = new Error(err); } if (err2) { errorMiddleware = middleware; } args.pop(); args.unshift(err2); next.apply(global, args); the.emit('error', err2, errorMiddleware); }); try { middleware.apply(the._options.context, args); } catch (err) { args[args.length - 1](err); } }) .serial(function (err) { if (err) { err = the._catchError(err, errorMiddleware); } var args = access.args(arguments); args[0] = err; callback.apply(the._options.context, args); }); return the; },
pipe('event: load 同一个 director 只加载一次', function (done) { var beforeTimes = 0; var afterTimes = 0; var router = new Router(); router.on('beforeLoad', function () { beforeTimes++; }); router.on('afterLoad', function () { afterTimes++; }); router.match(function (next) { next(); }).match('/', function (next) { next(); }).get('/', function (next) { next(); }).get('/a', function (next) { next(); }).start(); plan .task(function (next) { delay(next); }) .task(function (next) { location.hash = '#/a'; delay(next); }) .task(function (next) { history.back(); delay(next); }) .task(function (next) { router.destroy(); delay(next); }) .task(function (next) { expect(beforeTimes).toEqual(2); expect(afterTimes).toEqual(2); delay(next); }) .serial(done); });
pipe('#setQuery/removeQuery', function (done) { var changeTimes = 0; var router = new Router(); router.on('beforeChange', function () { changeTimes++; }); router.start(); plan .task(function (next) { router.setQuery({a: 1}); delay(next); }) .task(function (next) { expect(location.hash).toEqual('#/?a=1'); router.setQuery('a', '2'); delay(next); }) .task(function (next) { expect(location.hash).toEqual('#/?a=2'); router.setQuery('a=3'); delay(next); }) .task(function (next) { expect(location.hash).toEqual('#/?a=3'); router.removeQuery('a'); delay(next); }) .task(function (next) { expect(location.hash).toEqual('#/'); router.destroy(); delay(next); }) .task(function (next) { expect(changeTimes).toEqual(5); expect(location.hash).toEqual('#/'); delay(next); }) .serial(done); });
pipe('#match 路径匹配', function (done) { var router = new Router(); var change1Times = 0; var change2Times = 0; var change3Times = 0; var userName = ''; var param1 = ''; router .match('/user/:userName', function (next) { change1Times++; userName = this.params.userName; next(); }) .match(/^\/user\/([^\/]+)$/, function () { param1 = this.params[1]; change2Times++; }) .match('/user/bbb', function (next) { change3Times++; next(); }); router.start(); plan .task(function (next) { location.hash = '#/user/aaa'; delay(next); }) .task(function (next) { router.destroy(); expect(change1Times).toBe(1); expect(change2Times).toBe(1); expect(change3Times).toBe(0); expect(userName).toBe('aaa'); expect(param1).toBe('aaa'); delay(next); }) .serial(done); });
pipe('router.match meta', function (done) { var router = new Router(); var metaList = []; var aList = []; var bList = []; var cList = []; router.match({ meta: {a: 1, b: 2} }, function () { metaList.push(this.meta); aList.push(this.meta.a); bList.push(this.meta.b); cList.push(this.meta.c); }).match({ path: '/', meta: {c: 3, b: 4} }, function () { metaList.push(this.meta); aList.push(this.meta.a); bList.push(this.meta.b); cList.push(this.meta.c); }).start(); plan .task(function (next) { router.destroy(); delay(next); }) .task(function (next) { expect(metaList.length).toBe(2); expect(aList[0]).toBe(1); expect(aList[1]).toBe(1); expect(bList[0]).toBe(2); expect(bList[1]).toBe(4); expect(cList[0]).toBe(undefined); expect(cList[1]).toBe(3); delay(next); }) .serial(done); });
var getModulesVersion = function (modules, callback) { plan .each(modules, function (index, dep, next) { getLatestVersion(dep, function (err, version) { next(err, version); }); }) .parallel() .try(function () { var args = access.args(arguments); var deps = {}; collection.each(args, function (index, version) { var name = modules[index]; deps[name] = version; }); callback(null, deps); }) .catch(callback); };
pipe('#match + 同步控制器', function (done) { var router = new Router(); var route1 = null; var objA = {a: 'a'}; router .get('/', function () { route1 = this; return objA; }); router.start(); plan .task(function (next) { router.destroy(); expect(route1.controller).toBe(objA); delay(next); }) .serial(done); });
pipe('#match 中间件跳转模式', function (done) { var router = new Router(); router.match('/aaa', function (next) { next('bbb'); }); router.start(); plan .task(function (next) { location.hash = '#/aaa'; delay(next); }) .task(function (next) { expect(location.hash).toBe('#/bbb'); router.destroy(); delay(next); }) .serial(done); });
pipe('#rewrite ignore=true', function (done) { var router = new Router(); var one = 0; var two = 0; router.get('/', function () { one++; return 1; }).get('/2', function () { two++; return 2; }); router.start(); router.on('afterChange', function (route) { switch (route.controller) { case 1: route.rewrite('/2', true); break; } }); plan .task(function (next) { router.rewrite('/2'); delay(next); }) .task(function (next) { router.destroy(); delay(next); }) .task(function (next) { expect(one).toEqual(1); expect(two).toEqual(0); expect(location.hash).toEqual('#/2'); delay(next); }) .serial(done); });
pipe('小 route #resolve', function (done) { var router = new Router(); var ret = ''; router.match('/a/b/c/d', function () { ret = this.resolve('../../f'); }); router.start(); plan .task(function (next) { location.hash = '#/a/b/c/d'; delay(next); }) .task(function (next) { expect(ret).toBe('/a/f'); router.destroy(); delay(next); }) .serial(done); });