fix: 改进评论获取接口的slug规范化处理
修复当post_slug参数为根路径或包含查询参数/锚点时,slug列表生成逻辑不正确的问题。现在会先去除查询参数和锚点,然后正确处理根路径和带斜杠的变体。 新增单元测试验证各种slug格式的规范化行为,包括相对路径、完整URL和根路径。
This commit is contained in:
84
cwd-api/src/api/public/getComments.spec.ts
Normal file
84
cwd-api/src/api/public/getComments.spec.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { getComments } from './getComments'
|
||||
|
||||
describe('getComments slug normalization', () => {
|
||||
const createMockContext = (slug: string) => {
|
||||
const bindMock = vi.fn().mockReturnValue({
|
||||
all: vi.fn().mockResolvedValue({ results: [] }),
|
||||
first: vi.fn().mockResolvedValue(null)
|
||||
})
|
||||
|
||||
const prepareMock = vi.fn().mockReturnValue({
|
||||
bind: bindMock
|
||||
})
|
||||
|
||||
const c = {
|
||||
req: {
|
||||
query: (key: string) => {
|
||||
if (key === 'post_slug') return slug
|
||||
return undefined
|
||||
}
|
||||
},
|
||||
env: {
|
||||
CWD_DB: {
|
||||
prepare: prepareMock
|
||||
}
|
||||
},
|
||||
json: vi.fn(),
|
||||
executionCtx: {
|
||||
waitUntil: vi.fn()
|
||||
}
|
||||
} as any
|
||||
|
||||
return { c, prepareMock, bindMock }
|
||||
}
|
||||
|
||||
it('should query both variants for relative path without trailing slash', async () => {
|
||||
const { c, bindMock } = createMockContext('/1.html')
|
||||
|
||||
await getComments(c)
|
||||
|
||||
// We expect the bind to be called with arguments including both variants
|
||||
// The first call to bind should be for the main query (or we check all calls)
|
||||
const calls = bindMock.mock.calls
|
||||
const allArgs = calls.flat()
|
||||
|
||||
expect(allArgs).toContain('/1.html')
|
||||
expect(allArgs).toContain('/1.html/')
|
||||
})
|
||||
|
||||
it('should query both variants for relative path with trailing slash', async () => {
|
||||
const { c, bindMock } = createMockContext('/1.html/')
|
||||
|
||||
await getComments(c)
|
||||
|
||||
const calls = bindMock.mock.calls
|
||||
const allArgs = calls.flat()
|
||||
|
||||
expect(allArgs).toContain('/1.html')
|
||||
expect(allArgs).toContain('/1.html/')
|
||||
})
|
||||
|
||||
it('should query both variants for full URL', async () => {
|
||||
const { c, bindMock } = createMockContext('https://example.com/foo')
|
||||
|
||||
await getComments(c)
|
||||
|
||||
const calls = bindMock.mock.calls
|
||||
const allArgs = calls.flat()
|
||||
|
||||
expect(allArgs).toContain('https://example.com/foo')
|
||||
expect(allArgs).toContain('https://example.com/foo/')
|
||||
})
|
||||
|
||||
it('should handle root path correctly', async () => {
|
||||
const { c, bindMock } = createMockContext('/')
|
||||
|
||||
await getComments(c)
|
||||
|
||||
const calls = bindMock.mock.calls
|
||||
const allArgs = calls.flat()
|
||||
|
||||
expect(allArgs).toContain('/')
|
||||
})
|
||||
})
|
||||
@@ -30,7 +30,15 @@ export const getComments = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
slugList = Array.from(new Set([withSlash, withoutSlash]))
|
||||
}
|
||||
} catch {
|
||||
slugList = [postSlug]
|
||||
const path = postSlug.split('?')[0].split('#')[0]
|
||||
if (path === '/' || path === '') {
|
||||
slugList = ['/']
|
||||
} else {
|
||||
const hasTrailingSlash = path.endsWith('/')
|
||||
const withSlash = hasTrailingSlash ? path : path + '/'
|
||||
const withoutSlash = hasTrailingSlash ? path.slice(0, -1) : path
|
||||
slugList = Array.from(new Set([withSlash, withoutSlash]))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user