diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 42c83ff06..24aec5fff 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: 69 + min_coverage: 76 token: ${{ github.token }} ############################################################################## diff --git a/admin/src/pages/Creation.spec.js b/admin/src/pages/Creation.spec.js index 02c2ed4ce..65e56ca33 100644 --- a/admin/src/pages/Creation.spec.js +++ b/admin/src/pages/Creation.spec.js @@ -1,5 +1,6 @@ -import { mount } from '@vue/test-utils' +import { shallowMount } from '@vue/test-utils' import Creation from './Creation.vue' +import Vue from 'vue' const localVue = global.localVue @@ -7,11 +8,19 @@ const apolloQueryMock = jest.fn().mockResolvedValue({ data: { searchUsers: [ { + id: 1, firstName: 'Bibi', lastName: 'Bloxberg', email: 'bibi@bloxberg.de', creation: [200, 400, 600], }, + { + id: 2, + firstName: 'Benjamin', + lastName: 'Blümchen', + email: 'benjamin@bluemchen.de', + creation: [800, 600, 400], + }, ], }, }) @@ -31,10 +40,10 @@ describe('Creation', () => { let wrapper const Wrapper = () => { - return mount(Creation, { localVue, mocks }) + return shallowMount(Creation, { localVue, mocks }) } - describe('mount', () => { + describe('shallowMount', () => { beforeEach(() => { wrapper = Wrapper() }) @@ -43,6 +52,170 @@ describe('Creation', () => { expect(wrapper.find('div.creation').exists()).toBeTruthy() }) + describe('apollo returns user array', () => { + it('calls the searchUser query', () => { + expect(apolloQueryMock).toBeCalled() + }) + + it('sets the data of itemsList', () => { + expect(wrapper.vm.itemsList).toEqual([ + { + id: 1, + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + creation: [200, 400, 600], + showDetails: false, + }, + { + id: 2, + firstName: 'Benjamin', + lastName: 'Blümchen', + email: 'benjamin@bluemchen.de', + creation: [800, 600, 400], + showDetails: false, + }, + ]) + }) + }) + + describe('update item', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + describe('push', () => { + beforeEach(() => { + wrapper.findComponent({ name: 'UserTable' }).vm.$emit( + 'update-item', + { + id: 2, + firstName: 'Benjamin', + lastName: 'Blümchen', + email: 'benjamin@bluemchen.de', + creation: [800, 600, 400], + showDetails: false, + }, + 'push', + ) + }) + + it('removes the pushed item from itemsList', () => { + expect(wrapper.vm.itemsList).toEqual([ + { + id: 1, + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + creation: [200, 400, 600], + showDetails: false, + }, + ]) + }) + + it('adds the pushed item to itemsMassCreation', () => { + expect(wrapper.vm.itemsMassCreation).toEqual([ + { + id: 2, + firstName: 'Benjamin', + lastName: 'Blümchen', + email: 'benjamin@bluemchen.de', + creation: [800, 600, 400], + showDetails: false, + }, + ]) + }) + + describe('remove', () => { + beforeEach(() => { + wrapper.findComponent({ name: 'UserTable' }).vm.$emit( + 'update-item', + { + id: 2, + firstName: 'Benjamin', + lastName: 'Blümchen', + email: 'benjamin@bluemchen.de', + creation: [800, 600, 400], + showDetails: false, + }, + 'remove', + ) + }) + + it('removes the item from itemsMassCreation', () => { + expect(wrapper.vm.itemsMassCreation).toEqual([]) + }) + + it('adds the item to itemsList', () => { + expect(wrapper.vm.itemsList).toEqual([ + { + id: 1, + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + creation: [200, 400, 600], + showDetails: false, + }, + { + id: 2, + firstName: 'Benjamin', + lastName: 'Blümchen', + email: 'benjamin@bluemchen.de', + creation: [800, 600, 400], + showDetails: false, + }, + ]) + }) + }) + }) + + describe('error', () => { + const consoleErrorMock = jest.fn() + const warnHandler = Vue.config.warnHandler + + beforeEach(() => { + Vue.config.warnHandler = (w) => {} + // eslint-disable-next-line no-console + console.error = consoleErrorMock + wrapper.findComponent({ name: 'UserTable' }).vm.$emit('update-item', {}, 'no-rule') + }) + + afterEach(() => { + Vue.config.warnHandler = warnHandler + }) + + it('throws an error', () => { + expect(consoleErrorMock).toBeCalledWith(expect.objectContaining({ message: 'no-rule' })) + }) + }) + }) + + describe('remove all bookmarks', () => { + beforeEach(async () => { + await wrapper.findComponent({ name: 'UserTable' }).vm.$emit( + 'update-item', + { + id: 2, + firstName: 'Benjamin', + lastName: 'Blümchen', + email: 'benjamin@bluemchen.de', + creation: [800, 600, 400], + showDetails: false, + }, + 'push', + ) + wrapper.findComponent({ name: 'CreationFormular' }).vm.$emit('remove-all-bookmark') + }) + + it('removes all items from itemsMassCreation', () => { + expect(wrapper.vm.itemsMassCreation).toEqual([]) + }) + + it('adds all items to itemsList', () => { + expect(wrapper.vm.itemsList).toHaveLength(2) + }) + }) + describe('apollo returns error', () => { beforeEach(() => { apolloQueryMock.mockRejectedValue({ diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue index 21d4aa11a..820f6382e 100644 --- a/admin/src/pages/Creation.vue +++ b/admin/src/pages/Creation.vue @@ -125,20 +125,9 @@ export default { throw new Error(event) } }, - - // updateRadioSelected(obj) { - // this.radioSelectedMass = obj[0] - // }, - removeAllBookmark() { - alert('remove all bookmarks') - const index = 0 - let i = 0 - - for (i; i < this.itemsMassCreation.length; i++) { - this.itemsList.push(this.itemsMassCreation[i]) - } - this.itemsMassCreation.splice(index, this.itemsMassCreation.length) + this.itemsMassCreation.forEach((item) => this.itemsList.push(item)) + this.itemsMassCreation = [] }, }, } diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 749f2f591..127e5f26c 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -6,7 +6,7 @@ import { UpdatePendingCreation } from '../model/UpdatePendingCreation' import { RIGHTS } from '../../auth/RIGHTS' import { TransactionRepository } from '../../typeorm/repository/Transaction' import { TransactionCreationRepository } from '../../typeorm/repository/TransactionCreation' -import { PendingCreationRepository } from '../../typeorm/repository/PendingCreation' +import { LoginPendingTasksAdminRepository } from '../../typeorm/repository/LoginPendingTasksAdmin' import { UserRepository } from '../../typeorm/repository/User' import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs' import UpdatePendingCreationArgs from '../arg/UpdatePendingCreationArgs' @@ -48,8 +48,8 @@ export class AdminResolver { const creations = await getUserCreations(user.id) const creationDateObj = new Date(creationDate) if (isCreationValid(creations, amount, creationDateObj)) { - const pendingCreationRepository = getCustomRepository(PendingCreationRepository) - const loginPendingTaskAdmin = pendingCreationRepository.create() + const loginPendingTasksAdminRepository = getCustomRepository(LoginPendingTasksAdminRepository) + const loginPendingTaskAdmin = loginPendingTasksAdminRepository.create() loginPendingTaskAdmin.userId = user.id loginPendingTaskAdmin.amount = BigInt(amount * 10000) loginPendingTaskAdmin.created = new Date() @@ -57,7 +57,7 @@ export class AdminResolver { loginPendingTaskAdmin.memo = memo loginPendingTaskAdmin.moderator = moderator - pendingCreationRepository.save(loginPendingTaskAdmin) + loginPendingTasksAdminRepository.save(loginPendingTaskAdmin) } return await getUserCreations(user.id) } @@ -70,8 +70,8 @@ export class AdminResolver { const userRepository = getCustomRepository(UserRepository) const user = await userRepository.findByEmail(email) - const pendingCreationRepository = getCustomRepository(PendingCreationRepository) - const updatedCreation = await pendingCreationRepository.findOneOrFail({ id }) + const loginPendingTasksAdminRepository = getCustomRepository(LoginPendingTasksAdminRepository) + const updatedCreation = await loginPendingTasksAdminRepository.findOneOrFail({ id }) if (updatedCreation.userId !== user.id) throw new Error('user of the pending creation and send user does not correspond') @@ -81,7 +81,7 @@ export class AdminResolver { updatedCreation.date = new Date(creationDate) updatedCreation.moderator = moderator - await pendingCreationRepository.save(updatedCreation) + await loginPendingTasksAdminRepository.save(updatedCreation) const result = new UpdatePendingCreation() result.amount = parseInt(amount.toString()) result.memo = updatedCreation.memo @@ -110,8 +110,8 @@ export class AdminResolver { @Query(() => [PendingCreation]) async getPendingCreations(): Promise { - const pendingCreationRepository = getCustomRepository(PendingCreationRepository) - const pendingCreations = await pendingCreationRepository.find() + const loginPendingTasksAdminRepository = getCustomRepository(LoginPendingTasksAdminRepository) + const pendingCreations = await loginPendingTasksAdminRepository.find() const pendingCreationsPromise = await Promise.all( pendingCreations.map(async (pendingCreation) => { @@ -137,16 +137,16 @@ export class AdminResolver { @Mutation(() => Boolean) async deletePendingCreation(@Arg('id') id: number): Promise { - const pendingCreationRepository = getCustomRepository(PendingCreationRepository) - const entity = await pendingCreationRepository.findOneOrFail(id) - const res = await pendingCreationRepository.delete(entity) + const loginPendingTasksAdminRepository = getCustomRepository(LoginPendingTasksAdminRepository) + const entity = await loginPendingTasksAdminRepository.findOneOrFail(id) + const res = await loginPendingTasksAdminRepository.delete(entity) return !!res } @Mutation(() => Boolean) async confirmPendingCreation(@Arg('id') id: number): Promise { - const pendingCreationRepository = getCustomRepository(PendingCreationRepository) - const pendingCreation = await pendingCreationRepository.findOneOrFail(id) + const loginPendingTasksAdminRepository = getCustomRepository(LoginPendingTasksAdminRepository) + const pendingCreation = await loginPendingTasksAdminRepository.findOneOrFail(id) const transactionRepository = getCustomRepository(TransactionRepository) let transaction = new Transaction() @@ -198,7 +198,7 @@ export class AdminResolver { userBalance.modified = new Date() userBalance.recordDate = userBalance.recordDate ? userBalance.recordDate : new Date() await balanceRepository.save(userBalance) - await pendingCreationRepository.delete(pendingCreation) + await loginPendingTasksAdminRepository.delete(pendingCreation) return true } @@ -247,8 +247,8 @@ async function getUserCreations(id: number): Promise { }) .getRawOne() - const pendingCreationRepository = getCustomRepository(PendingCreationRepository) - const pendingAmountMounth = await pendingCreationRepository + const loginPendingTasksAdminRepository = getCustomRepository(LoginPendingTasksAdminRepository) + const pendingAmountMounth = await loginPendingTasksAdminRepository .createQueryBuilder('login_pending_tasks_admin') .select('SUM(login_pending_tasks_admin.amount)', 'sum') .where('login_pending_tasks_admin.userId = :id', { id }) @@ -260,7 +260,7 @@ async function getUserCreations(id: number): Promise { }) .getRawOne() - const pendingAmountLastMounth = await pendingCreationRepository + const pendingAmountLastMounth = await loginPendingTasksAdminRepository .createQueryBuilder('login_pending_tasks_admin') .select('SUM(login_pending_tasks_admin.amount)', 'sum') .where('login_pending_tasks_admin.userId = :id', { id }) @@ -272,7 +272,7 @@ async function getUserCreations(id: number): Promise { }) .getRawOne() - const pendingAmountBeforeLastMounth = await pendingCreationRepository + const pendingAmountBeforeLastMounth = await loginPendingTasksAdminRepository .createQueryBuilder('login_pending_tasks_admin') .select('SUM(login_pending_tasks_admin.amount)', 'sum') .where('login_pending_tasks_admin.userId = :id', { id }) diff --git a/backend/src/typeorm/repository/PendingCreation.ts b/backend/src/typeorm/repository/LoginPendingTasksAdmin.ts similarity index 64% rename from backend/src/typeorm/repository/PendingCreation.ts rename to backend/src/typeorm/repository/LoginPendingTasksAdmin.ts index 8b49e7ecc..b5c55fcd2 100644 --- a/backend/src/typeorm/repository/PendingCreation.ts +++ b/backend/src/typeorm/repository/LoginPendingTasksAdmin.ts @@ -2,4 +2,4 @@ import { EntityRepository, Repository } from 'typeorm' import { LoginPendingTasksAdmin } from '@entity/LoginPendingTasksAdmin' @EntityRepository(LoginPendingTasksAdmin) -export class PendingCreationRepository extends Repository {} +export class LoginPendingTasksAdminRepository extends Repository {} diff --git a/database/Dockerfile b/database/Dockerfile index f2048284b..ec0537ddf 100644 --- a/database/Dockerfile +++ b/database/Dockerfile @@ -1,7 +1,7 @@ ################################################################################## # BASE ########################################################################### ################################################################################## -FROM node:12.19.0-alpine3.10 as base +FROM node:17-alpine as base # ENVs (available in production aswell, can be overwritten by commandline or env file) ## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame @@ -14,8 +14,6 @@ ENV BUILD_VERSION="0.0.0.0" ENV BUILD_COMMIT="0000000" ## SET NODE_ENV ENV NODE_ENV="production" -## App relevant Envs -#ENV PORT="4000" # Labels LABEL org.label-schema.build-date="${BUILD_DATE}" @@ -34,10 +32,6 @@ LABEL maintainer="support@gradido.net" ## install: git #RUN apk --no-cache add git -# Settings -## Expose Container Port -# EXPOSE ${PORT} - ## Workdir RUN mkdir -p ${DOCKER_WORKDIR} WORKDIR ${DOCKER_WORKDIR} @@ -99,7 +93,7 @@ FROM base as production # Copy "binary"-files from build image COPY --from=build ${DOCKER_WORKDIR}/build ./build # We also copy the node_modules express and serve-static for the run script - COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules +COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules # Copy static files # COPY --from=build ${DOCKER_WORKDIR}/public ./public # Copy package.json for script definitions (lock file should not be needed) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 83f38a95f..cdaf46a7a 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -68,9 +68,6 @@ services: image: gradido/database:test_up build: target: test_up - #networks: - # - external-net - # - internal-net environment: - NODE_ENV="development" volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 9352fd162..ae72f3137 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -116,12 +116,10 @@ services: - mariadb networks: - internal-net - #ports: - # - 4000:4000 + - external-net # this is required to fetch the packages environment: # Envs used in Dockerfile # - DOCKER_WORKDIR="/app" - # - PORT=4000 - BUILD_DATE - BUILD_VERSION - BUILD_COMMIT diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 981917c54..25b0eadc5 100755 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,6 +1,6 @@