Skip to content

Commit 3b111bb

Browse files
author
Anton Hinz
committed
Increase coverage of core part + Small test-driven refactoring
1 parent 692aaa0 commit 3b111bb

File tree

10 files changed

+1266
-100
lines changed

10 files changed

+1266
-100
lines changed

src/core/bus.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { reactive } from 'vue';
22

3-
const $module = ({ state = {}, actions = {} }) => {
3+
export const $module = ({ state = {}, actions = {} }) => {
44
return {
55
state: reactive(state),
66
actions,
@@ -14,7 +14,7 @@ export default () => {
1414
return {
1515
/* Required to add new module to a bus */
1616
add(module) {
17-
if (!module.name) return;
17+
if (!module.name) throw new Error('Module should have a mandatory "name" property');
1818

1919
$modules[module.name] = $module(module);
2020
},

src/core/bus.spec.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import bus, { $module } from './bus';
2+
import vue from 'vue';
3+
4+
jest.mock('vue', () => ({
5+
reactive: jest.fn(v => v),
6+
}))
7+
8+
describe('$module', () => {
9+
describe('on call should', () => {
10+
let result;
11+
12+
beforeEach(() => {
13+
result = $module({ state: 'ABC', actions: { a: 'A', b: 'B' }})
14+
});
15+
16+
it('make state reactive', () => {
17+
expect(vue.reactive).toHaveBeenCalledWith('ABC')
18+
});
19+
20+
it('return same data', () => {
21+
expect(result).toEqual({ state: 'ABC', actions: { a: 'A', b: 'B' }});
22+
});
23+
});
24+
25+
describe('should set defaults', () => {
26+
it.each([
27+
[undefined, undefined, { state: {}, actions: {} }],
28+
['FOO', undefined, { state: 'FOO', actions: {} }],
29+
[undefined, 'BAR', { state: {}, actions: 'BAR' }],
30+
['FOO', 'BAR', { state: 'FOO', actions: 'BAR' }],
31+
])('when state is %j and actions %j should return %j', (state, actions, result) => {
32+
expect($module({ state, actions })).toEqual(result);
33+
});
34+
});
35+
});
36+
37+
describe('bus', () => {
38+
let $bus;
39+
40+
describe('with incorrect module', () => {
41+
it('should throw an error when module has no name', () => {
42+
try {
43+
$bus = bus();
44+
$bus.add({ state: {}, actions: {} });
45+
} catch (e) {
46+
expect(e.message).toBe('Module should have a mandatory "name" property');
47+
}
48+
});
49+
});
50+
51+
describe('with correct module', () => {
52+
beforeEach(() => {
53+
$bus = bus();
54+
55+
$bus.add({
56+
name: 'test',
57+
58+
state: {
59+
foo: 'FOO',
60+
bar: 'BAR'
61+
},
62+
63+
actions: {
64+
toggle() {
65+
this.state.foo = 'BAR';
66+
this.state.bar = 'FOO';
67+
},
68+
},
69+
});
70+
});
71+
72+
describe('#watch()', () => {
73+
it('should return full state by default', () => {
74+
expect($bus.watch('test')).toEqual({ foo: 'FOO', bar: 'BAR' });
75+
});
76+
77+
it('should return full state when property "*" is passed', () => {
78+
expect($bus.watch('test', '*')).toEqual({ foo: 'FOO', bar: 'BAR' });
79+
});
80+
81+
it('should return property of state when property is passed', () => {
82+
expect($bus.watch('test', 'foo')).toBe('FOO');
83+
});
84+
});
85+
86+
describe('#commit()', () => {
87+
it('should set value of property', () => {
88+
$bus.commit('test', 'foo', 'BAR');
89+
90+
expect($bus.watch('test', 'foo')).toBe('BAR');
91+
});
92+
});
93+
94+
describe('#dispatch()', () => {
95+
it('should trigger an action of a module', () => {
96+
$bus.dispatch('test', 'toggle');
97+
98+
expect($bus.watch('test', '*')).toEqual({ foo: 'BAR', bar: 'FOO' });
99+
});
100+
});
101+
});
102+
});
103+

src/core/embed.js

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,9 @@ export default (bus, name, component, customs = []) => {
1111
constructor() {
1212
super();
1313

14-
this.$app = null;
15-
this.$subscribers = {};
16-
this.$state = reactive(fromKeys(component.$attrs || []));
17-
18-
// Events emitter decorator
19-
this.$emit = (name, detail) => {
20-
const event = new CustomEvent(name, {
21-
bubbles: true,
22-
detail,
23-
});
24-
25-
this.dispatchEvent(event);
26-
};
27-
28-
// Events listener decorator
29-
this.$catch = (name, handler) => {
30-
this.addEventListener(name, (e) => {
31-
// Event should only be handled once in this system
32-
e.stopPropagation();
33-
34-
handler(e.detail);
35-
});
36-
};
14+
this.$app = null
15+
this.$subscribers = {}
16+
this.$state = reactive(fromKeys(component.$attrs || []))
3717

3818
// Parent allows whitelist of events to subscribe
3919
if (component?.$publishes?.length > 0) {
@@ -50,6 +30,24 @@ export default (bus, name, component, customs = []) => {
5030
}
5131
}
5232

33+
$catch(name, handler) {
34+
this.addEventListener(name, (e) => {
35+
// Event should only be handled once in this system
36+
e.stopPropagation();
37+
38+
handler(e.detail);
39+
});
40+
}
41+
42+
$emit(name, detail) {
43+
const event = new CustomEvent(name, {
44+
bubbles: true,
45+
detail,
46+
});
47+
48+
this.dispatchEvent(event);
49+
}
50+
5351
connectedCallback() {
5452
/* Pretty much Everything Vue-related is kept here */
5553
this.$app = createApp(component);
@@ -84,9 +82,7 @@ export default (bus, name, component, customs = []) => {
8482

8583
// Parent listens child
8684
this.$app.provide('$listen', (name, handler) => {
87-
this.$catch(`$dispatch:${name}`, (data) => {
88-
handler(data)
89-
});
85+
this.$catch(`$dispatch:${name}`, handler);
9086
});
9187

9288
// Initiall attributes set initialization
@@ -102,7 +98,7 @@ export default (bus, name, component, customs = []) => {
10298

10399
this.$app.component('content', {
104100
template: this.content,
105-
})
101+
});
106102
}
107103

108104
// This solution allows to provide styles for custom html container without

0 commit comments

Comments
 (0)