From b6aeb5e0e9d09129fae14ef56de1c635ae0b12bc Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 8 Apr 2022 15:53:21 +0200 Subject: [PATCH 01/16] composables refactor and their unit tests --- src/composables/__tests__/useRole.spec.js | 61 +++++++++ src/composables/__tests__/useSession.spec.js | 134 +++++++++++++++++++ src/composables/useRole.js | 8 +- src/composables/useSession.js | 9 +- 4 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 src/composables/__tests__/useRole.spec.js create mode 100644 src/composables/__tests__/useSession.spec.js diff --git a/src/composables/__tests__/useRole.spec.js b/src/composables/__tests__/useRole.spec.js new file mode 100644 index 000000000..bf2129107 --- /dev/null +++ b/src/composables/__tests__/useRole.spec.js @@ -0,0 +1,61 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { axios, flushPromises } from 'app/tests/jest/jestHelpers'; +import { useRole } from '../useRole'; +const role = useRole(); + +describe('useRole', () => { + + describe('fetch', () => { + it('should call setUser and setRoles of the state with the expected data', async () => { + const rolesData = [ + { + role: { + name: 'salesPerson' + } + }, + { + role: { + name: 'admin' + } + } + ]; + const expectedUser = { id: 1 } + const expectedRoles = ['salesPerson', 'admin'] + jest.spyOn(axios, 'get').mockResolvedValue({ + data: { roles: rolesData, user: expectedUser } + }); + + jest.spyOn(role.state, 'setUser'); + jest.spyOn(role.state, 'setRoles'); + + role.fetch(); + + await flushPromises(); + + expect(role.state.setUser).toHaveBeenCalledWith(expectedUser); + expect(role.state.setRoles).toHaveBeenCalledWith(expectedRoles); + + role.state.setRoles([]) + }); + }); + describe('hasAny', () => { + it('should return true if a role matched', async () => { + role.state.setRoles(['admin']) + const hasRole = role.hasAny(['admin']); + + await flushPromises(); + + expect(hasRole).toBe(true); + + role.state.setRoles([]) + }); + + it('should return false if no roles matched', async () => { + const hasRole = role.hasAny(['admin']); + + await flushPromises(); + + expect(hasRole).toBe(false); + }); + }); +}); \ No newline at end of file diff --git a/src/composables/__tests__/useSession.spec.js b/src/composables/__tests__/useSession.spec.js new file mode 100644 index 000000000..52b31f59c --- /dev/null +++ b/src/composables/__tests__/useSession.spec.js @@ -0,0 +1,134 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { useSession } from '../useSession'; +import { useState } from '../useState'; +import { axios } from 'app/tests/jest/jestHelpers'; + +const session = useSession(); +const state = useState(); + +describe('session', () => { + describe('getToken / setToken', () => { + it('should return an empty string if no token is found in local or session storage', async () => { + const expectedToken = '' + + const token = session.getToken(); + + expect(token).toEqual(expectedToken); + }); + + it('should return the token stored in local or session storage', async () => { + const expectedToken = 'myToken' + const data = { + token: expectedToken, + keepLogin: false + } + session.setToken(data); + + const token = session.getToken(); + + expect(token).toEqual(expectedToken); + }); + }); + + describe('destroy', () => { + it('should remove the token from the local storage and set a blank user', async () => { + const previousUser = { + id: 999, + name: `T'Challa`, + nickname: 'Black Panther', + } + const expectedUser = { + id: 0, + name: '', + nickname: '', + } + let user = state.getUser(); + + localStorage.setItem('token', 'tokenToBeGone'); + state.setUser(previousUser) + + expect(localStorage.getItem('token')).toEqual('tokenToBeGone'); + expect(user.value).toEqual(previousUser); + + + session.destroy(); + + user = state.getUser(); + expect(localStorage.getItem('token')).toBeNull(); + expect(user.value).toEqual(expectedUser); + }); + }); + + describe('login', () => { + it('should fetch the user roles and then set token in the sessionStorage', async () => { + const rolesData = [ + { + role: { + name: 'salesPerson' + } + }, + { + role: { + name: 'admin' + } + } + ]; + const expectedUser = { id: 1 } + const expectedRoles = ['salesPerson', 'admin'] + jest.spyOn(axios, 'get').mockResolvedValue({ + data: { roles: rolesData, user: expectedUser } + }); + + const expectedToken = 'mySessionToken' + const keepLogin = false + + await session.login(expectedToken, keepLogin); + + const roles = state.getRoles(); + const localToken = localStorage.getItem('token'); + const sessionToken = sessionStorage.getItem('token'); + + expect(roles.value).toEqual(expectedRoles); + expect(localToken).toBeNull(); + expect(sessionToken).toEqual(expectedToken); + + session.destroy() // this clears token and user for any other test + }); + + it('should fetch the user roles and then set token in the localStorage', async () => { + + const rolesData = [ + { + role: { + name: 'salesPerson' + } + }, + { + role: { + name: 'admin' + } + } + ]; + const expectedUser = { id: 1 } + const expectedRoles = ['salesPerson', 'admin'] + jest.spyOn(axios, 'get').mockResolvedValue({ + data: { roles: rolesData, user: expectedUser } + }); + + const expectedToken = 'myLocalToken' + const keepLogin = true + + await session.login(expectedToken, keepLogin); + + const roles = state.getRoles(); + const localToken = localStorage.getItem('token'); + const sessionToken = sessionStorage.getItem('token'); + + expect(roles.value).toEqual(expectedRoles); + expect(localToken).toEqual(expectedToken); + expect(sessionToken).toBeNull(); + + session.destroy() // this clears token and user for any other test + }); + }); +}); diff --git a/src/composables/useRole.js b/src/composables/useRole.js index 664dc2f66..a34e81a81 100644 --- a/src/composables/useRole.js +++ b/src/composables/useRole.js @@ -1,9 +1,9 @@ import { useState } from './useState'; import axios from 'axios'; -const state = useState(); - export function useRole() { + const state = useState(); + async function fetch() { const { data } = await axios.get('/api/accounts/acl'); const roles = data.roles.map(userRoles => userRoles.role.name); @@ -25,6 +25,6 @@ export function useRole() { return { fetch, hasAny, + state }; -} - +} \ No newline at end of file diff --git a/src/composables/useSession.js b/src/composables/useSession.js index e52829ba7..d897b0dd7 100644 --- a/src/composables/useSession.js +++ b/src/composables/useSession.js @@ -18,14 +18,17 @@ export function useSession() { } function destroy() { - localStorage.removeItem('token'); - sessionStorage.getItem('token'); + if (localStorage.getItem('token')) + localStorage.removeItem('token') + + if (sessionStorage.getItem('token')) + sessionStorage.removeItem('token'); const { setUser } = useState(); setUser({ id: 0, - username: '', + name: '', nickname: '', }); } From 78baa306b07dd531a3c01a1d534ddd3fbaf2aa8f Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 12 Apr 2022 14:53:43 +0200 Subject: [PATCH 02/16] Make use of slot --- src/layouts/MainLayout.vue | 36 ++++++++------------ src/pages/Customer/Card/CustomerCard.vue | 18 +++++----- src/pages/Customer/CustomerLayout.vue | 15 +++++++++ src/pages/Dashboard/DashboardLayout.vue | 17 ++++++++++ src/router/routes.js | 42 ++++++++++++++++++++++-- 5 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 src/pages/Dashboard/DashboardLayout.vue diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 480617886..c26912fa4 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -1,36 +1,26 @@ - + diff --git a/src/pages/Customer/Card/CustomerCard.vue b/src/pages/Customer/Card/CustomerCard.vue index 152c8cfdc..02db481f6 100644 --- a/src/pages/Customer/Card/CustomerCard.vue +++ b/src/pages/Customer/Card/CustomerCard.vue @@ -1,15 +1,15 @@ + + diff --git a/src/pages/Customer/CustomerLayout.vue b/src/pages/Customer/CustomerLayout.vue index 2785996d8..755652635 100644 --- a/src/pages/Customer/CustomerLayout.vue +++ b/src/pages/Customer/CustomerLayout.vue @@ -1,3 +1,18 @@ + diff --git a/src/pages/Dashboard/DashboardLayout.vue b/src/pages/Dashboard/DashboardLayout.vue new file mode 100644 index 000000000..917b15059 --- /dev/null +++ b/src/pages/Dashboard/DashboardLayout.vue @@ -0,0 +1,17 @@ + + diff --git a/src/router/routes.js b/src/router/routes.js index d4b63df1d..168a907e2 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -1,4 +1,4 @@ -import customer from './modules/customer'; +//import customer from './modules/customer'; import ticket from './modules/ticket'; const routes = [ @@ -18,7 +18,43 @@ const routes = [ path: '/dashboard', name: 'Dashboard', meta: { title: 'dashboard', icon: 'dashboard' }, - component: () => import('../pages/Dashboard/Dashboard.vue'), + component: () => import('../pages/Dashboard/DashboardLayout.vue'), + }, + { + path: '/customer', + name: 'Customer', + meta: { + title: 'customers', + icon: 'vn:client', + roles: ['salesPerson'], + }, + component: () => import('src/pages/Customer/CustomerLayout.vue'), + redirect: { name: 'CustomerList' }, + children: [ + { + path: 'list', + name: 'CustomerList', + meta: { + title: 'list' + }, + component: () => import('src/pages/Customer/CustomerList.vue'), + }, + { + path: ':id', + component: () => import('src/pages/Customer/Card/CustomerCard.vue'), + redirect: { name: 'CustomerBasicData' }, + children: [ + { + path: 'basic-data', + name: 'CustomerBasicData', + meta: { + title: 'basicData' + }, + component: () => import('src/pages/Customer/Card/CustomerBasicData.vue'), + } + ] + }, + ] }, /* { path: '/:pathMatch(.*)*', @@ -26,7 +62,7 @@ const routes = [ component: () => import('../pages/NotFound.vue'), }, */ // Module routes - customer, + //customer, ticket, ], }, From 9123ce9f5f45974a1904c78fd6c584e4a1ce6007 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 19 Apr 2022 11:03:37 +0200 Subject: [PATCH 03/16] Changes --- src/layouts/MainLayout.vue | 7 +------ src/pages/Customer/CustomerLayout.vue | 15 --------------- src/pages/Customer/CustomerList.vue | 22 ++++++++-------------- src/pages/Customer/CustomerMain.vue | 21 +++++++++++++++++++++ src/router/routes.js | 22 +++++++++++++++------- 5 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 src/pages/Customer/CustomerMain.vue diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index c26912fa4..4d43d79b8 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -13,12 +13,7 @@ import Navbar from 'src/components/Navbar.vue'; diff --git a/src/pages/Customer/CustomerLayout.vue b/src/pages/Customer/CustomerLayout.vue index 755652635..2785996d8 100644 --- a/src/pages/Customer/CustomerLayout.vue +++ b/src/pages/Customer/CustomerLayout.vue @@ -1,18 +1,3 @@ - diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue index 47960b007..22dc02b7b 100644 --- a/src/pages/Customer/CustomerList.vue +++ b/src/pages/Customer/CustomerList.vue @@ -25,9 +25,14 @@ const customers = [ function navigate(id) { router.push({ path: `/customer/${id}` }); } + +// function onToggleDrawer() { +// drawer.value = !drawer.value; +// }