diff --git a/cypress/e2e/auth.cy.ts b/cypress/e2e/auth.cy.ts index ff73c87..0f426f2 100644 --- a/cypress/e2e/auth.cy.ts +++ b/cypress/e2e/auth.cy.ts @@ -1,6 +1,12 @@ import { ROUTES } from './constant' describe('Auth', () => { + beforeEach(() => { + cy.intercept('GET', /users/, { fixture: 'user.json' }).as('getUser') + cy.intercept('GET', /tags/, { fixture: 'tags.json' }).as('getTags') + cy.intercept('GET', /articles/, { fixture: 'articles.json' }).as('getArticles') + }) + describe('Login and logout', () => { it('should login success when submit a valid login form', () => { cy.login() @@ -51,10 +57,22 @@ describe('Auth', () => { it('should not allow visiting login page when the user is logged in', () => { cy.login() - cy.visit('/#/login') + cy.visit(ROUTES.LOGIN) cy.url().should('match', /\/#\/$/) }) + + it('should has credential header after login success', () => { + cy.login() + + cy.visit(ROUTES.SETTINGS) + cy.intercept('PUT', /user/).as('updateSettingsRequest') + + cy.findByRole('textbox', { name: 'Username' }).type('foo') + cy.findByRole('button', { name: 'Update Settings' }).click() + + cy.wait('@updateSettingsRequest').its('request.headers').should('have.property', 'authorization') + }) }) describe('Register', () => { diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index aea6371..3a55459 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -54,7 +54,7 @@
token ? { headers: { authorization: `Bearer ${token}` } } : {}, + securityWorker: token => token ? { headers: { Authorization: `Bearer ${token}` } } : {}, baseApiParams: { headers: { 'content-type': ContentType.Json, diff --git a/src/store/user.ts b/src/store/user.ts index 3f35dcb..6d34e3d 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -13,14 +13,14 @@ export const useUserStore = defineStore('user', () => { const isAuthorized = computed(() => !!user.value) function updateUser (userData?: User | null) { - if (userData === undefined || userData === null) { - userStorage.remove() - api.setSecurityData(null) - user.value = null - } else { + if (userData) { userStorage.set(userData) api.setSecurityData(userData.token) user.value = userData + } else { + userStorage.remove() + api.setSecurityData(null) + user.value = null } } diff --git a/src/utils/use-async.ts b/src/utils/use-async.ts index 2f4809d..923d8f2 100644 --- a/src/utils/use-async.ts +++ b/src/utils/use-async.ts @@ -2,6 +2,7 @@ import type { Ref } from 'vue' import { ref } from 'vue' import { routerPush } from 'src/router' import { isFetchError } from 'src/services' +import { userStorage } from 'src/store/user.ts' interface UseAsync unknown> { active: Ref @@ -18,8 +19,9 @@ export default function useAsync unknown> (fn: return result as ReturnType } catch (error) { if (isFetchError(error) && error.status === 401) { + userStorage.remove() await routerPush('login') - throw new Error('Need to login first') + throw new Error('Unauthorized or token expired') } throw error } finally {