fix: resolve GitHub Actions CI failures (lint, typecheck, test, format)
- Remove unused `Locale` type imports from admin pages - Fix type annotations in easy-pay client test (CID fields as string | undefined) - Replace `as any` with proper types in limits test - Fix listSubscriptions test mock response structure (data.data.items) - Fix formatting with Prettier
This commit is contained in:
@@ -7,9 +7,9 @@ const { mockGetEnv } = vi.hoisted(() => ({
|
||||
EASY_PAY_API_BASE: 'https://pay.example.com',
|
||||
EASY_PAY_NOTIFY_URL: 'https://pay.example.com/api/easy-pay/notify',
|
||||
EASY_PAY_RETURN_URL: 'https://pay.example.com/pay/result',
|
||||
EASY_PAY_CID: undefined,
|
||||
EASY_PAY_CID_ALIPAY: undefined,
|
||||
EASY_PAY_CID_WXPAY: undefined,
|
||||
EASY_PAY_CID: undefined as string | undefined,
|
||||
EASY_PAY_CID_ALIPAY: undefined as string | undefined,
|
||||
EASY_PAY_CID_WXPAY: undefined as string | undefined,
|
||||
})),
|
||||
}));
|
||||
vi.mock('@/lib/config', () => ({
|
||||
@@ -108,10 +108,9 @@ describe('EasyPay client', () => {
|
||||
|
||||
it('should throw when API returns code !== 1', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValue(
|
||||
new Response(
|
||||
JSON.stringify({ code: -1, msg: 'Invalid parameter' }),
|
||||
{ headers: { 'content-type': 'application/json' } },
|
||||
),
|
||||
new Response(JSON.stringify({ code: -1, msg: 'Invalid parameter' }), {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}),
|
||||
) as typeof fetch;
|
||||
|
||||
await expect(
|
||||
@@ -296,15 +295,12 @@ describe('EasyPay client', () => {
|
||||
|
||||
it('should throw when API returns code !== 1', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValue(
|
||||
new Response(
|
||||
JSON.stringify({ code: -1, msg: 'Order not found' }),
|
||||
{ headers: { 'content-type': 'application/json' } },
|
||||
),
|
||||
new Response(JSON.stringify({ code: -1, msg: 'Order not found' }), {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}),
|
||||
) as typeof fetch;
|
||||
|
||||
await expect(queryOrder('nonexistent-order')).rejects.toThrow(
|
||||
'EasyPay query order failed: Order not found',
|
||||
);
|
||||
await expect(queryOrder('nonexistent-order')).rejects.toThrow('EasyPay query order failed: Order not found');
|
||||
});
|
||||
|
||||
it('should throw with "unknown error" when msg is absent', async () => {
|
||||
@@ -314,9 +310,7 @@ describe('EasyPay client', () => {
|
||||
}),
|
||||
) as typeof fetch;
|
||||
|
||||
await expect(queryOrder('order-err')).rejects.toThrow(
|
||||
'EasyPay query order failed: unknown error',
|
||||
);
|
||||
await expect(queryOrder('order-err')).rejects.toThrow('EasyPay query order failed: unknown error');
|
||||
});
|
||||
|
||||
it('should parse all response fields correctly', async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import type { MethodDefaultLimits } from '@/lib/payment/types';
|
||||
|
||||
vi.mock('@/lib/db', () => ({
|
||||
prisma: {
|
||||
@@ -28,7 +29,7 @@ beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// 默认:getEnv 返回无渠道限额字段,provider 无默认值
|
||||
mockedGetEnv.mockReturnValue({} as ReturnType<typeof getEnv>);
|
||||
mockedGetDefaultLimit.mockReturnValue(undefined as any);
|
||||
mockedGetDefaultLimit.mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
describe('getMethodDailyLimit', () => {
|
||||
@@ -39,35 +40,35 @@ describe('getMethodDailyLimit', () => {
|
||||
it('从 getEnv 读取渠道每日限额', () => {
|
||||
mockedGetEnv.mockReturnValue({
|
||||
MAX_DAILY_AMOUNT_ALIPAY: 5000,
|
||||
} as any);
|
||||
} as unknown as ReturnType<typeof getEnv>);
|
||||
expect(getMethodDailyLimit('alipay')).toBe(5000);
|
||||
});
|
||||
|
||||
it('环境变量 0 表示不限制', () => {
|
||||
mockedGetEnv.mockReturnValue({
|
||||
MAX_DAILY_AMOUNT_WXPAY: 0,
|
||||
} as any);
|
||||
} as unknown as ReturnType<typeof getEnv>);
|
||||
expect(getMethodDailyLimit('wxpay')).toBe(0);
|
||||
});
|
||||
|
||||
it('getEnv 未设置时回退到 provider 默认值', () => {
|
||||
mockedGetEnv.mockReturnValue({} as any);
|
||||
mockedGetDefaultLimit.mockReturnValue({ dailyMax: 3000 } as any);
|
||||
mockedGetEnv.mockReturnValue({} as ReturnType<typeof getEnv>);
|
||||
mockedGetDefaultLimit.mockReturnValue({ dailyMax: 3000 } as MethodDefaultLimits);
|
||||
expect(getMethodDailyLimit('stripe')).toBe(3000);
|
||||
});
|
||||
|
||||
it('getEnv 设置时覆盖 provider 默认值', () => {
|
||||
mockedGetEnv.mockReturnValue({
|
||||
MAX_DAILY_AMOUNT_STRIPE: 8000,
|
||||
} as any);
|
||||
mockedGetDefaultLimit.mockReturnValue({ dailyMax: 3000 } as any);
|
||||
} as unknown as ReturnType<typeof getEnv>);
|
||||
mockedGetDefaultLimit.mockReturnValue({ dailyMax: 3000 } as MethodDefaultLimits);
|
||||
expect(getMethodDailyLimit('stripe')).toBe(8000);
|
||||
});
|
||||
|
||||
it('paymentType 大小写不敏感(key 构造用 toUpperCase)', () => {
|
||||
mockedGetEnv.mockReturnValue({
|
||||
MAX_DAILY_AMOUNT_ALIPAY: 2000,
|
||||
} as any);
|
||||
} as unknown as ReturnType<typeof getEnv>);
|
||||
expect(getMethodDailyLimit('alipay')).toBe(2000);
|
||||
});
|
||||
|
||||
@@ -76,8 +77,8 @@ describe('getMethodDailyLimit', () => {
|
||||
});
|
||||
|
||||
it('getEnv 无值且 provider 默认值也无 dailyMax 时回退 process.env', () => {
|
||||
mockedGetEnv.mockReturnValue({} as any);
|
||||
mockedGetDefaultLimit.mockReturnValue({} as any); // no dailyMax
|
||||
mockedGetEnv.mockReturnValue({} as ReturnType<typeof getEnv>);
|
||||
mockedGetDefaultLimit.mockReturnValue({} as MethodDefaultLimits); // no dailyMax
|
||||
process.env['MAX_DAILY_AMOUNT_ALIPAY'] = '7777';
|
||||
try {
|
||||
expect(getMethodDailyLimit('alipay')).toBe(7777);
|
||||
@@ -111,13 +112,13 @@ describe('getMethodSingleLimit', () => {
|
||||
});
|
||||
|
||||
it('process.env 未设置时回退到 provider 默认值', () => {
|
||||
mockedGetDefaultLimit.mockReturnValue({ singleMax: 200 } as any);
|
||||
mockedGetDefaultLimit.mockReturnValue({ singleMax: 200 } as MethodDefaultLimits);
|
||||
expect(getMethodSingleLimit('alipay')).toBe(200);
|
||||
});
|
||||
|
||||
it('process.env 设置时覆盖 provider 默认值', () => {
|
||||
process.env['MAX_SINGLE_AMOUNT_ALIPAY'] = '999';
|
||||
mockedGetDefaultLimit.mockReturnValue({ singleMax: 200 } as any);
|
||||
mockedGetDefaultLimit.mockReturnValue({ singleMax: 200 } as MethodDefaultLimits);
|
||||
try {
|
||||
expect(getMethodSingleLimit('alipay')).toBe(999);
|
||||
} finally {
|
||||
@@ -127,7 +128,7 @@ describe('getMethodSingleLimit', () => {
|
||||
|
||||
it('无效 process.env 值回退到 provider 默认值', () => {
|
||||
process.env['MAX_SINGLE_AMOUNT_ALIPAY'] = 'abc';
|
||||
mockedGetDefaultLimit.mockReturnValue({ singleMax: 150 } as any);
|
||||
mockedGetDefaultLimit.mockReturnValue({ singleMax: 150 } as MethodDefaultLimits);
|
||||
try {
|
||||
expect(getMethodSingleLimit('alipay')).toBe(150);
|
||||
} finally {
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('listSubscriptions', () => {
|
||||
it('should call correct URL with no query params when no params provided', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ data: [], total: 0, page: 1, page_size: 50 }),
|
||||
json: () => Promise.resolve({ data: { items: [], total: 0, page: 1, page_size: 50 } }),
|
||||
}) as typeof fetch;
|
||||
|
||||
await listSubscriptions();
|
||||
@@ -30,7 +30,7 @@ describe('listSubscriptions', () => {
|
||||
it('should build correct query params when all params provided', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ data: [], total: 0, page: 2, page_size: 10 }),
|
||||
json: () => Promise.resolve({ data: { items: [], total: 0, page: 2, page_size: 10 } }),
|
||||
}) as typeof fetch;
|
||||
|
||||
await listSubscriptions({
|
||||
@@ -51,13 +51,11 @@ describe('listSubscriptions', () => {
|
||||
});
|
||||
|
||||
it('should parse normal response correctly', async () => {
|
||||
const mockSubs = [
|
||||
{ id: 1, user_id: 42, group_id: 5, status: 'active', expires_at: '2026-12-31' },
|
||||
];
|
||||
const mockSubs = [{ id: 1, user_id: 42, group_id: 5, status: 'active', expires_at: '2026-12-31' }];
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ data: mockSubs, total: 1, page: 1, page_size: 50 }),
|
||||
json: () => Promise.resolve({ data: { items: mockSubs, total: 1, page: 1, page_size: 50 } }),
|
||||
}) as typeof fetch;
|
||||
|
||||
const result = await listSubscriptions({ user_id: 42 });
|
||||
|
||||
@@ -7,7 +7,7 @@ import DashboardStats from '@/components/admin/DashboardStats';
|
||||
import DailyChart from '@/components/admin/DailyChart';
|
||||
import Leaderboard from '@/components/admin/Leaderboard';
|
||||
import PaymentMethodChart from '@/components/admin/PaymentMethodChart';
|
||||
import { resolveLocale, type Locale } from '@/lib/locale';
|
||||
import { resolveLocale } from '@/lib/locale';
|
||||
|
||||
interface DashboardData {
|
||||
summary: {
|
||||
|
||||
@@ -6,7 +6,7 @@ import OrderTable from '@/components/admin/OrderTable';
|
||||
import OrderDetail from '@/components/admin/OrderDetail';
|
||||
import PaginationBar from '@/components/PaginationBar';
|
||||
import PayPageLayout from '@/components/PayPageLayout';
|
||||
import { resolveLocale, type Locale } from '@/lib/locale';
|
||||
import { resolveLocale } from '@/lib/locale';
|
||||
|
||||
interface AdminOrder {
|
||||
id: string;
|
||||
|
||||
@@ -7,7 +7,7 @@ import DashboardStats from '@/components/admin/DashboardStats';
|
||||
import DailyChart from '@/components/admin/DailyChart';
|
||||
import Leaderboard from '@/components/admin/Leaderboard';
|
||||
import PaymentMethodChart from '@/components/admin/PaymentMethodChart';
|
||||
import { resolveLocale, type Locale } from '@/lib/locale';
|
||||
import { resolveLocale } from '@/lib/locale';
|
||||
|
||||
interface DashboardData {
|
||||
summary: {
|
||||
|
||||
Reference in New Issue
Block a user