Skip to content
Permalink
Browse files

feat(generators): add blueprint for CRUD module (#467)

closes #442
  • Loading branch information
devCrossNet committed Oct 1, 2019
1 parent 04fbabb commit 05ee8d92cf423a469d13d229e3978d55437a7b15
@@ -1,30 +1,29 @@
import { createLocalVue, mount } from '@vue/test-utils';{{#if wantVuex}}
import { createLocalVue, mount } from '@vue/test-utils';
import Vuex, { Store } from 'vuex';
import { i18n } from '@/app/shared/plugins/i18n/i18n';
import {{ properCase componentName }} from './{{ properCase componentName }}.vue';
import { I{{ properCase componentName }}State } from '../state';
import { {{ properCase componentName }}Module } from '../module';{{/if}}
import { I{{ properCase singularName }}State } from '../state';
import { {{ properCase singularName }}Module } from '../module';

const localVue = createLocalVue();{{#if wantVuex}}

localVue.use(Vuex);{{/if}}

describe('{{ properCase componentName }}.vue', () => {
{{#if wantVuex}}
let store: Store<I{{ properCase componentName }}State>;
let store: Store<I{{ properCase singularName }}State>;

beforeEach(() => {
store = new Vuex.Store({
modules: {
{{ camelCase moduleName }}: {{ properCase componentName }}Module,
{{ camelCase singularName }}: {{ properCase singularName }}Module,
},
} as any);
});

{{/if}} test('renders component', () => {
test('renders component', () => {
const wrapper = mount<any>({{ properCase componentName }}, {
{{#if wantVuex}} store,
{{/if}} localVue,
store,
localVue,
i18n,
stubs: ['router-link'],
});
@@ -1,6 +1,8 @@
<template>
<div :class="$style.{{ camelCase componentName }}">
<vue-grid>
<vue-breadcrumb :items="breadCrumbItems"></vue-breadcrumb>

<vue-grid-row>
<vue-grid-item fill>
<vue-headline level="1">{{ properCase componentName }}</vue-headline>
@@ -10,35 +12,45 @@
</div>
</template>

<script lang="ts">{{#if wantVuex}}
<script lang="ts">
import { registerModule } from '@/app/store';
import { {{ properCase moduleName }}Module } from '../module';
import { IPreLoad } from '@/server/isomorphic';{{/if}}
import { IPreLoad } from '@/server/isomorphic';
import VueGrid from '@/app/shared/components/VueGrid/VueGrid.vue';
import VueBreadcrumb from '@components/VueBreadcrumb/VueBreadcrumb.vue';
import VueGridRow from '@/app/shared/components/VueGridRow/VueGridRow.vue';
import VueGridItem from '@/app/shared/components/VueGridItem/VueGridItem.vue';
import VueButton from '@/app/shared/components/VueButton/VueButton.vue';
import VueGridRow from '@/app/shared/components/VueGridRow/VueGridRow.vue';
import VueHeadline from '@/app/shared/components/VueHeadline/VueHeadline.vue';
import { {{ properCase singularName }}Module } from '../module';
export default {
metaInfo: {
title: '{{ properCase componentName }}',
},
components: {
VueGrid,
VueBreadcrumb,
VueGridRow,
VueGridItem,
VueButton,
VueGridRow,
VueHeadline,
},
data: (): any => ({}),
methods: {},
computed: {},{{#if wantVuex}}
computed: {
breadCrumbItems() {
return [
{ label: this.$t('common.home' /* Home */), href: '/' },
{ label: this.$t('common.{{ properCase singularName }}' /* {{ properCase singularName }} */), href: '/{{ dashCase singularName }}' },
];
},
},
beforeCreate() {
registerModule('{{ camelCase moduleName }}', {{ properCase moduleName }}Module);
registerModule('{{ camelCase singularName }}', {{ properCase singularName }}Module);
},
prefetch: (options: IPreLoad) => {
registerModule('{{ camelCase moduleName }}', {{ properCase moduleName }}Module);
registerModule('{{ camelCase singularName }}', {{ properCase singularName }}Module);
/**
* This is the function where you can load all the data that is needed
@@ -47,13 +59,13 @@ export default {
* This function always returns a promise that means, if you want to
* call a vuex action you have to return it, here is an example
*
* return options.store.dispatch('myAction');
* return options.store.dispatch('fetch{{ properCase singularName }}', '1');
*
* If you need to fetch data from multiple source your can also return
* a Promise chain or a Promise.all()
*/
return Promise.resolve();
},{{/if}}
},
};
</script>

@@ -62,7 +74,6 @@ export default {
.{{ camelCase componentName }} {
margin-top: $nav-bar-height;
padding: $space-32 0;
min-height: 500px;
}
</style>
@@ -0,0 +1,146 @@
import { ActionContext, Commit, Dispatch } from 'vuex';
import MockAdapter from 'axios-mock-adapter';
import { IState } from '@/app/state';
import { HttpService } from '@/app/shared/services/HttpService/HttpService';
import { {{ properCase singularName }}Actions } from './actions';
import { {{ properCase singularName }}DefaultState, I{{ properCase singularName }}State } from './state';

describe('{{ properCase singularName }}Actions', () => {
let testContext: ActionContext<I{{ properCase singularName }}State, IState>;
let mockAxios: MockAdapter;

beforeEach(() => {
testContext = {
dispatch: jest.fn() as Dispatch,
commit: jest.fn() as Commit,
state: {{ properCase singularName }}DefaultState(),
} as ActionContext<I{{ properCase singularName }}State, IState>;

mockAxios = new MockAdapter(HttpService);
});

describe('fetch{{ properCase pluralName }}', () => {
test('it should call SET_{{ constantCase pluralName }} on success', async () => {
const commitMock: jest.Mock = testContext.commit as jest.Mock;
const expected = {};

mockAxios.onGet('/{{ singularName }}').reply(200, expected);

await {{ properCase singularName }}Actions.fetch{{ properCase pluralName }}(testContext);

const actual = commitMock.mock.calls[0];

expect(actual).toEqual(['SET_{{ constantCase pluralName }}', expected]);
});

test('it should throw an error on failure', async () => {
mockAxios.onGet('/{{ singularName }}').reply(500);

try {
await {{ properCase singularName }}Actions.fetch{{ properCase pluralName }}(testContext);
} catch (e) {
expect(e.message).toEqual('Request failed with status code 500');
}
});
});

describe('fetch{{ properCase singularName }}', () => {
test('it should call SET_CURRENT_{{ constantCase singularName }} on success', async () => {
const commitMock: jest.Mock = testContext.commit as jest.Mock;
const expected = {};

mockAxios.onGet('/{{ singularName }}/1').reply(200, expected);

await {{ properCase singularName }}Actions.fetch{{ properCase singularName }}(testContext, '1');

const actual = commitMock.mock.calls[0];

expect(actual).toEqual(['SET_CURRENT_{{ constantCase singularName }}', expected]);
});

test('it should throw an error on failure', async () => {
mockAxios.onGet('/{{ singularName }}/1').reply(500);

try {
await {{ properCase singularName }}Actions.fetch{{ properCase singularName }}(testContext, '1');
} catch (e) {
expect(e.message).toEqual('Request failed with status code 500');
}
});
});

describe('add{{ properCase singularName }}', () => {
test('it should call ADD_{{ constantCase singularName }} on success', async () => {
const commitMock: jest.Mock = testContext.commit as jest.Mock;
const expected = {};

mockAxios.onPost('/{{ singularName }}').reply(200, expected);

await {{ properCase singularName }}Actions.add{{ properCase singularName }}(testContext, expected);

const actual = commitMock.mock.calls[0];

expect(actual).toEqual(['ADD_{{ constantCase singularName }}', expected]);
});

test('it should throw an error on failure', async () => {
mockAxios.onPost('/{{ singularName }}').reply(500);

try {
await {{ properCase singularName }}Actions.add{{ properCase singularName }}(testContext, {});
} catch (e) {
expect(e.message).toEqual('Request failed with status code 500');
}
});
});

describe('update{{ properCase singularName }}', () => {
test('it should call UPDATE_{{ constantCase singularName }} on success', async () => {
const commitMock: jest.Mock = testContext.commit as jest.Mock;
const expected = { id: '1' };

mockAxios.onPut('/{{ singularName }}/1').reply(200, expected);

await {{ properCase singularName }}Actions.update{{ properCase singularName }}(testContext, expected);

const actual = commitMock.mock.calls[0];

expect(actual).toEqual(['UPDATE_{{ constantCase singularName }}', expected]);
});

test('it should throw an error on failure', async () => {
mockAxios.onPut('/{{ singularName }}/1').reply(500);

try {
await {{ properCase singularName }}Actions.update{{ properCase singularName }}(testContext, { id: '1' });
} catch (e) {
expect(e.message).toEqual('Request failed with status code 500');
}
});
});

describe('delete{{ properCase singularName }}', () => {
test('it should call DELETE_{{ constantCase singularName }} on success', async () => {
const commitMock: jest.Mock = testContext.commit as jest.Mock;
const expected = { id: '1' };

mockAxios.onDelete('/{{ singularName }}/1').reply(200, expected);

await {{ properCase singularName }}Actions.delete{{ properCase singularName }}(testContext, expected);

const actual = commitMock.mock.calls[0];

expect(actual).toEqual(['DELETE_{{ constantCase singularName }}', expected]);
});

test('it should throw an error on failure', async () => {
mockAxios.onDelete('/{{ singularName }}/1').reply(500);

try {
await {{ properCase singularName }}Actions.delete{{ properCase singularName }}(testContext, { id: '1' });
} catch (e) {
expect(e.message).toEqual('Request failed with status code 500');
}
});
});
});
@@ -0,0 +1,56 @@
import { ActionContext } from 'vuex';
import { IState } from '@/app/state';
import { HttpService } from '@/app/shared/services/HttpService/HttpService';
import { I{{ properCase singularName }}State } from './state';
import { I{{ properCase singularName }} } from './I{{ properCase singularName }}';

export interface I{{ properCase singularName }}Actions {
fetch{{ properCase pluralName }}(context: ActionContext<I{{ properCase singularName }}State, IState>): Promise<any>;
fetch{{ properCase singularName }}(context: ActionContext<I{{ properCase singularName }}State, IState>, id: string): Promise<any>;
add{{ properCase singularName }}(context: ActionContext<I{{ properCase singularName }}State, IState>, {{ camelCase singularName }}: I{{ properCase singularName }}): Promise<any>;
update{{ properCase singularName }}(context: ActionContext<I{{ properCase singularName }}State, IState>, {{ camelCase singularName }}: I{{ properCase singularName }}): Promise<any>;
delete{{ properCase singularName }}(context: ActionContext<I{{ properCase singularName }}State, IState>, {{ camelCase singularName }}: I{{ properCase singularName }}): Promise<any>;
}

export const {{ properCase singularName }}Actions: I{{ properCase singularName }}Actions = {
async fetch{{ properCase pluralName }}({ commit }) {
try {
const response = await HttpService.get<I{{ properCase singularName }}[]>('/{{ singularName }}');
commit('SET_{{ constantCase pluralName }}', response.data);
} catch (e) {
throw e;
}
},
async fetch{{ properCase singularName }}({ commit }, id) {
try {
const response = await HttpService.get<I{{ properCase singularName }}>(`/{{ singularName }}/${ id }`);
commit('SET_CURRENT_{{ constantCase singularName }}', response.data);
} catch (e) {
throw e;
}
},
async add{{ properCase singularName }}({ commit }, {{ camelCase singularName }}) {
try {
const response = await HttpService.post<I{{ properCase singularName }}>('/{{ singularName }}', {{ camelCase singularName }});
commit('ADD_{{ constantCase singularName }}', response.data);
} catch (e) {
throw e;
}
},
async update{{ properCase singularName }}({ commit }, {{ camelCase singularName }}) {
try {
const response = await HttpService.put<I{{ properCase singularName }}>(`/{{ singularName }}/${ {{ camelCase singularName }}.id }`, {{ camelCase singularName }});
commit('UPDATE_{{ constantCase singularName }}', response.data);
} catch (e) {
throw e;
}
},
async delete{{ properCase singularName }}({ commit }, {{ camelCase singularName }}) {
try {
await HttpService.delete<I{{ properCase singularName }}>(`/{{ singularName }}/${ {{ camelCase singularName }}.id }`);
commit('DELETE_{{ constantCase singularName }}', {{ camelCase singularName }});
} catch (e) {
throw e;
}
},
};
@@ -0,0 +1,18 @@
import { {{ properCase singularName }}Getters } from './getters';
import { {{ properCase singularName }}DefaultState, I{{ properCase singularName }}State } from './state';

describe('{{ properCase singularName }}Getters', () => {
let testState: I{{ properCase singularName }}State;

beforeEach(() => {
testState = {{ properCase singularName }}DefaultState();
});

test('it should get the {{ camelCase pluralName }}', () => {
expect({{ properCase singularName }}Getters.{{ camelCase pluralName }}(testState)).toEqual(testState.{{ camelCase pluralName }});
});

test('it should get the {{ camelCase pluralName }}', () => {
expect({{ properCase singularName }}Getters.current{{ properCase singularName }}(testState)).toEqual(testState.current{{ properCase singularName }});
});
});
@@ -0,0 +1,16 @@
import { I{{ properCase singularName }}State } from './state';
import { I{{ properCase singularName }} } from './I{{ properCase singularName }}';

export interface I{{ properCase singularName }}Getters {
{{ camelCase pluralName }}(state: I{{ properCase singularName }}State): I{{ properCase singularName }}[];
current{{ properCase singularName }}(state: I{{ properCase singularName }}State): I{{ properCase singularName }};
}

export const {{ properCase singularName }}Getters: I{{ properCase singularName }}Getters = {
{{ camelCase pluralName }}(state) {
return state.{{ camelCase pluralName }};
},
current{{ properCase singularName }}(state) {
return state.current{{ properCase singularName }};
},
};
@@ -0,0 +1,6 @@
export interface I{{properCase singularName}} {
/**
* define your data structure here
*/
id?: string;
}
@@ -0,0 +1,22 @@
import { Module } from 'vuex';
import { IState } from '@/app/state';
import { {{ properCase singularName }}DefaultState, I{{ properCase singularName }}State } from './state';
import { {{ properCase singularName }}Actions } from './actions';
import { {{ properCase singularName }}Getters } from './getters';
import { {{ properCase singularName }}Mutations } from './mutations';

export const {{ properCase singularName }}Module: Module<I{{ properCase singularName }}State, IState> = {
namespaced: true,
actions: {
...{{ properCase singularName }}Actions,
},
getters: {
...{{ properCase singularName }}Getters,
},
state: {
...{{ properCase singularName }}DefaultState(),
},
mutations: {
...{{ properCase singularName }}Mutations,
},
};

0 comments on commit 05ee8d9

Please sign in to comment.
You can’t perform that action at this time.