Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

finish e2e test #6

Merged
merged 1 commit into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,25 @@ export default defineConfig({
/* Configure projects for major browsers */
projects: [
// Setup project
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{ name: 'setup', testMatch: /setup-admin\.setup\.ts/ },
// logout project
{
name: 'logout',
testMatch: /logout\.spec\.ts/,
},
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
storageState: 'tests/.auth/user.json',
storageState: 'tests/.auth/admin.json',
},
dependencies: ['setup'],
},

{
name: 'firefox',
use: {
...devices['Desktop Firefox'],
storageState: 'tests/.auth/user.json',
storageState: 'tests/.auth/admin.json',
},
dependencies: ['setup'],
},
Expand All @@ -47,7 +51,7 @@ export default defineConfig({
name: 'webkit',
use: {
...devices['Desktop Safari'],
storageState: 'tests/.auth/user.json',
storageState: 'tests/.auth/admin.json',
},
dependencies: ['setup'],
},
Expand All @@ -57,6 +61,6 @@ export default defineConfig({
command: 'npm run build && npm run start',
port: 3000,
reuseExistingServer: !process.env.CI,
timeout: 120 * 1000,
timeout: 200 * 1000,
},
})
6 changes: 3 additions & 3 deletions src/actions/orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ export const updateOrderStatus = async (orderId: number, status: string) => {

// 查询用户信息:userId
const {
data: { session },
} = await supabase.auth.getSession()
data: { user },
} = await supabase.auth.getUser()

const userId = session?.user.id
const userId = user?.id

if (!userId) throw new Error('User not found')

Expand Down
12 changes: 9 additions & 3 deletions src/app/admin/categories/category-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ export const CategoryForm = ({
try {
return await imageUploadHandler(formData)
} catch {
toast.error('Image upload failed!')
toast.error('Image upload failed!', {
position: 'top-right',
})
return null
}
}
Expand All @@ -122,13 +124,17 @@ export const CategoryForm = ({
imageUrl,
slug: defaultValues?.slug || slug, // 如果已有 slug,则沿用;否则根据名称生成
})
toast.success('Category updated successfully')
toast.success('Category updated successfully', {
position: 'top-right',
})
} else {
// 创建新分类
const imageUrl = await handleImageUpload()
if (imageUrl) {
await createCategory({ imageUrl, name })
toast.success('Category created successfully')
toast.success('Category created successfully', {
position: 'top-right',
})
}
}
form.reset()
Expand Down
8 changes: 6 additions & 2 deletions src/app/admin/categories/category-table-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,13 @@ export const CategoryTableRow = ({
// 删除分类
try {
await deleteCategory(id)
toast.success('Category deleted successfully')
toast.success('Category deleted successfully', {
position: 'top-right',
})
} catch {
toast.error('Failed to delete category')
toast.error('Failed to delete category', {
position: 'top-right',
})
}

// 刷新页面
Expand Down
4 changes: 3 additions & 1 deletion src/app/admin/products/page-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export const ProductPageComponent: FC<Props> = ({
if (currentProduct?.slug) {
await deleteProduct(currentProduct.slug)
router.refresh()
toast.success('Product deleted successfully')
toast.success('Product deleted successfully', {
position: 'top-right',
})
setIsDeleteModalOpen(false)
setCurrentProduct(null)
}
Expand Down
17 changes: 13 additions & 4 deletions src/app/admin/products/product-dialog-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,17 @@ export const ProductForm = ({

// 检查主图是否成功上传
if (!uploadedHeroImage) {
toast.error('Failed to upload the hero image. Please try again.')
toast.error('Failed to upload the hero image. Please try again.', {
position: 'top-right',
})
return
}

// 检查是否所有产品图片都成功上传
if (uploadedImages.includes(null)) {
toast.error('Failed to upload some product images. Please try again.')
toast.error('Failed to upload some product images. Please try again.', {
position: 'top-right',
})
return
}

Expand Down Expand Up @@ -203,14 +207,19 @@ export const ProductForm = ({
toast.success(
isEditMode
? 'Product updated successfully!'
: 'Product created successfully!'
: 'Product created successfully!',
{
position: 'top-right',
}
)
form.reset() // 重置表单
router.refresh() // 刷新页面
setIsProductModalOpen(false) // 关闭模态框
} catch (error) {
console.error(error)
toast.error('Something went wrong. Please try again.')
toast.error('Something went wrong. Please try again.', {
position: 'top-right',
})
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/app/admin/products/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ export const createOrUpdateProductSchema = z.object({
price: z
.number()
.int({ message: 'Price must be an integer' })
.min(0, { message: 'Price must be a positive integer' }),
.positive({ message: 'Price is required' }),
maxQuantity: z
.number()
.int({ message: 'Max Quantity must be an integer' })
.min(0, { message: 'Max Quantity must be a positive integer' }),
.positive({ message: 'Max Quantity is required' }),
category: z.string().min(1, { message: 'Category is required' }),
heroImage: z
.union([
Expand Down
8 changes: 6 additions & 2 deletions src/app/auth/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,13 @@ export default function Auth() {
} catch (error) {
// 捕获到异常,提示异常中的错误信息
if (error instanceof Error) {
toast.error(error.message)
toast.error(error.message, {
position: 'top-right',
})
} else {
toast.error('An error occurred while authenticating')
toast.error('An error occurred while authenticating', {
position: 'top-right',
})
}
} finally {
setIsAuthenticating(false)
Expand Down
1 change: 1 addition & 0 deletions src/constants/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const ADMIN = 'admin'
export const USER = 'user'
15 changes: 15 additions & 0 deletions tests/.auth/admin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"cookies": [
{
"name": "sb-binfgbgsoetsbeapeoks-auth-token",
"value": "base64-eyJhY2Nlc3NfdG9rZW4iOiJleUpoYkdjaU9pSklVekkxTmlJc0ltdHBaQ0k2SWpsa1RXazVhSFJXWjFsNFRXMXpkSEVpTENKMGVYQWlPaUpLVjFRaWZRLmV5SnBjM01pT2lKb2RIUndjem92TDJKcGJtWm5ZbWR6YjJWMGMySmxZWEJsYjJ0ekxuTjFjR0ZpWVhObExtTnZMMkYxZEdndmRqRWlMQ0p6ZFdJaU9pSmhNREF6WXpBeE55MHlNV1F6TFRReFpqWXRPRE0yTkMwMVpUbGxaV0psWWprek5XUWlMQ0poZFdRaU9pSmhkWFJvWlc1MGFXTmhkR1ZrSWl3aVpYaHdJam94TnpNek5Ea3dOREV6TENKcFlYUWlPakUzTXpNME9EWTRNVE1zSW1WdFlXbHNJam9pZEdWemRFQmhaRzFwYmk1amIyMGlMQ0p3YUc5dVpTSTZJaUlzSW1Gd2NGOXRaWFJoWkdGMFlTSTZleUp3Y205MmFXUmxjaUk2SW1WdFlXbHNJaXdpY0hKdmRtbGtaWEp6SWpwYkltVnRZV2xzSWwxOUxDSjFjMlZ5WDIxbGRHRmtZWFJoSWpwN0ltVnRZV2xzSWpvaWRHVnpkRUJoWkcxcGJpNWpiMjBpTENKbGJXRnBiRjkyWlhKcFptbGxaQ0k2Wm1Gc2MyVXNJbkJvYjI1bFgzWmxjbWxtYVdWa0lqcG1ZV3h6WlN3aWMzVmlJam9pWVRBd00yTXdNVGN0TWpGa015MDBNV1kyTFRnek5qUXROV1U1WldWaVpXSTVNelZrSW4wc0luSnZiR1VpT2lKaGRYUm9aVzUwYVdOaGRHVmtJaXdpWVdGc0lqb2lZV0ZzTVNJc0ltRnRjaUk2VzNzaWJXVjBhRzlrSWpvaWNHRnpjM2R2Y21RaUxDSjBhVzFsYzNSaGJYQWlPakUzTXpNME9EWTRNVE45WFN3aWMyVnpjMmx2Ymw5cFpDSTZJbVZrWW1WaU1XSmxMVGMxTVRBdE5EUmtaUzA0T0RZMUxXSXdOMkV4T0RRMk5ESTVNeUlzSW1selgyRnViMjU1Ylc5MWN5STZabUZzYzJWOS5yNU9hZW8wckRvUk1CeFlZSWZZMFRIaUd0LVVDcFZaTjhmNmpiOW9SOG5nIiwidG9rZW5fdHlwZSI6ImJlYXJlciIsImV4cGlyZXNfaW4iOjM2MDAsImV4cGlyZXNfYXQiOjE3MzM0OTA0MTMsInJlZnJlc2hfdG9rZW4iOiJPb0NPT3lwdGVRdFNWZjFXMHlJZXd3IiwidXNlciI6eyJpZCI6ImEwMDNjMDE3LTIxZDMtNDFmNi04MzY0LTVlOWVlYmViOTM1ZCIsImF1ZCI6ImF1dGhlbnRpY2F0ZWQiLCJyb2xlIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoidGVzdEBhZG1pbi5jb20iLCJlbWFpbF9jb25maXJtZWRfYXQiOiIyMDI0LTEyLTA2VDA4OjUwOjM0LjUzMDU2NVoiLCJwaG9uZSI6IiIsImNvbmZpcm1lZF9hdCI6IjIwMjQtMTItMDZUMDg6NTA6MzQuNTMwNTY1WiIsImxhc3Rfc2lnbl9pbl9hdCI6IjIwMjQtMTItMDZUMTI6MDY6NTMuMzQ0MTc2NzA0WiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7ImVtYWlsIjoidGVzdEBhZG1pbi5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInBob25lX3ZlcmlmaWVkIjpmYWxzZSwic3ViIjoiYTAwM2MwMTctMjFkMy00MWY2LTgzNjQtNWU5ZWViZWI5MzVkIn0sImlkZW50aXRpZXMiOlt7ImlkZW50aXR5X2lkIjoiMGUyZGIzZTYtMWIzMi00MWI4LTlmNWMtMGZhMjdlOTExMWE2IiwiaWQiOiJhMDAzYzAxNy0yMWQzLTQxZjYtODM2NC01ZTllZWJlYjkzNWQiLCJ1c2VyX2lkIjoiYTAwM2MwMTctMjFkMy00MWY2LTgzNjQtNWU5ZWViZWI5MzVkIiwiaWRlbnRpdHlfZGF0YSI6eyJlbWFpbCI6InRlc3RAYWRtaW4uY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwaG9uZV92ZXJpZmllZCI6ZmFsc2UsInN1YiI6ImEwMDNjMDE3LTIxZDMtNDFmNi04MzY0LTVlOWVlYmViOTM1ZCJ9LCJwcm92aWRlciI6ImVtYWlsIiwibGFzdF9zaWduX2luX2F0IjoiMjAyNC0xMi0wNlQwODo1MDozNC41MjQ2NVoiLCJjcmVhdGVkX2F0IjoiMjAyNC0xMi0wNlQwODo1MDozNC41MjQ3MDhaIiwidXBkYXRlZF9hdCI6IjIwMjQtMTItMDZUMDg6NTA6MzQuNTI0NzA4WiIsImVtYWlsIjoidGVzdEBhZG1pbi5jb20ifV0sImNyZWF0ZWRfYXQiOiIyMDI0LTEyLTA2VDA4OjUwOjM0LjQ4OTA2OFoiLCJ1cGRhdGVkX2F0IjoiMjAyNC0xMi0wNlQxMjowNjo1My4zNDcxMDJaIiwiaXNfYW5vbnltb3VzIjpmYWxzZX19",
"domain": "localhost",
"path": "/",
"expires": 1768046813.496824,
"httpOnly": false,
"secure": false,
"sameSite": "Lax"
}
],
"origins": []
}
4 changes: 4 additions & 0 deletions tests/.auth/logout.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"cookies": [],
"origins": []
}
15 changes: 0 additions & 15 deletions tests/.auth/user.json

This file was deleted.

23 changes: 23 additions & 0 deletions tests/e2e/adminLayout.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import test from '../fixtures/pageFixtrue'

test.describe('admin layout common functions', () => {
test('should toggle light theme', async ({ adminLayout }) => {
await adminLayout.navigateToRadomPage()
await adminLayout.toggleLightTheme()
})

test('should toggle dark theme', async ({ adminLayout }) => {
await adminLayout.navigateToRadomPage()
await adminLayout.toggleDarkTheme()
})

test('should toggle system with light theme', async ({ adminLayout }) => {
await adminLayout.navigateToRadomPage()
await adminLayout.toggleSystemWithLightTheme()
})

test('should toggle system with dark theme', async ({ adminLayout }) => {
await adminLayout.navigateToRadomPage()
await adminLayout.toggleSystemWithDarkTheme()
})
})
8 changes: 7 additions & 1 deletion tests/e2e/authPage.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import test from '../fixtures/pageFixtrue'

test.describe('Auth Page', () => {
// 表单验证错误信息验证
test('login with form validation error', async ({ authPage }) => {
await authPage.navigate()
await authPage.loginWithFormValidationError()
})
// 登录成功验证
test('should be able to login', async ({ authPage }) => {
await authPage.navigate()
await authPage.login('[email protected]', '123456')
})

// 登录失败验证
test('should not be able to login with invalid credentials', async ({
authPage,
}) => {
Expand Down
5 changes: 5 additions & 0 deletions tests/e2e/categoriesPage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ test.describe('Categories Page', () => {
await categoriesPage.navigateToProducts()
})

test('form validation error messages', async ({ categoriesPage }) => {
await categoriesPage.navigate()
await categoriesPage.formvalidationErrorMessages()
})

test('add new category', async ({ categoriesPage }) => {
const categoryName = faker.commerce.productName()
await categoriesPage.navigate()
Expand Down
16 changes: 8 additions & 8 deletions tests/e2e/dashboardPage.spec.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import test from '../fixtures/pageFixtrue'

test.describe('Dashboard Page', () => {
test('ordersChartCheck', async ({ dashboardPage }) => {
test('ordersc chart check', async ({ dashboardPage }) => {
await dashboardPage.navigate()
await dashboardPage.ordersChartCheck()
})
test('productDistributionCheck', async ({ dashboardPage }) => {
test('product distribution chart check', async ({ dashboardPage }) => {
await dashboardPage.navigate()
await dashboardPage.productDistributionCheck()
await dashboardPage.productDistributionChartCheck()
})
test('productsPerCategoryChartCheck', async ({ dashboardPage }) => {
test('products per category chart check', async ({ dashboardPage }) => {
await dashboardPage.navigate()
await dashboardPage.productsPerCategoryChartCheck()
})
test('latestUsersChartCheck', async ({ dashboardPage }) => {
test('latestUsers chart check', async ({ dashboardPage }) => {
await dashboardPage.navigate()
await dashboardPage.latestUsersChartCheck()
})
test('navigateToOrdersPage', async ({ dashboardPage }) => {
test('navigate to orders page', async ({ dashboardPage }) => {
await dashboardPage.navigate()
await dashboardPage.navigateToOrdersPage()
})
test('navigateToProductsPage', async ({ dashboardPage }) => {
test('navigate to products page', async ({ dashboardPage }) => {
await dashboardPage.navigate()
await dashboardPage.navigateToProductsPage()
})
test('navigateToCategoriesPage', async ({ dashboardPage }) => {
test('navigate to categories page', async ({ dashboardPage }) => {
await dashboardPage.navigate()
await dashboardPage.navigateToCategoriesPage()
})
Expand Down
25 changes: 25 additions & 0 deletions tests/e2e/logout.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import test from '@playwright/test'
import { AdminLayout } from '../pages/adminLayout'
import { AuthPage } from '../pages/authPage'

test.describe('Logout functionality', () => {
test('Logout', async ({ browser }) => {
const context = await browser.newContext({
storageState: 'tests/.auth/logout.json', // 使用 user 的状态文件
})
const page = await context.newPage()

const authPage = new AuthPage(page)
await authPage.navigate()
await authPage.login('[email protected]', '123456')

// 测试登出逻辑
const adminLayout = new AdminLayout(page)
await adminLayout.navigateToRadomPage() // 跳转到随机页面
await adminLayout.logout()

// 验证已退出(比如应该重定向到登录页)

await context.close()
})
})
11 changes: 8 additions & 3 deletions tests/e2e/productsPage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@ import test from '../fixtures/pageFixtrue'
import { faker } from '@faker-js/faker'

test.describe('Products Page', () => {
test('navigateToDashboard', async ({ productsPage }) => {
test('navigate to dashboard page', async ({ productsPage }) => {
await productsPage.navigate()
await productsPage.navigateToDashboard()
})

test('navigateToOrdersPage', async ({ productsPage }) => {
test('navigate to Orders page', async ({ productsPage }) => {
await productsPage.navigate()
await productsPage.navigateToOrdersPage()
})

test('navigateToCategoriesPage', async ({ productsPage }) => {
test('navigate to categories page', async ({ productsPage }) => {
await productsPage.navigate()
await productsPage.navigateToCategoriesPage()
})

test('form validation error message', async ({ productsPage }) => {
await productsPage.navigate()
await productsPage.formValidationErrorMessages()
})

test('add new product', async ({ productsPage }) => {
// 生成一个随机产品名称
const productTitle = faker.commerce.productName()
Expand Down
Loading
Loading