Files
payload/test/form-state/int.spec.ts
Jacob Fletcher 9ea8a7acf0 feat: form state select (#11689)
Implements a select-like API into the form state endpoint. This follows
the same spec as the Select API on existing Payload operations, but
works on form state rather than at the db level. This means you can send
the `select` argument through the form state handler, and it will only
process and return the fields you've explicitly identified.

This is especially useful when you only need to generate a partial form
state, for example within the bulk edit form where you select only a
subset of fields to edit. There is no need to iterate all fields of the
schema, generate default values for each, and return them all through
the network. This will also simplify and reduce the amount of
client-side processing required, where we longer need to strip
unselected fields before submission.
2025-03-14 13:11:12 -04:00

143 lines
3.3 KiB
TypeScript

import type { Payload, User } from 'payload'
import { buildFormState } from '@payloadcms/ui/utilities/buildFormState'
import path from 'path'
import { createLocalReq } from 'payload'
import { fileURLToPath } from 'url'
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
import { devUser } from '../credentials.js'
import { initPayloadInt } from '../helpers/initPayloadInt.js'
import { postsSlug } from './collections/Posts/index.js'
let payload: Payload
let token: string
let restClient: NextRESTClient
let user: User
const { email, password } = devUser
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
describe('Form State', () => {
// --__--__--__--__--__--__--__--__--__
// Boilerplate test setup/teardown
// --__--__--__--__--__--__--__--__--__
beforeAll(async () => {
;({ payload, restClient } = await initPayloadInt(dirname))
const data = await restClient
.POST('/users/login', {
body: JSON.stringify({
email,
password,
}),
})
.then((res) => res.json())
token = data.token
user = data.user
})
afterAll(async () => {
if (typeof payload.db.destroy === 'function') {
await payload.db.destroy()
}
})
it('should build entire form state', async () => {
const req = await createLocalReq({ user }, payload)
const postData = await payload.create({
collection: postsSlug,
data: {
title: 'Test Post',
},
})
const { state } = await buildFormState({
id: postData.id,
collectionSlug: postsSlug,
data: postData,
docPermissions: {
create: true,
delete: true,
fields: true,
read: true,
readVersions: true,
update: true,
},
docPreferences: {
fields: {},
},
documentFormState: undefined,
operation: 'update',
renderAllFields: false,
req,
schemaPath: postsSlug,
})
expect(state).toMatchObject({
title: {
value: postData.title,
initialValue: postData.title,
},
updatedAt: {
value: postData.updatedAt,
initialValue: postData.updatedAt,
},
createdAt: {
value: postData.createdAt,
initialValue: postData.createdAt,
},
renderTracker: {},
validateUsingEvent: {},
blocks: {
initialValue: 0,
requiresRender: false,
rows: [],
value: 0,
},
})
})
it('should use `select` to build partial form state with only specified fields', async () => {
const req = await createLocalReq({ user }, payload)
const postData = await payload.create({
collection: postsSlug,
data: {
title: 'Test Post',
},
})
const { state } = await buildFormState({
id: postData.id,
collectionSlug: postsSlug,
data: postData,
docPermissions: undefined,
docPreferences: {
fields: {},
},
documentFormState: undefined,
operation: 'update',
renderAllFields: false,
req,
schemaPath: postsSlug,
select: {
title: true,
},
})
expect(state).toStrictEqual({
title: {
value: postData.title,
initialValue: postData.title,
},
})
})
it.todo('should skip validation if specified')
})