diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 902b71b11..ff6f4e831 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -441,7 +441,7 @@ jobs: report_name: Coverage Admin Interface type: lcov result_path: ./coverage/lcov.info - min_coverage: 65 + min_coverage: 47 token: ${{ github.token }} ############################################################################## @@ -491,7 +491,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 38 + min_coverage: 37 token: ${{ github.token }} ############################################################################## diff --git a/admin/jest.config.js b/admin/jest.config.js index ac132eed2..b7226bd8f 100644 --- a/admin/jest.config.js +++ b/admin/jest.config.js @@ -1,6 +1,11 @@ module.exports = { verbose: true, - collectCoverageFrom: ['src/**/*.{js,vue}', '!**/node_modules/**', '!**/?(*.)+(spec|test).js?(x)'], + collectCoverageFrom: [ + 'src/**/*.{js,vue}', + '!**/node_modules/**', + '!src/assets/**', + '!**/?(*.)+(spec|test).js?(x)', + ], moduleFileExtensions: [ 'js', // 'jsx', diff --git a/admin/package.json b/admin/package.json index 3e1522f91..e3c94f5d8 100644 --- a/admin/package.json +++ b/admin/package.json @@ -35,6 +35,7 @@ "identity-obj-proxy": "^3.0.0", "jest": "26.6.3", "moment": "^2.29.1", + "regenerator-runtime": "^0.13.9", "stats-webpack-plugin": "^0.7.0", "vue": "^2.6.11", "vue-apollo": "^3.0.8", diff --git a/admin/src/App.spec.js b/admin/src/App.spec.js new file mode 100644 index 000000000..e77bc578b --- /dev/null +++ b/admin/src/App.spec.js @@ -0,0 +1,26 @@ +import { shallowMount } from '@vue/test-utils' +import App from './App' + +const localVue = global.localVue + +const stubs = { + RouterView: true, +} + +describe('App', () => { + let wrapper + + const Wrapper = () => { + return shallowMount(App, { localVue, stubs }) + } + + describe('shallowMount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a div with id "app"', () => { + expect(wrapper.find('div#app').exists()).toBeTruthy() + }) + }) +}) diff --git a/admin/src/components/Footer.vue b/admin/src/components/ContentFooter.vue similarity index 75% rename from admin/src/components/Footer.vue rename to admin/src/components/ContentFooter.vue index 398f2e180..ade4e0a83 100644 --- a/admin/src/components/Footer.vue +++ b/admin/src/components/ContentFooter.vue @@ -8,3 +8,8 @@ + diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js index f218cf8e2..fcdf97cfa 100644 --- a/admin/src/components/CreationFormular.spec.js +++ b/admin/src/components/CreationFormular.spec.js @@ -19,7 +19,7 @@ const mocks = { const propsData = { type: '', item: {}, - creation: {}, + creation: [], itemsMassCreation: {}, } @@ -38,5 +38,104 @@ describe('CreationFormular', () => { it('has a DIV element with the class.component-creation-formular', () => { expect(wrapper.find('.component-creation-formular').exists()).toBeTruthy() }) + + describe('radio buttons to selcet month', () => { + it('has three radio buttons', () => { + expect(wrapper.findAll('input[type="radio"]').length).toBe(3) + }) + + describe('with mass creation', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.setProps({ type: 'massCreation' }) + }) + + describe('first radio button', () => { + beforeEach(async () => { + await wrapper.findAll('input[type="radio"]').at(0).setChecked() + }) + + it('emits update-radio-selected with index 0', () => { + expect(wrapper.emitted()['update-radio-selected']).toEqual([ + [expect.arrayContaining([0])], + ]) + }) + }) + + describe('second radio button', () => { + beforeEach(async () => { + await wrapper.findAll('input[type="radio"]').at(1).setChecked() + }) + + it('emits update-radio-selected with index 1', () => { + expect(wrapper.emitted()['update-radio-selected']).toEqual([ + [expect.arrayContaining([1])], + ]) + }) + }) + + describe('third radio button', () => { + beforeEach(async () => { + await wrapper.findAll('input[type="radio"]').at(2).setChecked() + }) + + it('emits update-radio-selected with index 2', () => { + expect(wrapper.emitted()['update-radio-selected']).toEqual([ + [expect.arrayContaining([2])], + ]) + }) + }) + }) + + describe('with single creation', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] }) + await wrapper.setData({ rangeMin: 180 }) + }) + + describe('first radio button', () => { + beforeEach(async () => { + await wrapper.findAll('input[type="radio"]').at(0).setChecked() + }) + + it('sets rangeMin to 0', () => { + expect(wrapper.vm.rangeMin).toBe(0) + }) + + it('sets rangeMax to 200', () => { + expect(wrapper.vm.rangeMax).toBe(200) + }) + }) + + describe('second radio button', () => { + beforeEach(async () => { + await wrapper.findAll('input[type="radio"]').at(1).setChecked() + }) + + it('sets rangeMin to 0', () => { + expect(wrapper.vm.rangeMin).toBe(0) + }) + + it('sets rangeMax to 400', () => { + expect(wrapper.vm.rangeMax).toBe(400) + }) + }) + + describe('third radio button', () => { + beforeEach(async () => { + await wrapper.findAll('input[type="radio"]').at(2).setChecked() + }) + + it('sets rangeMin to 0', () => { + expect(wrapper.vm.rangeMin).toBe(0) + }) + + it('sets rangeMax to 400', () => { + expect(wrapper.vm.rangeMax).toBe(600) + }) + }) + }) + }) }) }) diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index 995640c72..d6b637152 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -4,9 +4,10 @@

