Cap articles.content at 10000 characters, with coverage
PocketBase silently enforced its own default max on unbounded text fields, which broke saving a real production article longer than that. Make the limit explicit and generous enough for the content this blog actually publishes, and add a test asserting the exact boundary.
This commit is contained in:
@@ -18,7 +18,7 @@ migrate((app) => {
|
|||||||
fields: [
|
fields: [
|
||||||
{ type: 'text', name: 'title', required: true, max: 160 },
|
{ type: 'text', name: 'title', required: true, max: 160 },
|
||||||
{ type: 'text', name: 'slug', required: true, max: 160, pattern: '^[a-z0-9]+(-[a-z0-9]+)*$' },
|
{ type: 'text', name: 'slug', required: true, max: 160, pattern: '^[a-z0-9]+(-[a-z0-9]+)*$' },
|
||||||
{ type: 'text', name: 'content', required: true },
|
{ type: 'text', name: 'content', required: true, max: 10000 },
|
||||||
{
|
{
|
||||||
type: 'file',
|
type: 'file',
|
||||||
name: 'cover',
|
name: 'cover',
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { afterAll, describe, expect, it } from 'vitest'
|
||||||
|
import { startTestPocketbase } from '../support/pocketbase'
|
||||||
|
|
||||||
|
// Exercises the PocketBase collection schema directly (pb_migrations), not the
|
||||||
|
// Nitro /content/* endpoints — this is about what the CMS itself accepts.
|
||||||
|
const pb = await startTestPocketbase()
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await pb.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function createArticle(content: string) {
|
||||||
|
return fetch(`${pb.url}/api/collections/articles/records`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Authorization: pb.token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
title: 'Vincolo lunghezza contenuto',
|
||||||
|
slug: 'vincolo-lunghezza-contenuto',
|
||||||
|
content,
|
||||||
|
publishedAt: '2025-01-01 00:00:00',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('articles.content max length', () => {
|
||||||
|
it('accepts content up to 10000 characters', async () => {
|
||||||
|
const response = await createArticle('a'.repeat(10000))
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects content over 10000 characters', async () => {
|
||||||
|
const response = await createArticle('a'.repeat(10001))
|
||||||
|
expect(response.status).toBe(400)
|
||||||
|
const body = await response.json()
|
||||||
|
expect(body.data.content.code).toBe('validation_max_text_constraint')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -83,6 +83,8 @@ export interface TestCategory {
|
|||||||
|
|
||||||
export interface TestPocketbase {
|
export interface TestPocketbase {
|
||||||
url: string
|
url: string
|
||||||
|
/** Superuser auth token, for tests that need to create/inspect records beyond the seeded fixtures. */
|
||||||
|
token: string
|
||||||
categories: TestCategory[]
|
categories: TestCategory[]
|
||||||
articles: TestArticle[]
|
articles: TestArticle[]
|
||||||
stop(): Promise<void>
|
stop(): Promise<void>
|
||||||
@@ -155,6 +157,7 @@ export async function startTestPocketbase(options: StartOptions = {}): Promise<T
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
url,
|
url,
|
||||||
|
token,
|
||||||
categories,
|
categories,
|
||||||
articles,
|
articles,
|
||||||
async stop() {
|
async stop() {
|
||||||
|
|||||||
Reference in New Issue
Block a user