Skip to content

Commit 634bfdc

Browse files
author
Ben Crowl
committed
First test in place
1 parent 4a3f58f commit 634bfdc

File tree

11 files changed

+165
-79
lines changed

11 files changed

+165
-79
lines changed

.vscode/launch.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
// Use IntelliSense to learn about possible Node.js debug attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "Launch Program",
11+
"protocol": "inspector",
12+
"program": "${workspaceRoot}/dist/tests/main.js",
13+
"outFiles": [
14+
"${workspaceRoot}/dist/**/*.js"
15+
]
16+
}
17+
]
18+
}

.vscode/tasks.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
"version": "0.1.0",
33
"command": "npm",
44
"isShellCommand": true,
5-
"args": ["run"],
5+
"args": [
6+
"run"
7+
],
68
"showOutput": "always",
79
"tasks": [
810
{
911
"taskName": "build",
10-
"isBuildCommand": true
12+
"isBuildCommand": true,
13+
"isBackground": true,
14+
"problemMatcher": "$tsc-watch"
1115
},
1216
// {
1317
// "taskName": "clean"

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
"homepage": "https://github.com/mrcrowl/vuex-typex#readme",
4040
"scripts": {
4141
"clean": "rimraf dist && rimraf coverage",
42-
"compile": "tsc --pretty",
43-
"build": "npm run clean && npm run lint-force && npm run compile",
42+
"compile": "tsc --pretty --watch",
43+
"build": "npm run clean && npm run compile",
4444
"test": "npm run coverage",
4545
"test-only": "mocha --recursive dist/**/*.spec.js",
4646
"test-watch": "npm run test-only -- --watch",

src/index.ts

+28-16
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,32 @@ export type MutationHandler<S, P> = (state: S, payload: P) => void
77
export type ActionHandler<S, R, P, T> = (context: BareActionContext<S, R>, payload: P) => Promise<T> | T
88
export type GetterHandler<S, R, T> = (state: S, rootState: R) => T
99

10+
interface RootStore<R> extends Store<R> { rootGetters?: any }
11+
1012
export interface BareActionContext<S, R>
1113
{
12-
state: S;
13-
rootState: R;
14+
state: S
15+
rootState: R
1416
}
1517

1618
export class ModuleBuilder<S, R> {
17-
private store: Store<R>
19+
private store: RootStore<R>
1820

1921
private getters: GetterTree<S, R> = {}
2022
private mutations: MutationTree<S> = {}
2123
private actions: ActionTree<S, R> = {}
2224

2325
constructor(private namespace: string, private state: S) { }
2426

25-
provideStore(store: Store<R>)
26-
{
27-
this.store = store
28-
}
29-
3027
commit<P>(handler: MutationHandler<S, void>): () => void
3128
commit<P>(handler: MutationHandler<S, P>): (payload: P) => void
3229
commit<P>(handler: MutationHandler<S, void>, name: string): () => void
3330
commit<P>(handler: MutationHandler<S, P>, name: string): (payload: P) => void
3431
commit<P>(handler: MutationHandler<S, P>, name?: string)
3532
{
36-
const key = qualifyKey(handler, this.namespace, name)
37-
return ((payload: P) => this.store.commit(key, payload, useRootNamespace)) as any
33+
const { key, namespacedKey } = qualifyKey(handler, this.namespace, name)
34+
this.mutations[key] = handler
35+
return ((payload: P) => this.store.commit(namespacedKey, payload, useRootNamespace)) as any
3836
}
3937

4038
dispatch<P, T>(handler: ActionHandler<S, R, void, void>): () => Promise<void>
@@ -47,16 +45,30 @@ export class ModuleBuilder<S, R> {
4745
dispatch<P, T>(handler: ActionHandler<S, R, P, T>, name: string): (payload: P) => Promise<T>
4846
dispatch<P, T>(handler: any, name?: string): any
4947
{
50-
const key = qualifyKey(handler, this.namespace, name)
51-
return (payload: P) => this.store.dispatch(key, payload, useRootNamespace)
48+
const { key, namespacedKey } = qualifyKey(handler, this.namespace, name)
49+
this.actions[key] = handler
50+
return (payload: P) => this.store.dispatch(namespacedKey, payload, useRootNamespace)
5251
}
5352

5453
read<T>(handler: GetterHandler<S, R, T>): () => T
5554
read<T>(handler: GetterHandler<S, R, T>, name: string): () => T
5655
read<T>(handler: GetterHandler<S, R, T>, name?: string): () => T
5756
{
58-
const key = qualifyKey(handler, this.namespace, name)
59-
return () => this.store.getters[key] as T
57+
const { key, namespacedKey } = qualifyKey(handler, this.namespace, name)
58+
this.getters[key] = handler
59+
return () =>
60+
{
61+
if (this.store.rootGetters)
62+
{
63+
return this.store.rootGetters[namespacedKey] as T
64+
}
65+
return this.store.getters[namespacedKey] as T
66+
}
67+
}
68+
69+
provideStore(): (store: Store<R>) => void
70+
{
71+
return (store) => this.store = store
6072
}
6173

6274
toVuexModule(): Module<S, R>
@@ -71,12 +83,12 @@ export class ModuleBuilder<S, R> {
7183
}
7284
}
7385

74-
function qualifyKey(handler: Function, namespace: string | undefined, name?: string)
86+
function qualifyKey(handler: Function, namespace: string | undefined, name?: string): { key: string, namespacedKey: string }
7587
{
7688
const key: string = name || handler.name
7789
if (!key)
7890
{
7991
throw new Error(`Vuex handler functions must not be anonymous. Possible causes: fat-arrow functions, uglify`)
8092
}
81-
return namespace ? `${namespace}/${key}` : key
93+
return namespace ? { key, namespacedKey: `${namespace}/${key}` } : { key, namespacedKey: key }
8294
}

src/tests/main.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { expect } from "chai"
2+
import * as Vue from "vue"
3+
import * as Vuex from "vuex"
4+
import { createStore } from "./store"
5+
import { RootState } from "./store/index"
6+
import birthday from "./store/birthday/birthday"
7+
import auth from "./store/auth/auth"
8+
9+
let store: Vuex.Store<RootState>
10+
11+
async function test()
12+
{
13+
Vue.use(Vuex)
14+
store = createStore()
15+
store.replaceState({
16+
birthday: {
17+
birthdays: [
18+
{ name: "Richard", dob: new Date(1995, 10, 11) },
19+
{ name: "Erlich", dob: new Date(1983, 1, 17) },
20+
{ name: "Nelson", dob: new Date(1996, 3, 28) },
21+
{ name: "Dinesh", dob: new Date(1989, 1, 7) },
22+
{ name: "Bertram", dob: new Date(1985, 7, 14) },
23+
{ name: "Donald", dob: new Date(1994, 5, 31) },
24+
{ name: "Monica", dob: new Date(1996, 8, 26) },
25+
]
26+
},
27+
auth: { isLoggedIn: false, userID: "" }
28+
})
29+
auth.provideStore(store)
30+
birthday.provideStore(store)
31+
expect(birthday.oldestName).equal("Erlich")
32+
await birthday.dispatchRemoveFirstAfterDelay(20)
33+
await birthday.dispatchRemoveFirstAfterDelay(20)
34+
expect(birthday.oldestName).equal("Bertram")
35+
}
36+
37+
test();

src/tests/store.spec.ts

+45-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
1-
import { expect } from "chai";
2-
import * as Vue from "vue";
3-
import * as Vuex from "vuex";
4-
import { createStore, State } from "./store";
5-
import * as basket from "./store/basket";
1+
import { expect } from "chai"
2+
import * as Vue from "vue"
3+
import * as Vuex from "vuex"
4+
import { createStore } from "./store"
5+
import { RootState } from "./store/index"
6+
import birthday from "./store/birthday/birthday"
7+
import auth from "./store/auth/auth"
8+
9+
describe("Running an action", () =>
10+
{
11+
let store: Vuex.Store<RootState>
12+
13+
beforeEach(() =>
14+
{
15+
Vue.use(Vuex)
16+
store = createStore()
17+
store.replaceState({
18+
birthday: {
19+
birthdays: [
20+
{ name: "Richard", dob: new Date(1995, 10, 11) },
21+
{ name: "Erlich", dob: new Date(1983, 1, 17) },
22+
{ name: "Nelson", dob: new Date(1996, 3, 28) },
23+
{ name: "Dinesh", dob: new Date(1989, 1, 7) },
24+
{ name: "Bertram", dob: new Date(1985, 7, 14) },
25+
{ name: "Donald", dob: new Date(1994, 5, 31) },
26+
{ name: "Monica", dob: new Date(1996, 8, 26) },
27+
]
28+
},
29+
auth: { isLoggedIn: false, userID: "" }
30+
})
31+
auth.provideStore(store)
32+
birthday.provideStore(store)
33+
})
34+
35+
describe("remove first 2 birthdays", () =>
36+
{
37+
it("should show Bertram after removing first two birthdays", async () =>
38+
{
39+
expect(birthday.oldestName).equal("Erlich")
40+
await birthday.dispatchRemoveFirstAfterDelay(25)
41+
await birthday.dispatchRemoveFirstAfterDelay(25)
42+
expect(birthday.oldestName).equal("Bertram")
43+
})
44+
})
45+
})

src/tests/store/auth/auth.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11

2+
import * as Vuex from "vuex"
23
import { ModuleBuilder } from "../../.."
34
import { AuthState } from "./state"
45
import { RootState } from "../index"
56
import { Module } from "vuex"
67

78
const initialState: AuthState = {
89
userID: "b6c8185c6d0af2f5d968",
9-
isLoggedIn: true
10+
isLoggedIn: true
1011
}
1112

12-
const m = new ModuleBuilder<AuthState, RootState>("auth", initialState)
13+
const a = new ModuleBuilder<AuthState, RootState>("auth", initialState)
1314

1415
const auth = {
15-
commitSetUserID: m.commit((state, payload: { userID: string }) => state.userID = payload.userID),
16-
commitSetIsLoggedIn: m.commit((state, payload: { isLoggedIn: boolean }) => state.isLoggedIn = payload.isLoggedIn),
17-
dispatchLogin: m.dispatch((context) =>
16+
commitSetUserID: a.commit((state, payload: { userID: string }) => state.userID = payload.userID, "setUserID"),
17+
commitSetIsLoggedIn: a.commit((state, payload: { isLoggedIn: boolean }) => state.isLoggedIn = payload.isLoggedIn, "isLoggedIn"),
18+
dispatchLogin: a.dispatch((context) =>
1819
{
1920
return
20-
})
21+
}, "login"),
22+
provideStore: a.provideStore()
2123
}
2224

2325
export default auth
24-
export const birthdayModule: Module<AuthState, RootState> = m.toVuexModule()
26+
export const authModule: Module<AuthState, RootState> = a.toVuexModule()
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import birthday from "../birthday"
22
import { BareActionContext } from "../../../../index"
33
import { BirthdayState } from "../state"
4-
import { RootState } from "../../root"
4+
import { RootState } from "../../index"
55

6-
export default async function removeFirstAfter(context: BareActionContext<BirthdayState, RootState>, delay: number)
6+
export default async function removeFirstAfterDelay(context: BareActionContext<BirthdayState, RootState>, delay: number)
77
{
88
if (context.state.birthdays.length > 2)
99
{
10-
await new Promise((resolve, _) => setTimeout(resolve, 1000)); // second delay
10+
await new Promise((resolve, _) => setTimeout(resolve, delay)); // second delay
1111
birthday.commitRemoveFirstBirthday()
1212
}
1313
}

src/tests/store/birthday/birthday.ts

+14-42
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,27 @@
11

2+
import * as Vuex from "vuex"
23
import { ModuleBuilder } from "../../.."
34
import { BirthdayState, Birthday } from "./state"
45
import { Module } from "vuex"
5-
import { RootState } from "../root"
6-
import * as Vuex from "vuex"
7-
import removeFirstAfter from "../../../../dist/tests/store/birthday/actions/removeFirstAfter"
6+
import { RootState } from "../index"
7+
import removeFirstAfterDelay from "./actions/removeFirstAfter";
88

99
const initialState: BirthdayState = {
10-
birthdays: [
11-
{
12-
name: "Richard",
13-
dob: new Date(1995, 10, 11)
14-
},
15-
{
16-
name: "Erlich",
17-
dob: new Date(1983, 1, 17)
18-
},
19-
{
20-
name: "Nelson",
21-
dob: new Date(1996, 3, 28)
22-
},
23-
{
24-
name: "Dinesh",
25-
dob: new Date(1989, 1, 7)
26-
},
27-
{
28-
name: "Bertram",
29-
dob: new Date(1985, 7, 14)
30-
},
31-
{
32-
name: "Donald",
33-
dob: new Date(1994, 5, 31)
34-
},
35-
{
36-
name: "Monica",
37-
dob: new Date(1996, 8, 26)
38-
}
39-
]
10+
birthdays: []
4011
}
4112

42-
const m = new ModuleBuilder<BirthdayState, RootState>("birthday", initialState)
13+
const b = new ModuleBuilder<BirthdayState, RootState>("birthday", initialState)
4314

4415
const addBirthdayMut = (state: BirthdayState, payload: { birthday: Birthday }) => state.birthdays.push(payload.birthday)
4516
const removeFirstBirthdayMut = (state: BirthdayState) => state.birthdays.shift()
4617

47-
const oldestNameGetter = m.read((state): Birthday | undefined =>
18+
const oldestNameGetter = b.read((state): string | undefined =>
4819
{
49-
const sortedBirthdays = (<Birthday[]>[]).sort((a, b) => a.dob.getTime() - b.dob.getTime())
50-
return sortedBirthdays[0]
20+
const oldestBirthday = (<Birthday[]>state.birthdays).slice().sort((a, b) => a.dob.getTime() - b.dob.getTime())[0]
21+
return oldestBirthday && oldestBirthday.name
5122
}, "oldestName")
5223

53-
const dateOfBirthForMethod = m.read((state) => (name: string) =>
24+
const dateOfBirthForMethod = b.read((state) => (name: string) =>
5425
{
5526
const matches = state.birthdays.filter(b => b.name === name)
5627
if (matches.length)
@@ -67,11 +38,12 @@ const birthday = {
6738
dateOfBirthFor(name: string) { return dateOfBirthForMethod()(name) },
6839

6940
// mutations
70-
commitAddBirthday: m.commit(addBirthdayMut),
71-
commitRemoveFirstBirthday: m.commit(removeFirstBirthdayMut),
41+
commitAddBirthday: b.commit(addBirthdayMut),
42+
commitRemoveFirstBirthday: b.commit(removeFirstBirthdayMut),
7243

7344
// actions
74-
dispatchRemoveFirstAfter: m.dispatch(removeFirstAfter)
45+
dispatchRemoveFirstAfterDelay: b.dispatch(removeFirstAfterDelay),
46+
provideStore: b.provideStore()
7547
}
7648

7749
// birthday.commitAddBirthday({ birthday: { dob: new Date(1980, 2, 3), name: "Louise" } })
@@ -80,4 +52,4 @@ const birthday = {
8052
// birthday.dispatchRemoveFirstAfter(1000)
8153

8254
export default birthday
83-
export const birthdayModule: Module<BirthdayState, RootState> = m.toVuexModule()
55+
export const birthdayModule: Module<BirthdayState, RootState> = b.toVuexModule()

src/tests/store/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface RootState
1111
birthday: BirthdayState
1212
}
1313

14-
export const createStore = new Store({
14+
export const createStore = () => new Store<RootState>({
1515
modules: {
1616
auth: authModule,
1717
birthday: birthdayModule

0 commit comments

Comments
 (0)