diff --git a/cypress/e2e/auth.cy.ts b/cypress/e2e/auth.cy.ts
index 58d9823..9adc2e3 100644
--- a/cypress/e2e/auth.cy.ts
+++ b/cypress/e2e/auth.cy.ts
@@ -22,7 +22,7 @@ describe('Auth', () => {
it('should display error when submit an invalid form (password not match)', () => {
cy.intercept('POST', /users\/login/, {
- statusCode: 422,
+ statusCode: 403,
body: { errors: { 'email or password': ['is invalid'] } },
})
cy.visit(ROUTES.LOGIN)
diff --git a/cypress/e2e/favorite.cy.ts b/cypress/e2e/favorite.cy.ts
index 0d1cc14..f53c120 100644
--- a/cypress/e2e/favorite.cy.ts
+++ b/cypress/e2e/favorite.cy.ts
@@ -10,6 +10,10 @@ describe('Favorite', () => {
cy.intercept('POST', /articles\/\S+\/favorite$/, { statusCode: 401, body: {} }).as('favoriteArticle')
cy.visit(ROUTES.HOME)
+ Cypress.on('uncaught:exception', (err) => {
+ expect(err.message).to.contain('Need to login')
+ return false
+ })
cy.get('i.ion-heart:first').click()
cy.url().should('contain', 'login')
diff --git a/package.json b/package.json
index 58cd48c..32aef4e 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"test:unit": "cypress open --component",
"test:unit:ci": "cypress run --component --quiet --reporter spec",
"test:e2e": "npm run build && concurrently -rk -s first \"npm run serve\" \"cypress open --e2e -c baseUrl=http://localhost:4137\"",
+ "test:e2e:local": "cypress open --e2e -c baseUrl=http://localhost:5173",
"test:e2e:ci": "npm run build && concurrently -rk -s first \"npm run serve\" \"cypress run --e2e -c baseUrl=http://localhost:4137\"",
"test:e2e:prod": "cypress run --e2e -c baseUrl=https://vue3-realworld-example-app-mutoe.vercel.app",
"test": "npm run test:unit:ci && npm run test:e2e:ci",
diff --git a/src/pages/Login.vue b/src/pages/Login.vue
index 49566ec..87e1a02 100644
--- a/src/pages/Login.vue
+++ b/src/pages/Login.vue
@@ -62,7 +62,7 @@
diff --git a/src/services/index.ts b/src/services/index.ts
index cfb128f..aae23e6 100644
--- a/src/services/index.ts
+++ b/src/services/index.ts
@@ -1,3 +1,4 @@
+import type { GenericErrorModel, HttpResponse } from 'src/services/api'
import { Api } from 'src/services/api'
import { CONFIG } from 'src/config'
@@ -12,3 +13,7 @@ export function pageToOffset (page: number = 1, localLimit = limit): {limit: num
const offset = (page - 1) * localLimit
return { limit: localLimit, offset }
}
+
+export function isFetchError (e: unknown): e is HttpResponse {
+ return e instanceof Object && 'error' in e
+}
diff --git a/src/utils/use-async.ts b/src/utils/use-async.ts
index 455a5d5..44fa1ce 100644
--- a/src/utils/use-async.ts
+++ b/src/utils/use-async.ts
@@ -1,3 +1,5 @@
+import { routerPush } from 'src/router'
+import { isFetchError } from 'src/services'
import type { Ref } from 'vue'
import { ref } from 'vue'
@@ -11,9 +13,20 @@ export default function useAsync unknown> (fn:
const run: UseAsync['run'] = async (...args) => {
active.value = true
- const result = await fn(...args)
- active.value = false
- return result as ReturnType
+ try {
+ const result = await fn(...args)
+ return result as ReturnType
+ } catch (e) {
+ if (isFetchError(e)) {
+ if (e.status === 401) {
+ await routerPush('login')
+ throw new Error('Need to login first')
+ }
+ }
+ throw e
+ } finally {
+ active.value = false
+ }
}
return { active, run }