{{ this.type === 'singleCreation' - ? 'Einzelschöpfung für ' + item.first_name + ' ' + item.last_name + '' - : 'Massenschöpfung für ' + Object.keys(this.itemsMassCreation).length + ' Mitglieder' + ? 'Einzelschöpfung für ' + item.firstName + ' ' + item.lastName + '' + : 'Mehrfachschöpfung für ' + Object.keys(this.itemsMassCreation).length + ' Mitglieder' }} + {{ item }}

Bitte wähle ein oder Mehrere Mitglieder aus für die du Schöpfen möchtest @@ -26,7 +27,7 @@ size="lg" @change="updateRadioSelected(beforeLastMonth, 0, creation[0])" > - {{ beforeLastMonth }} {{ creation[0] != null ? creation[0] + ' GDD' : '' }} + {{ beforeLastMonth.short }} {{ creation[0] != null ? creation[0] + ' GDD' : '' }} @@ -36,7 +37,7 @@ size="lg" @change="updateRadioSelected(lastMonth, 1, creation[1])" > - {{ lastMonth }} {{ creation[1] != null ? creation[1] + ' GDD' : '' }} + {{ lastMonth.short }} {{ creation[1] != null ? creation[1] + ' GDD' : '' }} @@ -46,7 +47,7 @@ size="lg" @change="updateRadioSelected(currentMonth, 2, creation[2])" > - {{ currentMonth }} {{ creation[2] != null ? creation[2] + ' GDD' : '' }} + {{ currentMonth.short }} {{ creation[2] != null ? creation[2] + ' GDD' : '' }} @@ -73,6 +74,7 @@ :min="rangeMin" :max="rangeMax" step="10" + @load="checkFormForUpdate('range')" > @@ -83,6 +85,7 @@ v-model="text" :state="text.length >= 10" placeholder="Mindestens 10 Zeichen eingeben" + @load="checkFormForUpdate('text')" rows="3" >
@@ -96,6 +99,17 @@
+ Update Schöpfung ({{ type }},{{ pagetype }}) + + + ' + this.type + ' >> für VIELE ' + i + ' Mitglieder') this.submitObj = [ { @@ -191,32 +236,44 @@ export default { moderator: this.$store.state.moderator, }, ] - alert('MassenSCHÖPFUNG ABSENDEN FÜR >> ' + i + ' Mitglieder') + alert('MehrfachSCHÖPFUNG ABSENDEN FÜR >> ' + i + ' Mitglieder') // $store - offene Schöpfungen hochzählen this.$store.commit('openCreationsPlus', i) - // lösche alle Mitglieder aus der MassenSchöpfungsListe nach dem alle Massenschpfungen zum bestätigen gesendet wurden. + // lösche alle Mitglieder aus der MehrfachSchöpfungsListe nach dem alle Mehrfachschpfungen zum bestätigen gesendet wurden. this.$emit('remove-all-bookmark') } if (this.type === 'singleCreation') { // hinweis das eine einzelne schöpfung ausgeführt wird an (Vorname) - alert('SUBMIT CREATION => ' + this.type + ' >> für ' + this.item.first_name + '') + alert('SUBMIT CREATION => ' + this.type + ' >> für ' + this.item.firstName + '') // erstellen eines Arrays (submitObj) mit allen Daten this.submitObj = [ { item: this.item, - datum: this.radioSelected, + datum: this.radioSelected.long, amount: this.value, text: this.text, moderator: this.$store.state.moderator, }, ] - // hinweis das eine ein einzelne Schöpfung abgesendet wird an (email) - alert('EINZEL SCHÖPFUNG ABSENDEN FÜR >> ' + this.item.first_name + '') - // $store - offene Schöpfungen hochzählen - this.$store.commit('openCreationsPlus', 1) + + if (this.pagetype === 'PageCreationConfirm') { + // hinweis das eine ein einzelne Schöpfung abgesendet wird an (email) + alert('UPDATE EINZEL SCHÖPFUNG ABSENDEN FÜR >> ') + // umschreiben, update eine bestehende Schöpfung eine + this.$emit('update-creation-data', { + datum: this.radioSelected.long, + creationGdd: this.value, + text: this.text, + }) + } else { + // hinweis das eine ein einzelne Schöpfung abgesendet wird an (email) + alert('EINZEL SCHÖPFUNG ABSENDEN FÜR >> ' + this.item.firstName + '') + // $store - offene Schöpfungen hochzählen + this.$store.commit('openCreationsPlus', 1) + } } // das absendeergebniss im string ansehen diff --git a/admin/src/components/NavBar.spec.js b/admin/src/components/NavBar.spec.js index 6c92863c5..1d68b16ad 100644 --- a/admin/src/components/NavBar.spec.js +++ b/admin/src/components/NavBar.spec.js @@ -15,7 +15,7 @@ describe('NavBar', () => { let wrapper const Wrapper = () => { - return mount(NavBar, { localVue, mocks }) + return mount(NavBar, { mocks, localVue }) } describe('mount', () => { diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index 6fb0cb31f..c52743857 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -8,7 +8,7 @@ Usersuche | - Massenschöpfung + Mehrfachschöpfung { type: 'Type', itemsUser: [], fieldsTable: [], - creation: {}, + creation: [], } const Wrapper = () => { diff --git a/admin/src/components/UserTable.vue b/admin/src/components/UserTable.vue index b4b173782..265c2d12e 100644 --- a/admin/src/components/UserTable.vue +++ b/admin/src/components/UserTable.vue @@ -37,7 +37,12 @@ stacked="md" > @@ -132,7 +140,7 @@ export default { default: '', }, creation: { - type: Object, + type: Array, required: false, }, }, @@ -141,6 +149,7 @@ export default { }, data() { return { + creationData: {}, overlay: false, overlayBookmarkType: '', overlayItem: [], @@ -200,16 +209,28 @@ export default { } if (this.type === 'PageCreationConfirm') { - this.$emit('update-confirm-result', item, 'remove') + this.$emit('remove-confirm-result', item, 'remove') } }, bookmarkConfirm(item) { alert('die schöpfung bestätigen und abschließen') alert(JSON.stringify(item)) - this.$emit('update-confirm-result', item, 'remove') + this.$emit('remove-confirm-result', item, 'remove') }, - getCreationInMonths(creation) { - return creation.split(',') + editCreationUserTable(row, rowItem) { + alert('editCreationUserTable') + if (!row.detailsShowing) { + alert('offen edit loslegen') + // this.item = rowItem + this.creationData = rowItem + // alert(this.creationData) + } + row.toggleDetails() + }, + updateCreationData(data) { + this.creationData = { + ...data, + } }, }, } diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js new file mode 100644 index 000000000..86e333845 --- /dev/null +++ b/admin/src/graphql/searchUsers.js @@ -0,0 +1,12 @@ +import gql from 'graphql-tag' + +export const searchUsers = gql` + query ($searchText: String!) { + searchUsers(searchText: $searchText) { + firstName + lastName + email + creation + } + } +` diff --git a/admin/src/i18n.test.js b/admin/src/i18n.test.js new file mode 100644 index 000000000..e39e0e824 --- /dev/null +++ b/admin/src/i18n.test.js @@ -0,0 +1,30 @@ +import i18n from './i18n' +import VueI18n from 'vue-i18n' + +jest.mock('vue-i18n') + +describe('i18n', () => { + it('calls i18n with locale en', () => { + expect(VueI18n).toBeCalledWith( + expect.objectContaining({ + locale: 'en', + }), + ) + }) + + it('calls i18n with fallback locale en', () => { + expect(VueI18n).toBeCalledWith( + expect.objectContaining({ + fallbackLocale: 'en', + }), + ) + }) + + it('has a _t function', () => { + expect(i18n).toEqual( + expect.objectContaining({ + _t: expect.anything(), + }), + ) + }) +}) diff --git a/admin/src/main.js b/admin/src/main.js index b3925c9fe..3be3ae0bf 100644 --- a/admin/src/main.js +++ b/admin/src/main.js @@ -1,6 +1,9 @@ import Vue from 'vue' import App from './App.vue' +// without this async calls are not working +import 'regenerator-runtime' + import store from './store/store' import router from './router/router' @@ -22,7 +25,8 @@ import moment from 'vue-moment' const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) const authLink = new ApolloLink((operation, forward) => { - const token = '' // store.state.token + const token = store.state.token + operation.setContext({ headers: { Authorization: token && token.length > 0 ? `Bearer ${token}` : '', @@ -52,10 +56,13 @@ const apolloProvider = new VueApollo({ }) Vue.use(BootstrapVue) + Vue.use(IconsPlugin) Vue.use(moment) +Vue.use(VueApollo) + addNavigationGuards(router, store) new Vue({ diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue index 0f88199f8..7ab900b43 100644 --- a/admin/src/pages/Creation.vue +++ b/admin/src/pages/Creation.vue @@ -1,5 +1,5 @@