router/src/index.test.js

322 lines
8.0 KiB
JavaScript

import { Router } from './index.js';
describe('router.href builds urls', () => {
const router = Router([
{
name: 'home',
path: '/',
enter: (route, router) => {},
exit: (route, newRoute, router) => {}
},
{
name: 'article',
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ },
enter: (route, router) => {},
exit: (route, newRoute, router) => {}
}
]);
it('at the root', () => {
expect(router.href('home')).toEqual('#/');
});
it('with variables', () => {
expect(router.href('article', { id: 156234 })).toEqual('#/article/156234');
});
describe('but throws an error', () => {
it("if the route doesn't exist", () => {
expect(() => {
router.href('artcle', { id: 156 });
}).toThrowError(Error, 'Invalid route artcle.');
});
it("if the vars don't match", () => {
expect(() => {
router.href('article', { id: 156 });
}).toThrowError(Error, 'Invalid value for route /article/:id var id: 156.');
});
});
});
describe('router on start', () => {
let routeSpecArray, router;
beforeEach(() => {
routeSpecArray = [
{
name: 'home',
path: '/'
},
{
name: 'article',
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ }
}
];
router = Router(routeSpecArray);
spyOn(router, 'goto').and.callThrough();
});
afterEach(() => {
if (router) {
router.stop();
router = null;
location.hash = '';
}
});
it('listens to hashchanges', (done) => {
expect(router.goto).toHaveBeenCalledTimes(0);
router.start('home');
expect(router.goto).toHaveBeenCalledWith('home');
location.hash = '/article/123456';
setTimeout(() => {
expect(router.goto).toHaveBeenCalledWith('#/article/123456', null, true);
done();
}, 20);
});
it('does not double-start', () => {
expect(router.goto).toHaveBeenCalledTimes(0);
router.start('home');
expect(router.goto).toHaveBeenCalledWith('home');
router.start('gravy');
expect(router.goto).toHaveBeenCalledTimes(1);
});
it('throws errors for invalid routes', () => {
expect(() => router.start('artcle')).toThrowError(Error, 'Invalid route artcle.');
});
});
describe('router on hashchange event', () => {
let reEnterHooks, routeSpecArray, router;
beforeEach(() => {
reEnterHooks = {
home: () => {},
article: () => {}
};
routeSpecArray = [
{
name: 'home',
path: '/',
enter: (route, router) => reEnterHooks.home,
exit: (route, newRoute, router) => {}
},
{
name: 'article',
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ },
enter: (route, router) => reEnterHooks.article,
exit: (route, newRoute, router) => {}
}
];
spyOn(routeSpecArray[0], 'enter').and.callThrough();
spyOn(routeSpecArray[1], 'enter').and.callThrough();
router = Router(routeSpecArray);
spyOn(router, 'goto').and.callThrough();
});
afterEach(() => {
if (router) {
router.stop();
router = null;
location.hash = '';
}
});
it('calls handlers for the new location', (done) => {
expect(router.goto).toHaveBeenCalledTimes(0);
router.start('home');
location.hash = '/article/123456';
expect(routeSpecArray[1].enter).toHaveBeenCalledTimes(0);
setTimeout(() => {
expect(router.goto).toHaveBeenCalledWith('#/article/123456', null, true);
expect(routeSpecArray[1].enter).toHaveBeenCalledTimes(1);
done();
}, 20);
});
it('reverts if the change does not have a valid path.', (done) => {
function stepA() {
expect(router.goto).toHaveBeenCalledWith('home');
expect(router.current().name).toEqual('home');
expect(routeSpecArray[1].enter).toHaveBeenCalledTimes(0);
location.hash = '/invalid';
expect(location.hash).toEqual('#/invalid');
setTimeout(stepB, 20);
}
function stepB() {
expect(router.goto).toHaveBeenCalledWith('#/invalid', null, true);
expect(location.hash).toEqual('#/');
done();
}
router.start('home');
setTimeout(stepA, 20);
});
});
describe('router.goto()', () => {
let reEnterHooks, routeSpecArray, router;
describe('goes to routes', () => {
beforeEach(() => {
reEnterHooks = {
home: () => {},
article: () => {}
};
routeSpecArray = [
{
name: 'home',
path: '/',
enter: (route, router) => reEnterHooks.home,
exit: (route, newRoute, router) => {}
},
{
name: 'article',
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ },
enter: (route, router) => reEnterHooks.article,
exit: (route, newRoute, router) => {}
}
];
spyOn(routeSpecArray[0], 'enter').and.callThrough();
spyOn(routeSpecArray[1], 'enter').and.callThrough();
router = Router(routeSpecArray);
});
it('with vars', done => {
router.goto('article', { id: 156234 }).then(() => {
expect(routeSpecArray[1].enter).toHaveBeenCalled();
const current = router.current();
expect(current.name).toEqual('article');
expect(current.path).toEqual('#/article/156234');
done();
});
});
it('at the root', done => {
router.goto('home').then(() => {
expect(routeSpecArray[0].enter).toHaveBeenCalled();
const current = router.current();
expect(current.name).toEqual('home');
expect(current.path).toEqual('#/');
done();
});
});
it('with a url', done => {
router.goto('#/article/156233').then(() => {
expect(routeSpecArray[1].enter).toHaveBeenCalled();
const current = router.current();
expect(current.name).toEqual('article');
expect(current.path).toEqual('#/article/156233');
done();
});
});
});
describe('reEnters routes', () => {
it('when a route is navigated with merely different vars with a reenter hook', done => {
reEnterHooks = {
home: () => {},
article: () => {}
};
routeSpecArray = [
{
name: 'home',
path: '/',
enter: (route, router) => reEnterHooks.home,
exit: (route, newRoute, router) => {}
},
{
name: 'article',
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ },
enter: (route, router) => reEnterHooks.article,
exit: (route, newRoute, router) => {}
}
];
spyOn(routeSpecArray[0], 'enter').and.callThrough();
spyOn(routeSpecArray[1], 'enter').and.callThrough();
spyOn(routeSpecArray[1], 'exit').and.callThrough();
spyOn(reEnterHooks, 'article').and.callThrough();
router = Router(routeSpecArray);
router
.goto('article', { id: 156234 })
.then(() => {
expect(routeSpecArray[1].enter).toHaveBeenCalled();
expect(routeSpecArray[1].exit).toHaveBeenCalledTimes(0);
return router.goto('article', { id: 151234 });
})
.then(() => {
expect(reEnterHooks.article).toHaveBeenCalled();
expect(routeSpecArray[1].exit).toHaveBeenCalledTimes(0);
return router.goto('home');
})
.then(() => {
expect(routeSpecArray[0].enter).toHaveBeenCalled();
expect(routeSpecArray[1].exit).toHaveBeenCalled();
})
.then(done);
});
it('when a route is navigated with merely different vars without a reenter hook', done => {
routeSpecArray = [
{
name: 'home',
path: '/',
enter: (route, router) => {},
exit: (route, newRoute, router) => {}
},
{
name: 'article',
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ },
enter: (route, router) => {},
exit: (route, newRoute, router) => {}
}
];
spyOn(routeSpecArray[0], 'enter').and.callThrough();
spyOn(routeSpecArray[1], 'enter').and.callThrough();
spyOn(routeSpecArray[1], 'exit').and.callThrough();
router = Router(routeSpecArray);
router
.goto('article', { id: 156234 })
.then(() => {
expect(routeSpecArray[1].enter).toHaveBeenCalled();
expect(routeSpecArray[1].exit).toHaveBeenCalledTimes(0);
return router.goto('article', { id: 151234 });
})
.then(() => {
expect(routeSpecArray[1].enter).toHaveBeenCalledTimes(2);
expect(routeSpecArray[1].exit).toHaveBeenCalledTimes(1);
return router.goto('home');
})
.then(() => {
expect(routeSpecArray[0].enter).toHaveBeenCalled();
expect(routeSpecArray[1].exit).toHaveBeenCalled();
})
.then(done);
});
});
});