Skip to content

Commit

Permalink
Finished unit tests, 100%
Browse files Browse the repository at this point in the history
  • Loading branch information
unimonkiez committed Jul 25, 2016
1 parent 32401b5 commit 56a98c3
Show file tree
Hide file tree
Showing 11 changed files with 550 additions and 66 deletions.
15 changes: 10 additions & 5 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ module.exports = function karmaConfig(config) {
}
},
// Override `module` in `webpackConfig` only if coverage is produced
module: Object.assign(webpackConfig.module, isCoverage ? {
preLoaders: webpackConfig.module.preLoaders.concat([
module: Object.assign(webpackConfig.module, {
preLoaders: webpackConfig.module.preLoaders.concat(isCoverage ? [
{ // `isparta` all the code We want to be in the coverage report
test: /\.js$/,
include: [
Expand All @@ -65,10 +65,15 @@ module.exports = function karmaConfig(config) {
],
loader: 'babel?presets[]=es2015'
}
]),
] : []),
// Exclude js loaders from `loaders` because they are set in preLoaders
loaders: webpackConfig.module.loaders.filter(loaderObj => (typeof loaderObj.test !== 'function' && loaderObj.test.toString().indexOf('.js') === -1))
} : {})
loaders: webpackConfig.module.loaders
.filter(loaderObj => (typeof loaderObj.test !== 'function' && loaderObj.test.toString().indexOf('.js') === -1))
.concat(isCoverage ? [] : [{
test: /\.js$/,
loader: 'babel?presets[]=es2015'
}])
})
}),
webpackMiddleware: {
noInfo: true
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"absurd-loader": "^0.0.3",
"babel-eslint": "^6.0.2",
"babel-loader": "^6.2.4",
"babel-polyfill": "^6.9.1",
"babel-preset-es2015": "^6.6.0",
"bower": "^1.7.9",
"coveralls": "^2.11.11",
Expand Down
41 changes: 41 additions & 0 deletions src/set-events-for-template-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import categoryOrder from './category-order';
import { CATEGORY } from './constant';

export const getIsElementScrollable = el => {
return el.clientHeight !== el.scrollHeight;
};

export const round = num => ((num * 2).toFixed() / 2);

export const scrollElementTo = (el, done, newScrollHeight = 0, scrollDuration = 300) => {
const scrollHeight = el.scrollTop;
const scrollDiff = scrollHeight - newScrollHeight;
const scrollStep = Math.PI / (scrollDuration / 15);
const cosParameter = scrollDiff / 2;
let scrollCount = 0;
let scrollMargin;

const step = () => {
setTimeout(() => {
if (el.scrollTop !== newScrollHeight) {
requestAnimationFrame(step);
scrollCount = scrollCount + 1;
scrollMargin = round(cosParameter - cosParameter * Math.cos(scrollCount * scrollStep));
el.scrollTop = scrollHeight - scrollMargin;
} else {
done();
}
}, 15);
};

requestAnimationFrame(step);
};

const marginParam = 100 / categoryOrder.length;
export const slideToCategory = (panelVariables, slideEl, categoryId) => {
if (panelVariables.selectedCategoryId !== categoryId) {
panelVariables.selectedCategoryId = categoryId;
const selectedCategoryIndex = categoryOrder.indexOf(categoryId);
slideEl.style.marginLeft = selectedCategoryIndex * marginParam + '%';
}
};
64 changes: 12 additions & 52 deletions src/set-events-for-template.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,4 @@
import categoryOrder from './category-order';
import { CATEGORY } from './constant';

const getIsElementScrollable = el => {
return el.clientHeight !== el.scrollHeight;
};

const round = num => ((num * 2).toFixed() / 2);

const scrollElementTo = (el, done, newScrollHeight = 0, scrollDuration = 300) => {
const scrollHeight = el.scrollTop;
const scrollDiff = scrollHeight - newScrollHeight;
const scrollStep = Math.PI / (scrollDuration / 15);
const cosParameter = scrollDiff / 2;
let scrollCount = 0;
let scrollMargin;

const step = () => {
setTimeout(() => {
if (el.scrollTop !== newScrollHeight) {
requestAnimationFrame(step);
scrollCount = scrollCount + 1;
scrollMargin = round(cosParameter - cosParameter * Math.cos(scrollCount * scrollStep));
el.scrollTop = scrollHeight - scrollMargin;
} else {
done();
}
}, 15);
};

requestAnimationFrame(step);
};

const marginParam = 100 / categoryOrder.length;
const slideToCategory = (panelVariables, slideEl, categoryId) => {
if (panelVariables.selectedCategoryId !== categoryId) {
panelVariables.selectedCategoryId = categoryId;
const selectedCategoryIndex = categoryOrder.indexOf(categoryId);
slideEl.style.marginLeft = selectedCategoryIndex * marginParam + '%';
}
};
import { getIsElementScrollable, scrollElementTo, slideToCategory } from './set-events-for-template-helpers';

export default (el, { animationDuration, eventListeners } = {}) => {
const panelVariables = {
Expand All @@ -47,15 +7,15 @@ export default (el, { animationDuration, eventListeners } = {}) => {

const categoriesEl = el.querySelector('.ep-categories');
const slideEl = el.querySelector('.ep-slide');
const emojiesContainer = el.querySelector('.ep-emojies');
const emojiesContainerEl = el.querySelector('.ep-emojies');

// Set styles
slideEl.style.transitionDuration = animationDuration + 'ms';

const scrollListener = () => {
const scrollHeight = emojiesContainer.scrollTop;
const emojiesContainerChildren = Array.from(emojiesContainer.children);
const lastVisibleContainerChild = emojiesContainerChildren
const scrollHeight = emojiesContainerEl.scrollTop;
const emojiesContainerElChildren = Array.from(emojiesContainerEl.children);
const lastVisibleContainerChild = emojiesContainerElChildren
.find(node => scrollHeight >= node.offsetTop && (!node.nextElementSibling || scrollHeight < node.nextElementSibling.offsetTop));

const categoryId = Number(lastVisibleContainerChild.dataset.categoryId);
Expand All @@ -69,19 +29,19 @@ export default (el, { animationDuration, eventListeners } = {}) => {
target = target.parentElement;
}
if (target.classList.contains('ep-c')) {
const isElementScrollable = getIsElementScrollable(emojiesContainer);
const isElementScrollable = getIsElementScrollable(emojiesContainerEl);
if (isElementScrollable) {
const categoryId = Number(target.dataset.categoryId);
const categoryEl = emojiesContainer.querySelector(`[data-category-id="${categoryId}"]`);
const categoryEl = emojiesContainerEl.querySelector(`[data-category-id="${categoryId}"]`);
const categoryHeight = categoryEl.offsetTop;

panelVariables.isMidScrollAnimation = true;
// Remove scroll event listener for better performance
emojiesContainer.removeEventListener('scroll', scrollListener);
scrollElementTo(emojiesContainer, () => {
emojiesContainerEl.removeEventListener('scroll', scrollListener);
scrollElementTo(emojiesContainerEl, () => {
panelVariables.isMidScrollAnimation = false;
// Readd scroll event listener after javascript animation has finished
emojiesContainer.addEventListener('scroll', scrollListener);
emojiesContainerEl.addEventListener('scroll', scrollListener);
}, categoryHeight, animationDuration);

slideToCategory(panelVariables, slideEl, categoryId);
Expand All @@ -90,10 +50,10 @@ export default (el, { animationDuration, eventListeners } = {}) => {
}
});

emojiesContainer.addEventListener('scroll', scrollListener);
emojiesContainerEl.addEventListener('scroll', scrollListener);

if (eventListeners.onClick) {
emojiesContainer.addEventListener('click', e => {
emojiesContainerEl.addEventListener('click', e => {
const target = e.target;
if (target.classList.contains('ep-e')) {
const index = Number(target.dataset.index);
Expand Down
1 change: 1 addition & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'babel-polyfill';
// Disabling `no-undef` because we are using here require.context which requires files dynamically, instead of regular ES6 imports
/* eslint-disable no-undef */

Expand Down
27 changes: 27 additions & 0 deletions test/mock/emoji-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CATEGORY } from 'src/constant';
export default {
[CATEGORY.ACTIVITY]: [
{
index: 0,
unified: 'a'
}, {
index: 1,
unified: 'b'
}
],
[CATEGORY.FLAGS]: [
{
index: 2,
unified: 'c'
}, {
index: 3,
unified: 'd'
}
],
[CATEGORY.FOODS]: [],
[CATEGORY.NATURE]: [],
[CATEGORY.OBJECTS]: [],
[CATEGORY.PEOPLE]: [],
[CATEGORY.PLACES]: [],
[CATEGORY.SYMBOLS]: []
};
111 changes: 111 additions & 0 deletions test/spec/set-events-for-template-helpers-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { getIsElementScrollable, round, scrollElementTo, slideToCategory } from 'src/set-events-for-template-helpers';
import categoryOrder from 'src/category-order';
import { CATEGORY } from 'src/constant';

describe('`set-events-for-template-helpers`', () => {
describe('has `getIsElementScrollable` function which returns', () => {
it('false if `clientHeight` equals `scrollHeight`', () => {
expect(getIsElementScrollable({
clientHeight: 12,
scrollHeight: 12
})).toBeFalsy();
});
it('true if `clientHeight` is different than `scrollHeight`', () => {
expect(getIsElementScrollable({
clientHeight: 200,
scrollHeight: 12
})).toBeTruthy();
});
});
describe('has `round` function', () => {
it('that rounds up numbers', () => {
expect(round(1.77)).toBe(2);
});
it('that rounds down numbers', () => {
expect(round(1.12)).toBe(1);
});
describe('that rounds to half', () => {
it('when is half', () => {
expect(round(1.5)).toBe(1.5);
});
it('when is bellow half but closer to half than whole number', () => {
expect(round(1.32)).toBe(1.5);
});
it('when is higher than half but closer to half than whole number', () => {
expect(round(1.72)).toBe(1.5);
});
});
});
describe('has `slideToCategory` function', () => {
let panelVariables;
let slideEl;
beforeEach(() => {
panelVariables = {
selectedCategoryId: categoryOrder[0]
};
slideEl = {
style: {
marginLeft: '0%'
}
};
});
it('that does nothing if categoryId matches the `panelVariables.selectedCategoryId`', () => {
slideToCategory(panelVariables, slideEl, categoryOrder[0]);
expect(panelVariables.selectedCategoryId).toBe(categoryOrder[0]);
expect(slideEl.style.marginLeft).toBe('0%');
});
it('that changes `panelVariables.selectedCategoryId` and `slideEl.style.marginLeft` (based on how many categories there are) if given differentCategoryId', () => {
const indexOfNewCatergyId = 3;
const newCategoryId = categoryOrder[indexOfNewCatergyId];
slideToCategory(panelVariables, slideEl, newCategoryId);
expect(panelVariables.selectedCategoryId).toBe(newCategoryId);
expect(slideEl.style.marginLeft).toBe(`${(indexOfNewCatergyId / categoryOrder.length) * 100}%`);
});
});
describe('has `scrollElementTo` function that does scroll animation', () => {
let funcArray;
/**
* Loops through funcArray and runs all of the functions
*/
const runFuncArray = fn => {
let i = 0;
while (i < funcArray.length) {
funcArray[i]();
// Middleware function
if (fn) {
fn();
}
i++;
}
};
/**
* beforeEach sets resets array to empty, and each time raf or setTimeout is called, adds them to the array to be run by `runFuncArray`
*/
beforeEach(() => {
funcArray = [];
spyOn(window, 'setTimeout').and.callFake(fn => {
funcArray.push(fn);
});
spyOn(window, 'requestAnimationFrame').and.callFake(fn => {
funcArray.push(fn);
});
});
it('`done` is called once', () => {
const doneSpy = jasmine.createSpy('done');
scrollElementTo({
scrollTop: 0
}, doneSpy, 300);
runFuncArray();
expect(doneSpy).toHaveBeenCalledTimes(1);
});
it('step function is called every 15ms', () => {
const animationTime = 310;
const timesStepShouldBeCalled = Math.ceil(animationTime / 15);
scrollElementTo({
scrollTop: 0
}, () => {}, animationTime);
runFuncArray();
expect(window.setTimeout).toHaveBeenCalledTimes(timesStepShouldBeCalled);
});
});
});
Loading

0 comments on commit 56a98c3

Please sign in to comment.