diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d5b02cc76..24aec5fff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -380,7 +380,7 @@ jobs: ########################################################################## - name: frontend | Unit tests run: | - docker run -v ~/coverage:/app/coverage --rm gradido/frontend:test yarn run test + docker run --env NODE_ENV=test -v ~/coverage:/app/coverage --rm gradido/frontend:test yarn run test cp -r ~/coverage ./coverage ########################################################################## # COVERAGE REPORT FRONTEND ############################################### @@ -399,7 +399,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 86 + min_coverage: 90 token: ${{ github.token }} ############################################################################## @@ -441,7 +441,7 @@ jobs: report_name: Coverage Admin Interface type: lcov result_path: ./coverage/lcov.info - min_coverage: 60 + min_coverage: 76 token: ${{ github.token }} ############################################################################## diff --git a/admin/src/main.js b/admin/src/main.js index 6a59f1cc7..2743e0f9a 100644 --- a/admin/src/main.js +++ b/admin/src/main.js @@ -11,11 +11,8 @@ import addNavigationGuards from './router/guards' import i18n from './i18n' -import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' import VueApollo from 'vue-apollo' -import CONFIG from './config' - import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' @@ -23,37 +20,7 @@ import 'bootstrap-vue/dist/bootstrap-vue.css' import moment from 'vue-moment' import Toasted from 'vue-toasted' -const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) - -const authLink = new ApolloLink((operation, forward) => { - const token = store.state.token - - operation.setContext({ - headers: { - Authorization: token && token.length > 0 ? `Bearer ${token}` : '', - }, - }) - return forward(operation).map((response) => { - if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { - response.errors[0].message = i18n.t('error.session-expired') - store.dispatch('logout', null) - if (router.currentRoute.path !== '/logout') router.push('/logout') - return response - } - const newToken = operation.getContext().response.headers.get('token') - if (newToken) store.commit('token', newToken) - return response - }) -}) - -const apolloClient = new ApolloClient({ - link: authLink.concat(httpLink), - cache: new InMemoryCache(), -}) - -const apolloProvider = new VueApollo({ - defaultClient: apolloClient, -}) +import { apolloProvider } from './plugins/apolloProvider' Vue.use(BootstrapVue) diff --git a/admin/src/main.test.js b/admin/src/main.test.js index 747ef5d2a..06efa8b65 100644 --- a/admin/src/main.test.js +++ b/admin/src/main.test.js @@ -101,77 +101,4 @@ describe('main', () => { }), ) }) - - describe('ApolloLink', () => { - // mock store - const storeDispatchMock = jest.fn() - store.state = { - token: 'some-token', - } - store.dispatch = storeDispatchMock - - // mock i18n.t - i18n.t = jest.fn((t) => t) - - // mock apllo response - const responseMock = { - errors: [{ message: '403.13 - Client certificate revoked' }], - } - - // mock router - const routerPushMock = jest.fn() - router.push = routerPushMock - router.currentRoute = { - path: '/overview', - } - - // mock context - const setContextMock = jest.fn() - const getContextMock = jest.fn(() => { - return { - response: { - headers: { - get: jest.fn(), - }, - }, - } - }) - - // mock apollo link function params - const operationMock = { - setContext: setContextMock, - getContext: getContextMock, - } - - const forwardMock = jest.fn(() => { - return [responseMock] - }) - - // get apollo link callback - const middleware = ApolloLink.mock.calls[0][0] - - beforeEach(() => { - jest.clearAllMocks() - // run the callback with mocked params - middleware(operationMock, forwardMock) - }) - - it('sets authorization header', () => { - expect(setContextMock).toBeCalledWith({ - headers: { - Authorization: 'Bearer some-token', - }, - }) - }) - - describe('apollo response is 403.13', () => { - it.skip('dispatches logout', () => { - expect(storeDispatchMock).toBeCalledWith('logout', null) - }) - - it.skip('redirects to logout', () => { - expect(routerPushMock).toBeCalledWith('/logout') - }) - }) - }) }) 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/admin/src/plugins/apolloProvider.js b/admin/src/plugins/apolloProvider.js new file mode 100644 index 000000000..0e342b8fc --- /dev/null +++ b/admin/src/plugins/apolloProvider.js @@ -0,0 +1,37 @@ +import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' +import VueApollo from 'vue-apollo' +import CONFIG from '../config' +import store from '../store/store' +import router from '../router/router' +import i18n from '../i18n' + +const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) + +const authLink = new ApolloLink((operation, forward) => { + const token = store.state.token + operation.setContext({ + headers: { + Authorization: token && token.length > 0 ? `Bearer ${token}` : '', + }, + }) + return forward(operation).map((response) => { + if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { + response.errors[0].message = i18n.t('error.session-expired') + store.dispatch('logout', null) + if (router.currentRoute.path !== '/logout') router.push('/logout') + return response + } + const newToken = operation.getContext().response.headers.get('token') + if (newToken) store.commit('token', newToken) + return response + }) +}) + +const apolloClient = new ApolloClient({ + link: authLink.concat(httpLink), + cache: new InMemoryCache(), +}) + +export const apolloProvider = new VueApollo({ + defaultClient: apolloClient, +}) diff --git a/admin/src/plugins/apolloProvider.test.js b/admin/src/plugins/apolloProvider.test.js new file mode 100644 index 000000000..e5f394e96 --- /dev/null +++ b/admin/src/plugins/apolloProvider.test.js @@ -0,0 +1,178 @@ +import { ApolloClient, ApolloLink, HttpLink } from 'apollo-boost' +import './apolloProvider' +import CONFIG from '../config' + +import VueApollo from 'vue-apollo' +import store from '../store/store' +import router from '../router/router' +import i18n from '../i18n' + +jest.mock('vue-apollo') +jest.mock('../store/store') +jest.mock('../router/router') +jest.mock('../i18n') + +jest.mock('apollo-boost', () => { + return { + __esModule: true, + ApolloClient: jest.fn(), + ApolloLink: jest.fn(() => { + return { concat: jest.fn() } + }), + InMemoryCache: jest.fn(), + HttpLink: jest.fn(), + } +}) + +describe('apolloProvider', () => { + it('calls the HttpLink', () => { + expect(HttpLink).toBeCalledWith({ uri: CONFIG.GRAPHQL_URI }) + }) + + it('calls the ApolloLink', () => { + expect(ApolloLink).toBeCalled() + }) + + it('calls the ApolloClient', () => { + expect(ApolloClient).toBeCalled() + }) + + it('calls the VueApollo', () => { + expect(VueApollo).toBeCalled() + }) + + describe('ApolloLink', () => { + // mock store + const storeDispatchMock = jest.fn() + const storeCommitMock = jest.fn() + store.state = { + token: 'some-token', + } + store.dispatch = storeDispatchMock + store.commit = storeCommitMock + + // mock i18n.t + i18n.t = jest.fn((t) => t) + + // mock apllo response + const responseMock = { + errors: [{ message: '403.13 - Client certificate revoked' }], + } + + // mock router + const routerPushMock = jest.fn() + router.push = routerPushMock + router.currentRoute = { + path: '/overview', + } + + // mock context + const setContextMock = jest.fn() + const getContextMock = jest.fn(() => { + return { + response: { + headers: { + get: jest.fn(() => 'another-token'), + }, + }, + } + }) + + // mock apollo link function params + const operationMock = { + setContext: setContextMock, + getContext: getContextMock, + } + + const forwardMock = jest.fn(() => { + return [responseMock] + }) + + // get apollo link callback + const middleware = ApolloLink.mock.calls[0][0] + + describe('with token in store', () => { + it('sets authorization header with token', () => { + // run the apollo link callback with mocked params + middleware(operationMock, forwardMock) + expect(setContextMock).toBeCalledWith({ + headers: { + Authorization: 'Bearer some-token', + }, + }) + }) + }) + + describe('without token in store', () => { + beforeEach(() => { + store.state.token = null + }) + + it('sets authorization header empty', () => { + middleware(operationMock, forwardMock) + expect(setContextMock).toBeCalledWith({ + headers: { + Authorization: '', + }, + }) + }) + }) + + describe('apollo response is 403.13', () => { + beforeEach(() => { + // run the apollo link callback with mocked params + middleware(operationMock, forwardMock) + }) + + it('dispatches logout', () => { + expect(storeDispatchMock).toBeCalledWith('logout', null) + }) + + describe('current route is not logout', () => { + it('redirects to logout', () => { + expect(routerPushMock).toBeCalledWith('/logout') + }) + }) + + describe('current route is logout', () => { + beforeEach(() => { + jest.clearAllMocks() + router.currentRoute.path = '/logout' + }) + + it('does not redirect to logout', () => { + expect(routerPushMock).not.toBeCalled() + }) + }) + }) + + describe('apollo response is with new token', () => { + beforeEach(() => { + delete responseMock.errors + middleware(operationMock, forwardMock) + }) + + it('commits new token to store', () => { + expect(storeCommitMock).toBeCalledWith('token', 'another-token') + }) + }) + + describe('apollo response is without new token', () => { + beforeEach(() => { + jest.clearAllMocks() + getContextMock.mockReturnValue({ + response: { + headers: { + get: jest.fn(() => null), + }, + }, + }) + middleware(operationMock, forwardMock) + }) + + it('does not commit token to store', () => { + expect(storeCommitMock).not.toBeCalled() + }) + }) + }) +}) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 3c03227d5..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,9 +81,9 @@ 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(updatedCreation.amount.toString()) + result.amount = parseInt(amount.toString()) result.memo = updatedCreation.memo result.date = updatedCreation.date result.moderator = updatedCreation.moderator @@ -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() @@ -176,7 +176,7 @@ export class AdminResolver { } else { newBalance = lastUserTransaction.balance } - newBalance = Number(newBalance) + Number(parseInt(pendingCreation.amount.toString()) / 10000) + newBalance = Number(newBalance) + Number(parseInt(pendingCreation.amount.toString())) const newUserTransaction = new UserTransaction() newUserTransaction.userId = pendingCreation.userId @@ -194,11 +194,11 @@ export class AdminResolver { if (!userBalance) userBalance = balanceRepository.create() userBalance.userId = pendingCreation.userId - userBalance.amount = Number(newBalance * 10000) + userBalance.amount = Number(newBalance) 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/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 58eb695ea..b2f4b4db5 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -428,7 +428,7 @@ async function addUserTransaction( if (lastUserTransaction) { newBalance += Number( await calculateDecay( - Number(lastUserTransaction.balance * 10000), + Number(lastUserTransaction.balance), lastUserTransaction.balanceDate, transaction.received, ).catch(() => { 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/babel.config.js b/frontend/babel.config.js index 5907ab074..fab7b82b8 100644 --- a/frontend/babel.config.js +++ b/frontend/babel.config.js @@ -1,11 +1,22 @@ -module.exports = { - presets: ['@babel/preset-env'], - plugins: [ +module.exports = function (api) { + api.cache(true) + + const presets = ['@babel/preset-env'] + const plugins = [ [ 'component', { styleLibraryName: 'theme-chalk', }, ], - ], + ] + + if (process.env.NODE_ENV === 'test') { + plugins.push('transform-require-context') + } + + return { + presets, + plugins, + } } diff --git a/frontend/jest.config.js b/frontend/jest.config.js index 774aa6bf9..5caae815c 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -22,4 +22,5 @@ module.exports = { testMatch: ['**/?(*.)+(spec|test).js?(x)'], // snapshotSerializers: ['jest-serializer-vue'], transformIgnorePatterns: ['/node_modules/(?!vee-validate/dist/rules)'], + testEnvironment: 'jest-environment-jsdom-sixteen', } diff --git a/frontend/package.json b/frontend/package.json index e50c5fe89..cfa7be87c 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,8 +22,7 @@ "apollo-boost": "^0.4.9", "axios": "^0.21.1", "babel-core": "^7.0.0-bridge.0", - "babel-jest": "^26.6.3", - "babel-plugin-require-context-hook": "^1.0.0", + "babel-jest": "^27.3.1", "babel-preset-vue": "^2.0.2", "bootstrap": "4.3.1", "bootstrap-vue": "^2.5.0", @@ -51,6 +50,7 @@ "identity-obj-proxy": "^3.0.0", "jest": "^26.6.3", "jest-canvas-mock": "^2.3.1", + "jest-environment-jsdom-sixteen": "^2.0.0", "nouislider": "^12.1.0", "particles-bg-vue": "1.2.3", "perfect-scrollbar": "^1.3.0", @@ -88,6 +88,7 @@ "@vue/eslint-config-prettier": "^4.0.1", "babel-eslint": "^10.1.0", "babel-plugin-component": "^1.1.0", + "babel-plugin-transform-require-context": "^0.1.1", "dotenv-webpack": "^7.0.3", "node-sass": "^6.0.1", "sass-loader": "^10", 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 @@