vuex-tstore
Version:
Provides a low-overhead TypeScript wrapper around Vuex that can trigger compilation errors and IntelliSense tips.
361 lines (289 loc) • 9.59 kB
text/typescript
import Vue from "vue";
import Vuex, { ActionContext } from "vuex";
import { Store } from "./store";
Vue.use(Vuex);
/*
|-----------------------------------------------------------------------------
| Test Bootstrapping
|-----------------------------------------------------------------------------
|
| We need some types and data to test against. This section sets up the data
| that the tests will be run against.
|
*/
type TestRootContext = ActionContext<TestState, TestState>;
type TestModuleContext = ActionContext<TestModule, TestState>;
interface TestState {
title: string;
}
interface TestModule {
value: number;
}
const testModuleStoreOptions = () => ({
namespaced: true,
state: (): TestModule => ({ value: 0 }),
actions: {
mpayload: async (
context: TestModuleContext,
payload: { value: number }
) => {
context.state.value = payload.value;
},
mnoPayload: async (context: TestModuleContext) => {
context.state.value = 0;
}
},
getters: {
mvalue: (state: TestModule) => state.value,
mupdate: (state: TestModule) => (val: number) => {
state.value = val;
return state.value;
}
},
mutations: {
mpayload: (context: TestModule, payload: { value: number }) => {
context.value = payload.value;
},
mnoPayload: (context: TestModule) => {
context.value = 0;
}
},
modules: {
submodule: {
namespaced: true,
state() { return { foo: "bar" }; }
}
}
});
const testRootStoreOptions = () => ({
state: (): TestState => ({ title: "Hello, world!" }),
actions: {
payload: async (context: TestRootContext, payload: { title: string }) => {
context.state.title = payload.title;
return true;
},
noPayload: async (context: TestRootContext) => {
context.state.title = "Hello, world!";
return true;
}
},
getters: {
title: (state: TestState) => state.title,
update: (state: TestState) => (val: string) => {
state.title = val;
return state.title;
}
},
mutations: {
payload: (context: TestState, payload: { title: string }) => {
context.title = payload.title;
},
noPayload: (context: TestState) => {
context.title = "Hello, world!";
}
},
modules: {
module: testModuleStoreOptions()
}
});
/*
|-----------------------------------------------------------------------------
| Tests
|-----------------------------------------------------------------------------
|
| This section conducts holistic tests on the Store class.
|
*/
test("Can create a Store", () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
expect(wrapper).toBeInstanceOf(Store);
});
test("Can access store actions", async () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
const title = `${Date.now()}`;
await wrapper.actions.payload({ title });
expect(wrapper.state.title).toBe(title);
await wrapper.actions.noPayload();
expect(wrapper.state.title).toBe("Hello, world!");
});
test("Can accept missing action config", () => {
const options = testRootStoreOptions();
delete options.actions;
const wrapper = new Store(options);
expect(wrapper.actions).toEqual({});
});
test("Can access store mutations", () => {
const options = testRootStoreOptions();
const store = new Store(options);
const title = `${Date.now()}`;
store.mutations.payload({ title });
expect(store.state.title).toBe(title);
store.mutations.noPayload();
expect(store.state.title).toBe("Hello, world!");
});
test("Can accept missing mutation config", () => {
const options = testRootStoreOptions();
delete options.mutations;
expect(new Store(options)).toBeTruthy();
});
test("Can access store getters", () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
expect(wrapper.getters.title).toBe(wrapper.state.title);
expect(wrapper.getters.title).toBe(wrapper.getters.title);
const title = `${Date.now()}`;
expect(wrapper.getters.update(title)).toBe(title);
});
test("Can accept missing getter config", () => {
const wrapper = new Store({});
expect(wrapper.getters).toEqual({});
});
test("Can access store modules", () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
expect(wrapper.modules.module).toBeInstanceOf(Store);
});
test("Can access module actions", async () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
const value = Math.random();
wrapper.modules.module.actions.mpayload({ value });
expect((wrapper.state as any).module.value).toBe(value);
await wrapper.modules.module.actions.mnoPayload();
expect((wrapper.state as any).module.value).toBe(0);
});
test("Can access module mutations", () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
const value = Math.random();
wrapper.modules.module.mutations.mpayload({ value });
expect((wrapper.state as any).module.value).toBe(value);
wrapper.modules.module.mutations.mnoPayload();
expect((wrapper.state as any).module.value).toBe(0);
});
test("Can access module getters", () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
expect(wrapper.modules.module.getters.mvalue).toBe(
wrapper.store.getters["module/mvalue"]
);
expect(wrapper.modules.module.getters.mvalue).toBe(
(wrapper.state as any).module.value
);
const value = Math.random();
expect(wrapper.modules.module.getters.mupdate(value)).toBe(value);
});
test("Can access module state", () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
expect(wrapper.modules.module.state.value).toBe(0);
const value = Math.random();
wrapper.modules.module.getters.mupdate(value);
expect(wrapper.modules.module.state.value).toBe(value);
expect(wrapper.modules.module.modules.submodule.state.foo).toBe("bar");
});
test("Can access non-namespaced modules", () => {
const options = testRootStoreOptions();
options.modules.module.namespaced = false;
const wrapper = new Store(options);
expect(wrapper.modules.module).toBeInstanceOf(Store);
expect(wrapper.modules.module.getters.mvalue).toBe(
(wrapper.state as any).module.value
);
expect(wrapper.modules.module.getters.mvalue).toBe(
wrapper.store.getters.mvalue
);
});
test("Can create commit listeners on mutations", () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
let onNoPayload = false;
let onPayload: any = null;
wrapper.mutations.noPayload.listen(() => {
onNoPayload = true;
});
wrapper.mutations.payload.listen(fnPayload => {
onPayload = fnPayload;
});
const payload = { title: "test" };
wrapper.mutations.payload(payload);
wrapper.mutations.noPayload();
expect(onPayload).toBe(payload);
expect(onNoPayload).toBe(true);
});
test("Can create before-action listeners on actions", async () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
let onNoPayload = false;
let onPayload: any = null;
wrapper.actions.noPayload.before(() => {
onNoPayload = true;
});
wrapper.actions.payload.before(fnPayload => {
onPayload = fnPayload;
});
const payload = { title: "test" };
wrapper.actions.payload(payload);
wrapper.actions.noPayload();
expect(onPayload).toBe(payload);
expect(onNoPayload).toBe(true);
});
test("Can create before-action listeners on store", async () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
let onNoPayload = false;
let onPayload: any = null;
const npPromise = wrapper.actions.noPayload.after(() => {
onNoPayload = true;
});
const pPromise = wrapper.actions.payload.after(fnPayload => {
onPayload = fnPayload;
});
const payload = { title: `${Date.now()}` };
wrapper.actions.payload(payload);
wrapper.actions.noPayload();
expect(onPayload).toBe(null);
expect(onNoPayload).toBe(false);
await Promise.all([npPromise, pPromise]);
expect(onPayload).toBe(payload);
expect(onNoPayload).toBe(true);
});
test("Can create before-action listeners on module actions", async () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
let onNoPayload = false;
let onPayload: any = null;
wrapper.modules.module.actions.mnoPayload.before(() => {
onNoPayload = true;
});
wrapper.modules.module.actions.mpayload.before(fnPayload => {
onPayload = fnPayload;
});
const payload = { value: Math.random() };
wrapper.modules.module.actions.mpayload(payload);
wrapper.modules.module.actions.mnoPayload();
expect(onPayload).toBe(payload);
expect(onNoPayload).toBe(true);
});
test("Can create after-action listeners on module actions", async () => {
const options = testRootStoreOptions();
const wrapper = new Store(options);
let onNoPayload = false;
let onPayload: any = null;
const npPromise = wrapper.modules.module.actions.mnoPayload.after(() => {
onNoPayload = true;
});
const pPromise = wrapper.modules.module.actions.mpayload.after(fnPayload => {
onPayload = fnPayload;
});
const payload = { value: Math.random() };
wrapper.modules.module.actions.mpayload(payload);
wrapper.modules.module.actions.mnoPayload();
expect(onPayload).toBe(null);
expect(onNoPayload).toBe(false);
await Promise.all([npPromise, pPromise]);
expect(onPayload).toBe(payload);
expect(onNoPayload).toBe(true);
});