Skip to content

Commit

Permalink
Add client.test.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Klingler committed Jun 9, 2018
1 parent b303795 commit 9de748f
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- run:
command: |
./cc-test-reporter before-build
npm run test
npm run test -- --coverage
./cc-test-reporter after-build --exit-code $?
# publish to npm
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,20 @@
"typescript": "^2.9.1"
},
"jest": {
"collectCoverage": true,
"collectCoverageFrom": [
"src/**"
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
]
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$"
}
}
8 changes: 4 additions & 4 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ import { StylesTarget } from 'typestyle/lib/internal/typestyle';

import { alternateFirstInvocation, updateVNode } from './utils';

const removeServersideStyles = (styleElementSelector: string) => {
export const removeElement = (styleElementSelector: string) => {
const previousStyleTarget = document.querySelector(styleElementSelector);

if (previousStyleTarget) {
previousStyleTarget.remove();
}
};

const makeDomUpdater = (styleElementSelector: string | undefined = undefined) => (oldNode: VNode, newNode: VNode): void => {
export const makeDomUpdater = (styleElementSelector: string | undefined = undefined) => (oldNode: VNode, newNode: VNode): void => {
if (newNode.elm) {
const elm: Element = newNode.elm as Element;
updateVNode(newNode, (name, value) => elm.setAttribute(name, value));
}

if (typeof styleElementSelector !== 'undefined') {
removeServersideStyles(styleElementSelector);
removeElement(styleElementSelector);
}
};

Expand All @@ -32,7 +32,7 @@ export const makeModule = (styleElementSelector: string | undefined = undefined)

return {
create: updateDOM,
update: updateDOM,
update: updateDOM
} as Module;
};

Expand Down
67 changes: 67 additions & 0 deletions test/client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { h } from 'snabbdom';
import { VNode } from 'snabbdom/vnode';
import { style } from 'typestyle';
import * as client from '../src/client';
import * as utils from '../src/utils';
import * as mocks from './mocks';

jest.mock('typestyle');

describe('removeElement', () => {

it('removes an element given a selector', () => {

const element = document.createElement('style');
element.id = 'styles';
document.head.appendChild(element);

client.removeElement(mocks.styleElementSelector());
expect(document.head.contains(element)).toBe(false);
});

it('doesn\'t error when not given a selector', () => {
client.removeElement();
});
});

describe('makeDomUpdater', () => {
it('calls updateVNode when passed a VNode with an element', () => {
utils.updateVNode = jest.fn();
client.makeDomUpdater()(mocks.vNodeWithElm(), mocks.vNodeWithElm();
expect(utils.updateVNode.mock.calls.length).toBe(1);
});

it('does not call updateVNode when create is passed a VNode without an element', () => {
utils.updateVNode = jest.fn();
client.makeDomUpdater()(mocks.vNode(), mocks.vNode();
expect(utils.updateVNode.mock.calls.length).toBe(0);
});

it('passes removeElement the style element selector when create is called', () => {
client.removeElement = jest.fn();
client.makeDomUpdater(mocks.styleElementSelector())(mocks.vNode(), mocks.vNode();
expect(client.removeElement.mock.calls.length).toBe(1);
expect(client.removeElement.mock.calls[0][0]).toBe(mocks.styleElementSelector());
});

});

describe('makeModule', () => {

const module;

beforeEach(() => {
module = client.makeModule(mocks.styleElementSelector());
});

it('returns a module that calls that performs the same function on create and update', () => {
expect(module.update).toEqual(module.create);
});

it('calls makeDomUpdater with the styleElementSelector', () => {
const spy = jest.fn();
client.makeDomUpdater = () => spy;
module.create(mocks.vNodeWithElm(), mocks.vNodeWithElm());
expect(spy.mock.calls.length).toBe(1);
});
});
25 changes: 25 additions & 0 deletions test/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { h } from 'snabbdom';

export const styleElementSelector = () => '#styles';

export const css = () => ({
color: 'blue'
});

export const oldClassName = () => 'test';

export const vNode = () => h('div', {
css: css(),
props: {
className: oldClassName()
}
});

export const vNodeWithElm = () => {
const node = vNode();
node.elm = {
setAttribute: jest.fn();
};

return node;
};
21 changes: 6 additions & 15 deletions test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as utils from '../src/utils';
import { style } from 'typestyle';
import { h } from 'snabbdom';
import { VNode } from 'snabbdom/vnode';
import { style } from 'typestyle';
import * as utils from '../src/utils';
import * as mocks from './mocks';

jest.mock('typestyle');

Expand Down Expand Up @@ -45,30 +45,21 @@ describe('makeClassName', () => {

describe('updateVNode', () => {

const css;
const oldClassName;
const attributeAccessor;

beforeEach(() => {
css = {
color: 'blue',
};

oldClassName = 'test';
const vNode = h('div', { css, props: { className: oldClassName} });
attributeAccessor = jest.fn();
utils.makeClassName = jest.fn(() => 'className');

utils.updateVNode(vNode, attributeAccessor);
utils.updateVNode(mocks.vNode(), attributeAccessor);
});

it('calls style with the vnode css', () => {
expect(style.mock.calls[0][0]).toEqual(css);
expect(style.mock.calls[0][0]).toEqual(mocks.css());
});

it('calls makeClassName with old classname and new classname', () => {
const newClassName = style.mock.results[0].value;
expect(utils.makeClassName.mock.calls[0][0]).toBe(oldClassName);
expect(utils.makeClassName.mock.calls[0][0]).toBe(mocks.oldClassName());
expect(utils.makeClassName.mock.calls[0][1]).toBe(newClassName);
});

Expand Down
3 changes: 2 additions & 1 deletion tslint.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"extends": "tslint:recommended",
"rules": {
"interface-name": [false],
"quotemark": [true, "single"],
"interface-name": [false]
"trailing-comma": [true, {"multiline": "never", "singleline": "never"}]
}
}

0 comments on commit 9de748f

Please sign in to comment.