This clarifies that jobs.autoRun only *runs* already-queued jobs. It does not queue the jobs for you. Also adds an e2e test as this functionality had no e2e coverage
3326 lines
88 KiB
TypeScript
3326 lines
88 KiB
TypeScript
import type { MongooseAdapter } from '@payloadcms/db-mongodb'
|
|
import type { IndexDirection, IndexOptions } from 'mongoose'
|
|
|
|
import path from 'path'
|
|
import { type Payload, reload } from 'payload'
|
|
import { fileURLToPath } from 'url'
|
|
|
|
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
|
|
import type { BlockField, GroupField } from './payload-types.js'
|
|
|
|
import { devUser } from '../credentials.js'
|
|
import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
|
import { isMongoose } from '../helpers/isMongoose.js'
|
|
import { arrayDefaultValue } from './collections/Array/index.js'
|
|
import { blocksDoc } from './collections/Blocks/shared.js'
|
|
import { dateDoc } from './collections/Date/shared.js'
|
|
import { groupDefaultChild, groupDefaultValue } from './collections/Group/index.js'
|
|
import { namedGroupDoc } from './collections/Group/shared.js'
|
|
import { defaultNumber } from './collections/Number/index.js'
|
|
import { numberDoc } from './collections/Number/shared.js'
|
|
import { pointDoc } from './collections/Point/shared.js'
|
|
import {
|
|
localizedTextValue,
|
|
namedTabDefaultValue,
|
|
namedTabText,
|
|
} from './collections/Tabs/constants.js'
|
|
import { tabsDoc } from './collections/Tabs/shared.js'
|
|
import { defaultText } from './collections/Text/shared.js'
|
|
import { clearAndSeedEverything } from './seed.js'
|
|
import {
|
|
arrayFieldsSlug,
|
|
blockFieldsSlug,
|
|
checkboxFieldsSlug,
|
|
collapsibleFieldsSlug,
|
|
groupFieldsSlug,
|
|
numberFieldsSlug,
|
|
relationshipFieldsSlug,
|
|
tabsFieldsSlug,
|
|
textFieldsSlug,
|
|
} from './slugs.js'
|
|
|
|
let restClient: NextRESTClient
|
|
let user: any
|
|
let payload: Payload
|
|
|
|
const filename = fileURLToPath(import.meta.url)
|
|
const dirname = path.dirname(filename)
|
|
|
|
describe('Fields', () => {
|
|
beforeAll(async () => {
|
|
process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit
|
|
;({ payload, restClient } = await initPayloadInt(dirname))
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await payload.destroy()
|
|
})
|
|
|
|
beforeEach(async () => {
|
|
await clearAndSeedEverything(payload)
|
|
await restClient.login({
|
|
slug: 'users',
|
|
credentials: devUser,
|
|
})
|
|
user = await payload.login({
|
|
collection: 'users',
|
|
data: {
|
|
email: devUser.email,
|
|
password: devUser.password,
|
|
},
|
|
})
|
|
})
|
|
|
|
describe('text', () => {
|
|
let doc
|
|
const text = 'text field'
|
|
beforeEach(async () => {
|
|
doc = await payload.create({
|
|
collection: 'text-fields',
|
|
data: { text },
|
|
})
|
|
})
|
|
|
|
it('creates with default values', () => {
|
|
expect(doc.text).toStrictEqual(text)
|
|
expect(doc.defaultString).toStrictEqual(defaultText)
|
|
expect(doc.defaultEmptyString).toStrictEqual('')
|
|
expect(doc.defaultFunction).toStrictEqual(defaultText)
|
|
expect(doc.defaultAsync).toStrictEqual(defaultText)
|
|
})
|
|
|
|
it('should populate default values in beforeValidate hook', async () => {
|
|
const { dependentOnFieldWithDefaultValue, fieldWithDefaultValue } = await payload.create({
|
|
collection: 'text-fields',
|
|
data: { text },
|
|
})
|
|
|
|
expect(fieldWithDefaultValue).toEqual(dependentOnFieldWithDefaultValue)
|
|
})
|
|
|
|
it('should populate function default values from req', async () => {
|
|
const text = await payload.create({
|
|
req: {
|
|
context: {
|
|
defaultValue: 'from-context',
|
|
},
|
|
},
|
|
collection: 'text-fields',
|
|
data: { text: 'required' },
|
|
})
|
|
|
|
expect(text.defaultValueFromReq).toBe('from-context')
|
|
})
|
|
|
|
it('should localize an array of strings using hasMany', async () => {
|
|
const localizedHasMany = ['hello', 'world']
|
|
const { id } = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
localizedHasMany,
|
|
text,
|
|
},
|
|
locale: 'en',
|
|
})
|
|
const localizedDoc = await payload.findByID({
|
|
id,
|
|
collection: 'text-fields',
|
|
locale: 'all',
|
|
})
|
|
|
|
// @ts-expect-error
|
|
expect(localizedDoc.localizedHasMany.en).toEqual(localizedHasMany)
|
|
})
|
|
|
|
it('should query hasMany in', async () => {
|
|
const hit = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
hasMany: ['one', 'five'],
|
|
text: 'required',
|
|
},
|
|
})
|
|
|
|
const miss = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
hasMany: ['two'],
|
|
text: 'required',
|
|
},
|
|
})
|
|
|
|
const { docs } = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
hasMany: {
|
|
in: ['one'],
|
|
},
|
|
},
|
|
})
|
|
|
|
const hitResult = docs.find(({ id: findID }) => hit.id === findID)
|
|
const missResult = docs.find(({ id: findID }) => miss.id === findID)
|
|
|
|
expect(hitResult).toBeDefined()
|
|
expect(missResult).toBeFalsy()
|
|
})
|
|
|
|
it('should query like on value', async () => {
|
|
const miss = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'dog',
|
|
},
|
|
})
|
|
|
|
const hit = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'cat',
|
|
},
|
|
})
|
|
|
|
const { docs } = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
text: {
|
|
like: 'cat',
|
|
},
|
|
},
|
|
})
|
|
|
|
const hitResult = docs.find(({ id: findID }) => hit.id === findID)
|
|
const missResult = docs.find(({ id: findID }) => miss.id === findID)
|
|
|
|
expect(hitResult).toBeDefined()
|
|
expect(missResult).toBeFalsy()
|
|
})
|
|
|
|
it('should query not_like on value', async () => {
|
|
const hit = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'dog',
|
|
},
|
|
})
|
|
|
|
const miss = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'cat',
|
|
},
|
|
})
|
|
|
|
const { docs } = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
text: {
|
|
not_like: 'cat',
|
|
},
|
|
},
|
|
})
|
|
|
|
const hitResult = docs.find(({ id: findID }) => hit.id === findID)
|
|
const missResult = docs.find(({ id: findID }) => miss.id === findID)
|
|
|
|
expect(hitResult).toBeDefined()
|
|
expect(missResult).toBeFalsy()
|
|
})
|
|
|
|
it('should query hasMany within an array', async () => {
|
|
const docFirst = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'required',
|
|
array: [
|
|
{
|
|
texts: ['text_1', 'text_2'],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const docSecond = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'required',
|
|
array: [
|
|
{
|
|
texts: ['text_other', 'text_2'],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const resEqualsFull = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'array.texts': {
|
|
equals: 'text_2',
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resEqualsFull.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFull.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resEqualsFull.totalDocs).toBe(2)
|
|
|
|
const resEqualsFirst = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'array.texts': {
|
|
equals: 'text_1',
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docSecond.id)).toBeUndefined()
|
|
|
|
expect(resEqualsFirst.totalDocs).toBe(1)
|
|
|
|
const resContainsSecond = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'array.texts': {
|
|
contains: 'text_other',
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resContainsSecond.docs.find((res) => res.id === docFirst.id)).toBeUndefined()
|
|
expect(resContainsSecond.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resContainsSecond.totalDocs).toBe(1)
|
|
|
|
const resInSecond = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'array.texts': {
|
|
in: ['text_other'],
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resInSecond.docs.find((res) => res.id === docFirst.id)).toBeUndefined()
|
|
expect(resInSecond.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resInSecond.totalDocs).toBe(1)
|
|
})
|
|
|
|
it('should query hasMany within blocks', async () => {
|
|
const docFirst = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'required',
|
|
blocks: [
|
|
{
|
|
blockType: 'blockWithText',
|
|
texts: ['text_1', 'text_2'],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const docSecond = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: 'required',
|
|
blocks: [
|
|
{
|
|
blockType: 'blockWithText',
|
|
texts: ['text_other', 'text_2'],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const resEqualsFull = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'blocks.texts': {
|
|
equals: 'text_2',
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resEqualsFull.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFull.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resEqualsFull.totalDocs).toBe(2)
|
|
|
|
const resEqualsFirst = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'blocks.texts': {
|
|
equals: 'text_1',
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docSecond.id)).toBeUndefined()
|
|
|
|
expect(resEqualsFirst.totalDocs).toBe(1)
|
|
|
|
const resContainsSecond = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'blocks.texts': {
|
|
contains: 'text_other',
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resContainsSecond.docs.find((res) => res.id === docFirst.id)).toBeUndefined()
|
|
expect(resContainsSecond.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resContainsSecond.totalDocs).toBe(1)
|
|
|
|
const resInSecond = await payload.find({
|
|
collection: 'text-fields',
|
|
where: {
|
|
'blocks.texts': {
|
|
in: ['text_other'],
|
|
},
|
|
},
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(resInSecond.docs.find((res) => res.id === docFirst.id)).toBeUndefined()
|
|
expect(resInSecond.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resInSecond.totalDocs).toBe(1)
|
|
})
|
|
|
|
it('should delete rows when updating hasMany with empty array', async () => {
|
|
const { id: createdDocId } = await payload.create({
|
|
collection: textFieldsSlug,
|
|
data: {
|
|
text: 'hasMany deletion test',
|
|
hasMany: ['one', 'two', 'three'],
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
collection: textFieldsSlug,
|
|
id: createdDocId,
|
|
data: {
|
|
hasMany: [],
|
|
},
|
|
})
|
|
|
|
const resultingDoc = await payload.findByID({
|
|
collection: textFieldsSlug,
|
|
id: createdDocId,
|
|
})
|
|
|
|
expect(resultingDoc.hasMany).toHaveLength(0)
|
|
})
|
|
})
|
|
|
|
describe('relationship', () => {
|
|
let textDoc
|
|
let otherTextDoc
|
|
let selfReferencing
|
|
let parent
|
|
let child
|
|
let grandChild
|
|
let relationshipInArray
|
|
const textDocText = 'text document'
|
|
const otherTextDocText = 'alt text'
|
|
const relationshipText = 'relationship text'
|
|
|
|
beforeEach(async () => {
|
|
textDoc = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: textDocText,
|
|
},
|
|
})
|
|
otherTextDoc = await payload.create({
|
|
collection: 'text-fields',
|
|
data: {
|
|
text: otherTextDocText,
|
|
},
|
|
})
|
|
const relationship = { relationTo: 'text-fields', value: textDoc.id }
|
|
parent = await payload.create({
|
|
collection: relationshipFieldsSlug,
|
|
data: {
|
|
relationship,
|
|
text: relationshipText,
|
|
},
|
|
})
|
|
|
|
child = await payload.create({
|
|
collection: relationshipFieldsSlug,
|
|
data: {
|
|
relationToSelf: parent.id,
|
|
relationship,
|
|
text: relationshipText,
|
|
},
|
|
})
|
|
|
|
grandChild = await payload.create({
|
|
collection: relationshipFieldsSlug,
|
|
data: {
|
|
relationToSelf: child.id,
|
|
relationship,
|
|
text: relationshipText,
|
|
},
|
|
})
|
|
|
|
selfReferencing = await payload.create({
|
|
collection: relationshipFieldsSlug,
|
|
data: {
|
|
relationship,
|
|
text: relationshipText,
|
|
},
|
|
})
|
|
|
|
relationshipInArray = await payload.create({
|
|
collection: relationshipFieldsSlug,
|
|
data: {
|
|
array: [
|
|
{
|
|
relationship: otherTextDoc.id,
|
|
},
|
|
],
|
|
relationship,
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should query parent self-reference', async () => {
|
|
const childResult = await payload.find({
|
|
collection: relationshipFieldsSlug,
|
|
where: {
|
|
relationToSelf: { equals: parent.id },
|
|
},
|
|
})
|
|
|
|
const grandChildResult = await payload.find({
|
|
collection: relationshipFieldsSlug,
|
|
where: {
|
|
relationToSelf: { equals: child.id },
|
|
},
|
|
})
|
|
|
|
const anyChildren = await payload.find({
|
|
collection: relationshipFieldsSlug,
|
|
})
|
|
const allChildren = await payload.find({
|
|
collection: relationshipFieldsSlug,
|
|
where: {
|
|
'relationToSelf.text': { equals: relationshipText },
|
|
},
|
|
})
|
|
|
|
expect(childResult.docs[0].id).toStrictEqual(child.id)
|
|
expect(grandChildResult.docs[0].id).toStrictEqual(grandChild.id)
|
|
expect(allChildren.docs).toHaveLength(2)
|
|
})
|
|
|
|
it('should query relationship inside array', async () => {
|
|
const result = await payload.find({
|
|
collection: relationshipFieldsSlug,
|
|
where: {
|
|
'array.relationship.text': { equals: otherTextDocText },
|
|
},
|
|
})
|
|
|
|
expect(result.docs).toHaveLength(1)
|
|
expect(result.docs[0]).toMatchObject(relationshipInArray)
|
|
})
|
|
|
|
it('should query text in row after relationship', async () => {
|
|
const row = await payload.create({
|
|
collection: 'row-fields',
|
|
data: { title: 'some-title', id: 'custom-row-id' },
|
|
})
|
|
const textDoc = await payload.create({
|
|
collection: 'text-fields',
|
|
data: { text: 'asd' },
|
|
})
|
|
|
|
const rel = await payload.create({
|
|
collection: 'relationship-fields',
|
|
data: {
|
|
relationship: { relationTo: 'text-fields', value: textDoc },
|
|
relationToRow: row.id,
|
|
relationToRowMany: [row.id],
|
|
},
|
|
})
|
|
|
|
const result = await payload.find({
|
|
collection: 'relationship-fields',
|
|
where: {
|
|
'relationToRow.title': { equals: 'some-title' },
|
|
'relationToRowMany.title': { equals: 'some-title' },
|
|
},
|
|
})
|
|
|
|
expect(result.docs[0].id).toBe(rel.id)
|
|
expect(result.totalDocs).toBe(1)
|
|
})
|
|
})
|
|
|
|
describe('rows', () => {
|
|
it('should show proper validation error message on text field within row field', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'row-fields',
|
|
data: {
|
|
id: 'some-id',
|
|
title: '',
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Title within a row')
|
|
})
|
|
})
|
|
|
|
describe('timestamps', () => {
|
|
const tenMinutesAgo = new Date(Date.now() - 1000 * 60 * 10)
|
|
let doc
|
|
beforeEach(async () => {
|
|
doc = await payload.create({
|
|
collection: 'date-fields',
|
|
data: dateDoc,
|
|
})
|
|
})
|
|
|
|
it('should query updatedAt', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'date-fields',
|
|
depth: 0,
|
|
where: {
|
|
updatedAt: {
|
|
greater_than_equal: tenMinutesAgo,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(docs.map(({ id }) => id)).toContain(doc.id)
|
|
})
|
|
|
|
it('should query createdAt', async () => {
|
|
const result = await payload.find({
|
|
collection: 'date-fields',
|
|
depth: 0,
|
|
where: {
|
|
createdAt: {
|
|
greater_than_equal: tenMinutesAgo,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(result.docs[0].id).toEqual(doc.id)
|
|
})
|
|
|
|
// Function to generate random date between start and end dates
|
|
function getRandomDate(start: Date, end: Date): string {
|
|
const date = new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()))
|
|
return date.toISOString()
|
|
}
|
|
|
|
// Generate sample data
|
|
const dataSample = Array.from({ length: 100 }, (_, index) => {
|
|
const startDate = new Date('2024-01-01')
|
|
const endDate = new Date('2025-12-31')
|
|
|
|
return {
|
|
array: Array.from({ length: 5 }, (_, listIndex) => {
|
|
return {
|
|
date: getRandomDate(startDate, endDate),
|
|
}
|
|
}),
|
|
...dateDoc,
|
|
}
|
|
})
|
|
|
|
it('should query a date field inside an array field', async () => {
|
|
await payload.delete({ collection: 'date-fields', where: {} })
|
|
for (const doc of dataSample) {
|
|
await payload.create({
|
|
collection: 'date-fields',
|
|
data: doc,
|
|
})
|
|
}
|
|
|
|
const res = await payload.find({
|
|
collection: 'date-fields',
|
|
where: { 'array.date': { greater_than: new Date('2025-06-01').toISOString() } },
|
|
})
|
|
|
|
const filter = (doc: any) =>
|
|
doc.array.some((item) => new Date(item.date).getTime() > new Date('2025-06-01').getTime())
|
|
|
|
expect(res.docs.every(filter)).toBe(true)
|
|
expect(dataSample.filter(filter)).toHaveLength(res.totalDocs)
|
|
// eslint-disable-next-line jest/no-conditional-in-test
|
|
if (res.totalDocs > 10) {
|
|
// This is where postgres might fail! selectDistinct actually removed some rows here, because it distincts by:
|
|
// not only ID, but also created_at, updated_at, items_date
|
|
expect(res.docs).toHaveLength(10)
|
|
} else {
|
|
expect(res.docs.length).toBeLessThanOrEqual(res.totalDocs)
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('select', () => {
|
|
let doc
|
|
beforeEach(async () => {
|
|
const { id } = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
selectHasManyLocalized: ['one', 'two'],
|
|
},
|
|
locale: 'en',
|
|
})
|
|
doc = await payload.findByID({
|
|
id,
|
|
collection: 'select-fields',
|
|
locale: 'all',
|
|
})
|
|
})
|
|
|
|
it('creates with hasMany localized', () => {
|
|
expect(doc.selectHasManyLocalized.en).toEqual(['one', 'two'])
|
|
})
|
|
|
|
it('retains hasMany updates', async () => {
|
|
const { id } = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
selectHasMany: ['one', 'two'],
|
|
},
|
|
})
|
|
|
|
const updatedDoc = await payload.update({
|
|
id,
|
|
collection: 'select-fields',
|
|
data: {
|
|
select: 'one',
|
|
},
|
|
})
|
|
|
|
expect(Array.isArray(updatedDoc.selectHasMany)).toBe(true)
|
|
expect(updatedDoc.selectHasMany).toEqual(['one', 'two'])
|
|
})
|
|
|
|
it('should clear select hasMany field', async () => {
|
|
const { id } = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
selectHasMany: ['one', 'two'],
|
|
},
|
|
})
|
|
|
|
const updatedDoc = await payload.update({
|
|
id,
|
|
collection: 'select-fields',
|
|
data: {
|
|
selectHasMany: [],
|
|
},
|
|
})
|
|
|
|
expect(updatedDoc.selectHasMany).toHaveLength(0)
|
|
})
|
|
|
|
it('should query hasMany in', async () => {
|
|
const hit = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
selectHasMany: ['one', 'four'],
|
|
},
|
|
})
|
|
|
|
const miss = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
selectHasMany: ['three'],
|
|
},
|
|
})
|
|
|
|
const { docs } = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
selectHasMany: {
|
|
in: ['one'],
|
|
},
|
|
},
|
|
})
|
|
|
|
const hitResult = docs.find(({ id: findID }) => hit.id === findID)
|
|
const missResult = docs.find(({ id: findID }) => miss.id === findID)
|
|
|
|
expect(hitResult).toBeDefined()
|
|
expect(missResult).toBeFalsy()
|
|
})
|
|
|
|
it('should CRUD within array hasMany', async () => {
|
|
const doc = await payload.create({
|
|
collection: 'select-fields',
|
|
data: { array: [{ selectHasMany: ['one', 'two'] }] },
|
|
})
|
|
|
|
expect(doc.array[0].selectHasMany).toStrictEqual(['one', 'two'])
|
|
|
|
const upd = await payload.update({
|
|
collection: 'select-fields',
|
|
id: doc.id,
|
|
data: {
|
|
array: [
|
|
{
|
|
id: doc.array[0].id,
|
|
selectHasMany: ['six'],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
expect(upd.array[0].selectHasMany).toStrictEqual(['six'])
|
|
})
|
|
|
|
it('should CRUD within array + group hasMany', async () => {
|
|
const doc = await payload.create({
|
|
collection: 'select-fields',
|
|
data: { array: [{ group: { selectHasMany: ['one', 'two'] } }] },
|
|
})
|
|
|
|
expect(doc.array[0].group.selectHasMany).toStrictEqual(['one', 'two'])
|
|
|
|
const upd = await payload.update({
|
|
collection: 'select-fields',
|
|
id: doc.id,
|
|
data: {
|
|
array: [
|
|
{
|
|
id: doc.array[0].id,
|
|
group: { selectHasMany: ['six'] },
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
expect(upd.array[0].group.selectHasMany).toStrictEqual(['six'])
|
|
})
|
|
|
|
it('should work with versions', async () => {
|
|
const base = await payload.create({
|
|
collection: 'select-versions-fields',
|
|
data: { hasMany: ['a', 'b'] },
|
|
})
|
|
|
|
expect(base.hasMany).toStrictEqual(['a', 'b'])
|
|
|
|
const array = await payload.create({
|
|
collection: 'select-versions-fields',
|
|
data: { array: [{ hasManyArr: ['a', 'b'] }] },
|
|
draft: true,
|
|
})
|
|
|
|
expect(array.array[0]?.hasManyArr).toStrictEqual(['a', 'b'])
|
|
|
|
const block = await payload.create({
|
|
collection: 'select-versions-fields',
|
|
data: { blocks: [{ blockType: 'block', hasManyBlocks: ['a', 'b'] }] },
|
|
})
|
|
|
|
expect(block.blocks[0]?.hasManyBlocks).toStrictEqual(['a', 'b'])
|
|
})
|
|
|
|
it('should work with autosave', async () => {
|
|
let data = await payload.create({
|
|
collection: 'select-versions-fields',
|
|
data: { hasMany: ['a', 'b', 'c'] },
|
|
})
|
|
expect(data.hasMany).toStrictEqual(['a', 'b', 'c'])
|
|
|
|
data = await payload.update({
|
|
id: data.id,
|
|
collection: 'select-versions-fields',
|
|
data: { hasMany: ['a'] },
|
|
draft: true,
|
|
})
|
|
expect(data.hasMany).toStrictEqual(['a'])
|
|
|
|
data = await payload.update({
|
|
id: data.id,
|
|
collection: 'select-versions-fields',
|
|
data: { hasMany: ['a', 'b', 'c', 'd'] },
|
|
draft: true,
|
|
autosave: true,
|
|
})
|
|
expect(data.hasMany).toStrictEqual(['a', 'b', 'c', 'd'])
|
|
|
|
data = await payload.update({
|
|
id: data.id,
|
|
collection: 'select-versions-fields',
|
|
data: { hasMany: ['a'] },
|
|
draft: true,
|
|
autosave: true,
|
|
})
|
|
expect(data.hasMany).toStrictEqual(['a'])
|
|
})
|
|
|
|
it('should prevent against saving a value excluded by `filterOptions`', async () => {
|
|
try {
|
|
const result = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
disallowOption1: true,
|
|
selectWithFilteredOptions: 'one',
|
|
},
|
|
})
|
|
|
|
expect(result).toBeFalsy()
|
|
} catch (error) {
|
|
expect((error as Error).message).toBe(
|
|
'The following field is invalid: Select with filtered options',
|
|
)
|
|
}
|
|
|
|
const result = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
disallowOption1: true,
|
|
selectWithFilteredOptions: 'two',
|
|
},
|
|
})
|
|
|
|
expect(result).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe('number', () => {
|
|
let doc
|
|
beforeEach(async () => {
|
|
doc = await payload.create({
|
|
collection: 'number-fields',
|
|
data: numberDoc,
|
|
})
|
|
})
|
|
|
|
it('creates with default values', () => {
|
|
expect(doc.number).toEqual(numberDoc.number)
|
|
expect(doc.min).toEqual(numberDoc.min)
|
|
expect(doc.max).toEqual(numberDoc.max)
|
|
expect(doc.positiveNumber).toEqual(numberDoc.positiveNumber)
|
|
expect(doc.negativeNumber).toEqual(numberDoc.negativeNumber)
|
|
expect(doc.decimalMin).toEqual(numberDoc.decimalMin)
|
|
expect(doc.decimalMax).toEqual(numberDoc.decimalMax)
|
|
expect(doc.defaultNumber).toEqual(defaultNumber)
|
|
})
|
|
|
|
it('should not create number below minimum', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
min: 5,
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Min')
|
|
})
|
|
it('should not create number above max', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
max: 15,
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Max')
|
|
})
|
|
|
|
it('should not create number below 0', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
positiveNumber: -5,
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Positive Number')
|
|
})
|
|
|
|
it('should not create number above 0', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
negativeNumber: 5,
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Negative Number')
|
|
})
|
|
it('should not create a decimal number below min', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
decimalMin: -0.25,
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Decimal Min')
|
|
})
|
|
|
|
it('should not create a decimal number above max', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
decimalMax: 1.5,
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Decimal Max')
|
|
})
|
|
it('should localize an array of numbers using hasMany', async () => {
|
|
const localizedHasMany = [5, 10]
|
|
const { id } = await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
localizedHasMany,
|
|
},
|
|
locale: 'en',
|
|
})
|
|
const localizedDoc = await payload.findByID({
|
|
id,
|
|
collection: 'number-fields',
|
|
locale: 'all',
|
|
})
|
|
|
|
// @ts-expect-error
|
|
expect(localizedDoc.localizedHasMany.en).toEqual(localizedHasMany)
|
|
})
|
|
|
|
it('should query hasMany in', async () => {
|
|
const hit = await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
hasMany: [5, 10],
|
|
},
|
|
})
|
|
|
|
const miss = await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
hasMany: [13],
|
|
},
|
|
})
|
|
|
|
const { docs } = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
hasMany: {
|
|
in: [5],
|
|
},
|
|
},
|
|
})
|
|
|
|
const hitResult = docs.find(({ id: findID }) => hit.id === findID)
|
|
const missResult = docs.find(({ id: findID }) => miss.id === findID)
|
|
|
|
expect(hitResult).toBeDefined()
|
|
expect(missResult).toBeFalsy()
|
|
})
|
|
|
|
it('should properly query numbers with exists operator', async () => {
|
|
await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
number: null,
|
|
},
|
|
})
|
|
|
|
const numbersExist = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
number: {
|
|
exists: true,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(numbersExist.totalDocs).toBe(4)
|
|
|
|
const numbersNotExists = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
number: {
|
|
exists: false,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(numbersNotExists.docs).toHaveLength(1)
|
|
})
|
|
|
|
it('should delete rows when updating hasMany with empty array', async () => {
|
|
const { id: createdDocId } = await payload.create({
|
|
collection: numberFieldsSlug,
|
|
data: {
|
|
localizedHasMany: [1, 2, 3],
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
collection: numberFieldsSlug,
|
|
id: createdDocId,
|
|
data: {
|
|
localizedHasMany: [],
|
|
},
|
|
})
|
|
|
|
const resultingDoc = await payload.findByID({
|
|
collection: numberFieldsSlug,
|
|
id: createdDocId,
|
|
})
|
|
|
|
expect(resultingDoc.localizedHasMany).toHaveLength(0)
|
|
})
|
|
})
|
|
|
|
it('should query hasMany within an array', async () => {
|
|
const docFirst = await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
array: [
|
|
{
|
|
numbers: [10, 30],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const docSecond = await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
array: [
|
|
{
|
|
numbers: [10, 40],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const resEqualsFull = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
'array.numbers': {
|
|
equals: 10,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(resEqualsFull.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFull.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resEqualsFull.totalDocs).toBe(2)
|
|
|
|
const resEqualsFirst = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
'array.numbers': {
|
|
equals: 30,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docSecond.id)).toBeUndefined()
|
|
|
|
expect(resEqualsFirst.totalDocs).toBe(1)
|
|
|
|
const resInSecond = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
'array.numbers': {
|
|
in: [40],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(resInSecond.docs.find((res) => res.id === docFirst.id)).toBeUndefined()
|
|
expect(resInSecond.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resInSecond.totalDocs).toBe(1)
|
|
})
|
|
|
|
it('should query hasMany within blocks', async () => {
|
|
const docFirst = await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
blocks: [
|
|
{
|
|
blockType: 'blockWithNumber',
|
|
numbers: [10, 30],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const docSecond = await payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
blocks: [
|
|
{
|
|
blockType: 'blockWithNumber',
|
|
numbers: [10, 40],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const resEqualsFull = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
'blocks.numbers': {
|
|
equals: 10,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(resEqualsFull.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFull.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resEqualsFull.totalDocs).toBe(2)
|
|
|
|
const resEqualsFirst = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
'blocks.numbers': {
|
|
equals: 30,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docFirst.id)).toBeDefined()
|
|
expect(resEqualsFirst.docs.find((res) => res.id === docSecond.id)).toBeUndefined()
|
|
|
|
expect(resEqualsFirst.totalDocs).toBe(1)
|
|
|
|
const resInSecond = await payload.find({
|
|
collection: 'number-fields',
|
|
where: {
|
|
'blocks.numbers': {
|
|
in: [40],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(resInSecond.docs.find((res) => res.id === docFirst.id)).toBeUndefined()
|
|
expect(resInSecond.docs.find((res) => res.id === docSecond.id)).toBeDefined()
|
|
|
|
expect(resInSecond.totalDocs).toBe(1)
|
|
})
|
|
|
|
if (isMongoose(payload)) {
|
|
describe('indexes', () => {
|
|
let indexes
|
|
const definitions: Record<string, IndexDirection> = {}
|
|
const options: Record<string, IndexOptions> = {}
|
|
|
|
beforeAll(() => {
|
|
indexes = (payload.db as MongooseAdapter).collections[
|
|
'indexed-fields'
|
|
].schema.indexes() as [Record<string, IndexDirection>, IndexOptions]
|
|
|
|
indexes.forEach((index) => {
|
|
const field = Object.keys(index[0])[0]
|
|
definitions[field] = index[0][field]
|
|
|
|
options[field] = index[1]
|
|
})
|
|
})
|
|
|
|
it('should have indexes', () => {
|
|
expect(definitions.text).toEqual(1)
|
|
})
|
|
|
|
it('should have unique sparse indexes when field is not required', () => {
|
|
expect(definitions.uniqueText).toEqual(1)
|
|
expect(options.uniqueText).toMatchObject({ sparse: true, unique: true })
|
|
})
|
|
|
|
it('should have unique indexes that are not sparse when field is required', () => {
|
|
expect(definitions.uniqueRequiredText).toEqual(1)
|
|
expect(options.uniqueText).toMatchObject({ unique: true })
|
|
})
|
|
|
|
it('should have 2dsphere indexes on point fields', () => {
|
|
expect(definitions.point).toEqual('2dsphere')
|
|
})
|
|
|
|
it('should have 2dsphere indexes on point fields in groups', () => {
|
|
expect(definitions['group.point']).toEqual('2dsphere')
|
|
})
|
|
|
|
it('should have a sparse index on a unique localized field in a group', () => {
|
|
expect(definitions['group.localizedUnique.en']).toEqual(1)
|
|
expect(options['group.localizedUnique.en']).toMatchObject({ sparse: true, unique: true })
|
|
expect(definitions['group.localizedUnique.es']).toEqual(1)
|
|
expect(options['group.localizedUnique.es']).toMatchObject({ sparse: true, unique: true })
|
|
})
|
|
|
|
it('should have unique indexes in a collapsible', () => {
|
|
expect(definitions['collapsibleLocalizedUnique.en']).toEqual(1)
|
|
expect(options['collapsibleLocalizedUnique.en']).toMatchObject({
|
|
sparse: true,
|
|
unique: true,
|
|
})
|
|
expect(definitions.collapsibleTextUnique).toEqual(1)
|
|
expect(options.collapsibleTextUnique).toMatchObject({ unique: true })
|
|
})
|
|
})
|
|
|
|
describe('version indexes', () => {
|
|
let indexes
|
|
const definitions: Record<string, IndexDirection> = {}
|
|
const options: Record<string, IndexOptions> = {}
|
|
|
|
beforeEach(() => {
|
|
indexes = (payload.db as MongooseAdapter).versions['indexed-fields'].schema.indexes() as [
|
|
Record<string, IndexDirection>,
|
|
IndexOptions,
|
|
]
|
|
indexes.forEach((index) => {
|
|
const field = Object.keys(index[0])[0]
|
|
definitions[field] = index[0][field]
|
|
|
|
options[field] = index[1]
|
|
})
|
|
})
|
|
|
|
it('should have versions indexes', () => {
|
|
expect(definitions['version.text']).toEqual(1)
|
|
})
|
|
})
|
|
}
|
|
|
|
describe('point', () => {
|
|
let doc
|
|
const point = [7, -7]
|
|
const localized = [5, -2]
|
|
const group = { point: [1, 9] }
|
|
|
|
beforeEach(async () => {
|
|
const findDoc = await payload.find({
|
|
collection: 'point-fields',
|
|
pagination: false,
|
|
})
|
|
;[doc] = findDoc.docs
|
|
})
|
|
|
|
it('should read', async () => {
|
|
if (payload.db.name === 'sqlite') {
|
|
return
|
|
}
|
|
const find = await payload.find({
|
|
collection: 'point-fields',
|
|
pagination: false,
|
|
})
|
|
|
|
;[doc] = find.docs
|
|
|
|
expect(doc.point).toEqual(pointDoc.point)
|
|
expect(doc.localized).toEqual(pointDoc.localized)
|
|
expect(doc.group).toMatchObject(pointDoc.group)
|
|
})
|
|
|
|
it('should create', async () => {
|
|
if (payload.db.name === 'sqlite') {
|
|
return
|
|
}
|
|
doc = await payload.create({
|
|
collection: 'point-fields',
|
|
data: {
|
|
group,
|
|
localized,
|
|
point,
|
|
},
|
|
})
|
|
|
|
expect(doc.point).toEqual(point)
|
|
expect(doc.localized).toEqual(localized)
|
|
expect(doc.group).toMatchObject(group)
|
|
})
|
|
|
|
it('should not create duplicate point when unique', async () => {
|
|
if (payload.db.name === 'sqlite') {
|
|
return
|
|
}
|
|
// first create the point field
|
|
doc = await payload.create({
|
|
collection: 'point-fields',
|
|
data: {
|
|
group,
|
|
localized,
|
|
point,
|
|
},
|
|
})
|
|
|
|
// Now make sure we can't create a duplicate (since 'localized' is a unique field)
|
|
await expect(() =>
|
|
payload.create({
|
|
collection: 'point-fields',
|
|
data: {
|
|
group,
|
|
localized,
|
|
point,
|
|
},
|
|
}),
|
|
).rejects.toThrow(Error)
|
|
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'number-fields',
|
|
data: {
|
|
min: 5,
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Min')
|
|
|
|
expect(doc.point).toEqual(point)
|
|
expect(doc.localized).toEqual(localized)
|
|
expect(doc.group).toMatchObject(group)
|
|
})
|
|
})
|
|
|
|
describe('checkbox', () => {
|
|
beforeEach(async () => {
|
|
await payload.delete({
|
|
collection: checkboxFieldsSlug,
|
|
where: {
|
|
id: {
|
|
exists: true,
|
|
},
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should query checkbox fields with exists operator', async () => {
|
|
const existsTrueDoc = await payload.create({
|
|
collection: checkboxFieldsSlug,
|
|
data: {
|
|
checkbox: true,
|
|
checkboxNotRequired: false,
|
|
},
|
|
})
|
|
|
|
const existsFalseDoc = await payload.create({
|
|
collection: checkboxFieldsSlug,
|
|
data: {
|
|
checkbox: true,
|
|
},
|
|
})
|
|
|
|
const existsFalse = await payload.find({
|
|
collection: checkboxFieldsSlug,
|
|
where: {
|
|
checkboxNotRequired: {
|
|
exists: false,
|
|
},
|
|
},
|
|
})
|
|
expect(existsFalse.totalDocs).toBe(1)
|
|
expect(existsFalse.docs[0]?.id).toEqual(existsFalseDoc.id)
|
|
|
|
const existsTrue = await payload.find({
|
|
collection: checkboxFieldsSlug,
|
|
where: {
|
|
checkboxNotRequired: {
|
|
exists: true,
|
|
},
|
|
},
|
|
})
|
|
expect(existsTrue.totalDocs).toBe(1)
|
|
expect(existsTrue.docs[0]?.id).toEqual(existsTrueDoc.id)
|
|
})
|
|
})
|
|
|
|
describe('unique indexes', () => {
|
|
it('should throw validation error saving on unique fields', async () => {
|
|
const data = {
|
|
text: 'a',
|
|
uniqueText: 'a',
|
|
}
|
|
await payload.create({
|
|
collection: 'indexed-fields',
|
|
data,
|
|
})
|
|
expect(async () => {
|
|
const result = await payload.create({
|
|
collection: 'indexed-fields',
|
|
data,
|
|
})
|
|
return result.error
|
|
}).toBeDefined()
|
|
})
|
|
|
|
it('should throw validation error saving on unique relationship fields hasMany: false non polymorphic', async () => {
|
|
const textDoc = await payload.create({ collection: 'text-fields', data: { text: 'asd' } })
|
|
|
|
await payload
|
|
.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '1',
|
|
text: '2',
|
|
uniqueRequiredText: '3',
|
|
uniqueRelationship: textDoc.id,
|
|
},
|
|
})
|
|
// Skip mongodb unique error because it threats localizedUniqueRequriedText.es as undefined
|
|
.then((doc) =>
|
|
payload.update({
|
|
locale: 'es',
|
|
collection: 'indexed-fields',
|
|
data: { localizedUniqueRequiredText: '20' },
|
|
id: doc.id,
|
|
}),
|
|
)
|
|
|
|
await expect(
|
|
payload.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '4',
|
|
text: '5',
|
|
uniqueRequiredText: '10',
|
|
uniqueRelationship: textDoc.id,
|
|
},
|
|
}),
|
|
).rejects.toBeTruthy()
|
|
})
|
|
|
|
it('should throw validation error saving on unique relationship fields hasMany: true', async () => {
|
|
const textDoc = await payload.create({ collection: 'text-fields', data: { text: 'asd' } })
|
|
|
|
await payload
|
|
.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '1',
|
|
text: '2',
|
|
uniqueRequiredText: '3',
|
|
uniqueHasManyRelationship: [textDoc.id],
|
|
},
|
|
})
|
|
// Skip mongodb unique error because it threats localizedUniqueRequriedText.es as undefined
|
|
.then((doc) =>
|
|
payload.update({
|
|
locale: 'es',
|
|
collection: 'indexed-fields',
|
|
data: { localizedUniqueRequiredText: '40' },
|
|
id: doc.id,
|
|
}),
|
|
)
|
|
|
|
// Should allow the same relationship on a diferrent field!
|
|
await payload
|
|
.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '31',
|
|
text: '24',
|
|
uniqueRequiredText: '55',
|
|
uniqueHasManyRelationship_2: [textDoc.id],
|
|
},
|
|
})
|
|
// Skip mongodb unique error because it threats localizedUniqueRequriedText.es as undefined
|
|
.then((doc) =>
|
|
payload.update({
|
|
locale: 'es',
|
|
collection: 'indexed-fields',
|
|
data: { localizedUniqueRequiredText: '30' },
|
|
id: doc.id,
|
|
}),
|
|
)
|
|
|
|
await expect(
|
|
payload.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '4',
|
|
text: '5',
|
|
uniqueRequiredText: '10',
|
|
uniqueHasManyRelationship: [textDoc.id],
|
|
},
|
|
}),
|
|
).rejects.toBeTruthy()
|
|
})
|
|
|
|
it('should throw validation error saving on unique relationship fields polymorphic not hasMany', async () => {
|
|
const textDoc = await payload.create({ collection: 'text-fields', data: { text: 'asd' } })
|
|
|
|
await payload
|
|
.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '1',
|
|
text: '2',
|
|
uniqueRequiredText: '3',
|
|
uniquePolymorphicRelationship: { relationTo: 'text-fields', value: textDoc.id },
|
|
},
|
|
})
|
|
// Skip mongodb unique error because it threats localizedUniqueRequriedText.es as undefined
|
|
.then((doc) =>
|
|
payload.update({
|
|
locale: 'es',
|
|
collection: 'indexed-fields',
|
|
data: { localizedUniqueRequiredText: '20' },
|
|
id: doc.id,
|
|
}),
|
|
)
|
|
|
|
// Should allow the same relationship on a diferrent field!
|
|
await payload
|
|
.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '31',
|
|
text: '24',
|
|
uniqueRequiredText: '55',
|
|
uniquePolymorphicRelationship_2: { relationTo: 'text-fields', value: textDoc.id },
|
|
},
|
|
})
|
|
// Skip mongodb unique error because it threats localizedUniqueRequriedText.es as undefined
|
|
.then((doc) =>
|
|
payload.update({
|
|
locale: 'es',
|
|
collection: 'indexed-fields',
|
|
data: { localizedUniqueRequiredText: '100' },
|
|
id: doc.id,
|
|
}),
|
|
)
|
|
|
|
await expect(
|
|
payload.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '4',
|
|
text: '5',
|
|
uniqueRequiredText: '10',
|
|
uniquePolymorphicRelationship: { relationTo: 'text-fields', value: textDoc.id },
|
|
},
|
|
}),
|
|
).rejects.toBeTruthy()
|
|
})
|
|
|
|
it('should throw validation error saving on unique relationship fields polymorphic hasMany: true', async () => {
|
|
const textDoc = await payload.create({ collection: 'text-fields', data: { text: 'asd' } })
|
|
|
|
await payload
|
|
.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '1',
|
|
text: '2',
|
|
uniqueRequiredText: '3',
|
|
uniqueHasManyPolymorphicRelationship: [
|
|
{ relationTo: 'text-fields', value: textDoc.id },
|
|
],
|
|
},
|
|
})
|
|
.then((doc) =>
|
|
payload.update({
|
|
locale: 'es',
|
|
collection: 'indexed-fields',
|
|
data: { localizedUniqueRequiredText: '100' },
|
|
id: doc.id,
|
|
}),
|
|
)
|
|
|
|
// Should allow the same relationship on a diferrent field!
|
|
await payload
|
|
.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '31',
|
|
text: '24',
|
|
uniqueRequiredText: '55',
|
|
uniqueHasManyPolymorphicRelationship_2: [
|
|
{ relationTo: 'text-fields', value: textDoc.id },
|
|
],
|
|
},
|
|
})
|
|
// Skip mongodb unique error because it threats localizedUniqueRequriedText.es as undefined
|
|
.then((doc) =>
|
|
payload.update({
|
|
locale: 'es',
|
|
collection: 'indexed-fields',
|
|
data: { localizedUniqueRequiredText: '300' },
|
|
id: doc.id,
|
|
}),
|
|
)
|
|
|
|
await expect(
|
|
payload.create({
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: '4',
|
|
text: '5',
|
|
uniqueRequiredText: '10',
|
|
uniqueHasManyPolymorphicRelationship: [
|
|
{ relationTo: 'text-fields', value: textDoc.id },
|
|
],
|
|
},
|
|
}),
|
|
).rejects.toBeTruthy()
|
|
})
|
|
|
|
it('should not throw validation error saving multiple null values for unique fields', async () => {
|
|
const data = {
|
|
localizedUniqueRequiredText: 'en1',
|
|
text: 'a',
|
|
uniqueRequiredText: 'a',
|
|
// uniqueText omitted on purpose
|
|
}
|
|
const doc = await payload.create({
|
|
collection: 'indexed-fields',
|
|
data,
|
|
})
|
|
// Update spanish so we do not run into the unique constraint for other locales
|
|
await payload.update({
|
|
id: doc.id,
|
|
collection: 'indexed-fields',
|
|
data: {
|
|
localizedUniqueRequiredText: 'es1',
|
|
},
|
|
locale: 'es',
|
|
})
|
|
data.uniqueRequiredText = 'b'
|
|
const result = await payload.create({
|
|
collection: 'indexed-fields',
|
|
data: { ...data, localizedUniqueRequiredText: 'en2' },
|
|
})
|
|
|
|
expect(result.id).toBeDefined()
|
|
})
|
|
|
|
it('should duplicate with unique fields', async () => {
|
|
const data = {
|
|
text: 'a',
|
|
// uniqueRequiredText: 'duplicate',
|
|
}
|
|
const doc = await payload.create({
|
|
collection: 'indexed-fields',
|
|
data,
|
|
})
|
|
const result = await payload.duplicate({
|
|
id: doc.id,
|
|
collection: 'indexed-fields',
|
|
})
|
|
|
|
expect(result.id).not.toEqual(doc.id)
|
|
expect(result.uniqueRequiredText).toStrictEqual('uniqueRequired - Copy')
|
|
})
|
|
})
|
|
|
|
describe('array', () => {
|
|
let doc
|
|
const collection = arrayFieldsSlug
|
|
|
|
beforeEach(async () => {
|
|
doc = await payload.create({
|
|
collection,
|
|
data: {},
|
|
})
|
|
})
|
|
|
|
it('should create with ids and nested ids', async () => {
|
|
const docWithIDs = (await payload.create({
|
|
collection: groupFieldsSlug,
|
|
data: namedGroupDoc,
|
|
})) as Partial<GroupField>
|
|
expect(docWithIDs.group.subGroup.arrayWithinGroup[0].id).toBeDefined()
|
|
})
|
|
|
|
it('should create with defaultValue', () => {
|
|
expect(doc.items).toMatchObject(arrayDefaultValue)
|
|
expect(doc.localized).toMatchObject(arrayDefaultValue)
|
|
})
|
|
|
|
it('should create and update localized subfields with versions', async () => {
|
|
const doc = await payload.create({
|
|
collection,
|
|
data: {
|
|
items: [
|
|
{
|
|
localizedText: 'test',
|
|
text: 'required',
|
|
},
|
|
],
|
|
localized: [
|
|
{
|
|
text: 'english',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const spanish = await payload.update({
|
|
id: doc.id,
|
|
collection,
|
|
data: {
|
|
items: [
|
|
{
|
|
id: doc.items[0].id,
|
|
localizedText: 'spanish',
|
|
text: 'required',
|
|
},
|
|
],
|
|
},
|
|
locale: 'es',
|
|
})
|
|
|
|
const result = await payload.findByID({
|
|
id: doc.id,
|
|
collection,
|
|
locale: 'all',
|
|
})
|
|
|
|
expect(doc.items[0].localizedText).toStrictEqual('test')
|
|
expect(spanish.items[0].localizedText).toStrictEqual('spanish')
|
|
expect(result.items[0].localizedText.en).toStrictEqual('test')
|
|
expect(result.items[0].localizedText.es).toStrictEqual('spanish')
|
|
})
|
|
|
|
it('should create and append localized items to nested array with versions', async () => {
|
|
const doc = await payload.create({
|
|
collection,
|
|
data: {
|
|
items: [{ text: 'req' }],
|
|
localized: [{ text: 'req' }],
|
|
nestedArrayLocalized: [
|
|
{
|
|
array: [
|
|
{
|
|
text: 'marcelo',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const res = await payload.update({
|
|
id: doc.id,
|
|
collection,
|
|
data: {
|
|
nestedArrayLocalized: [
|
|
...doc.nestedArrayLocalized,
|
|
{
|
|
array: [
|
|
{
|
|
text: 'alejandro',
|
|
},
|
|
{
|
|
text: 'raul',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
array: [
|
|
{
|
|
text: 'amigo',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
expect(res.nestedArrayLocalized).toHaveLength(3)
|
|
|
|
expect(res.nestedArrayLocalized[0].array[0].text).toBe('marcelo')
|
|
|
|
expect(res.nestedArrayLocalized[1].array[0].text).toBe('alejandro')
|
|
expect(res.nestedArrayLocalized[1].array[1].text).toBe('raul')
|
|
|
|
expect(res.nestedArrayLocalized[2].array[0].text).toBe('amigo')
|
|
})
|
|
|
|
it('should create with nested array', async () => {
|
|
const subArrayText = 'something expected'
|
|
const doc = await payload.create({
|
|
collection,
|
|
data: {
|
|
items: [
|
|
{
|
|
subArray: [
|
|
{
|
|
text: subArrayText,
|
|
},
|
|
],
|
|
text: 'test',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const result = await payload.findByID({
|
|
id: doc.id,
|
|
collection,
|
|
})
|
|
|
|
expect(result.items[0]).toMatchObject({
|
|
subArray: [
|
|
{
|
|
text: subArrayText,
|
|
},
|
|
],
|
|
text: 'test',
|
|
})
|
|
expect(result.items[0].subArray[0].text).toStrictEqual(subArrayText)
|
|
})
|
|
|
|
it('should update without overwriting other locales with defaultValue', async () => {
|
|
const localized = [{ text: 'unique' }]
|
|
const enText = 'english'
|
|
const esText = 'spanish'
|
|
const { id } = await payload.create({
|
|
collection,
|
|
data: {
|
|
localized,
|
|
},
|
|
})
|
|
|
|
const enDoc = await payload.update({
|
|
id,
|
|
collection,
|
|
data: {
|
|
localized: [{ text: enText }],
|
|
},
|
|
locale: 'en',
|
|
})
|
|
|
|
const esDoc = await payload.update({
|
|
id,
|
|
collection,
|
|
data: {
|
|
localized: [{ text: esText }],
|
|
},
|
|
locale: 'es',
|
|
})
|
|
|
|
const allLocales = (await payload.findByID({
|
|
id,
|
|
collection,
|
|
locale: 'all',
|
|
})) as unknown as {
|
|
localized: {
|
|
en: unknown
|
|
es: unknown
|
|
}
|
|
}
|
|
|
|
expect(enDoc.localized[0].text).toStrictEqual(enText)
|
|
expect(esDoc.localized[0].text).toStrictEqual(esText)
|
|
expect(allLocales.localized.en[0].text).toStrictEqual(enText)
|
|
expect(allLocales.localized.es[0].text).toStrictEqual(esText)
|
|
})
|
|
|
|
it('should query by the same array', async () => {
|
|
const doc = await payload.create({
|
|
collection,
|
|
data: {
|
|
items: [
|
|
{
|
|
localizedText: 'test',
|
|
text: 'required',
|
|
anotherText: 'another',
|
|
},
|
|
],
|
|
localized: [{ text: 'a' }],
|
|
},
|
|
})
|
|
|
|
// left join collection_items + left join collection_items_locales
|
|
const {
|
|
docs: [res],
|
|
} = await payload.find({
|
|
collection,
|
|
where: {
|
|
and: [
|
|
{
|
|
'items.localizedText': {
|
|
equals: 'test',
|
|
},
|
|
},
|
|
{
|
|
'items.anotherText': {
|
|
equals: 'another',
|
|
},
|
|
},
|
|
{
|
|
'items.text': {
|
|
equals: 'required',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
expect(res.id).toBe(doc.id)
|
|
})
|
|
|
|
it('should show proper validation error on text field in nested array', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection,
|
|
data: {
|
|
items: [
|
|
{
|
|
text: 'required',
|
|
subArray: [
|
|
{
|
|
textTwo: '',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Items 1 > Sub Array 1 > Second text field')
|
|
})
|
|
|
|
it('should show proper validation error on text field in row field in nested array', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection,
|
|
data: {
|
|
items: [
|
|
{
|
|
text: 'required',
|
|
subArray: [
|
|
{
|
|
textInRow: '',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Items 1 > Sub Array 1 > Text In Row')
|
|
})
|
|
})
|
|
|
|
describe('group', () => {
|
|
let document
|
|
|
|
beforeEach(async () => {
|
|
document = await payload.create({
|
|
collection: groupFieldsSlug,
|
|
data: {},
|
|
})
|
|
})
|
|
|
|
it('should create with defaultValue', () => {
|
|
expect(document.group.defaultParent).toStrictEqual(groupDefaultValue)
|
|
expect(document.group.defaultChild).toStrictEqual(groupDefaultChild)
|
|
})
|
|
|
|
it('should not have duplicate keys', () => {
|
|
expect(document.arrayOfGroups[0]).toMatchObject({
|
|
id: expect.any(String),
|
|
groupItem: {
|
|
text: 'Hello world',
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should work with unnamed group', async () => {
|
|
const groupDoc = await payload.create({
|
|
collection: groupFieldsSlug,
|
|
data: {
|
|
insideUnnamedGroup: 'Hello world',
|
|
deeplyNestedGroup: { insideNestedUnnamedGroup: 'Secondfield' },
|
|
},
|
|
})
|
|
expect(groupDoc).toMatchObject({
|
|
id: expect.anything(),
|
|
insideUnnamedGroup: 'Hello world',
|
|
deeplyNestedGroup: {
|
|
insideNestedUnnamedGroup: 'Secondfield',
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should work with unnamed group - graphql', async () => {
|
|
const mutation = `mutation {
|
|
createGroupField(
|
|
data: {
|
|
insideUnnamedGroup: "Hello world",
|
|
deeplyNestedGroup: { insideNestedUnnamedGroup: "Secondfield" },
|
|
group: {text: "hello"}
|
|
}
|
|
) {
|
|
insideUnnamedGroup
|
|
deeplyNestedGroup {
|
|
insideNestedUnnamedGroup
|
|
}
|
|
}
|
|
}`
|
|
|
|
const groupDoc = await restClient.GRAPHQL_POST({
|
|
body: JSON.stringify({ query: mutation }),
|
|
})
|
|
|
|
const data = (await groupDoc.json()).data.createGroupField
|
|
|
|
expect(data).toMatchObject({
|
|
insideUnnamedGroup: 'Hello world',
|
|
deeplyNestedGroup: {
|
|
insideNestedUnnamedGroup: 'Secondfield',
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should query a subfield within a localized group', async () => {
|
|
const text = 'find this'
|
|
const hit = await payload.create({
|
|
collection: groupFieldsSlug,
|
|
data: {
|
|
localizedGroup: {
|
|
text,
|
|
},
|
|
},
|
|
})
|
|
const miss = await payload.create({
|
|
collection: groupFieldsSlug,
|
|
data: {
|
|
localizedGroup: {
|
|
text: 'do not find this',
|
|
},
|
|
},
|
|
})
|
|
const result = await payload.find({
|
|
collection: groupFieldsSlug,
|
|
where: {
|
|
'localizedGroup.text': { equals: text },
|
|
},
|
|
})
|
|
|
|
const resultIDs = result.docs.map(({ id }) => id)
|
|
|
|
expect(resultIDs).toContain(hit.id)
|
|
expect(resultIDs).not.toContain(miss.id)
|
|
})
|
|
|
|
it('should insert/read camelCase group with nested arrays + localized', async () => {
|
|
const res = await payload.create({
|
|
collection: 'group-fields',
|
|
data: {
|
|
group: { text: 'required' },
|
|
camelCaseGroup: {
|
|
array: [
|
|
{
|
|
text: 'text',
|
|
array: [
|
|
{
|
|
text: 'nested',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(res.camelCaseGroup.array[0].text).toBe('text')
|
|
expect(res.camelCaseGroup.array[0].array[0].text).toBe('nested')
|
|
})
|
|
|
|
it('should insert/update/read localized group with array inside', async () => {
|
|
const doc = await payload.create({
|
|
collection: 'group-fields',
|
|
locale: 'en',
|
|
data: {
|
|
group: { text: 'req' },
|
|
localizedGroupArr: {
|
|
array: [{ text: 'text-en' }],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(doc.localizedGroupArr.array[0].text).toBe('text-en')
|
|
|
|
const esDoc = await payload.update({
|
|
collection: 'group-fields',
|
|
locale: 'es',
|
|
id: doc.id,
|
|
data: {
|
|
localizedGroupArr: {
|
|
array: [{ text: 'text-es' }],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(esDoc.localizedGroupArr.array[0].text).toBe('text-es')
|
|
|
|
const allDoc = await payload.findByID({
|
|
collection: 'group-fields',
|
|
id: doc.id,
|
|
locale: 'all',
|
|
})
|
|
|
|
expect(allDoc.localizedGroupArr.en.array[0].text).toBe('text-en')
|
|
expect(allDoc.localizedGroupArr.es.array[0].text).toBe('text-es')
|
|
})
|
|
|
|
it('should insert/update/read localized group with select hasMany inside', async () => {
|
|
const doc = await payload.create({
|
|
collection: 'group-fields',
|
|
locale: 'en',
|
|
data: {
|
|
group: { text: 'req' },
|
|
localizedGroupSelect: {
|
|
select: ['one', 'two'],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(doc.localizedGroupSelect.select).toStrictEqual(['one', 'two'])
|
|
|
|
const esDoc = await payload.update({
|
|
collection: 'group-fields',
|
|
locale: 'es',
|
|
id: doc.id,
|
|
data: {
|
|
localizedGroupSelect: {
|
|
select: ['one'],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(esDoc.localizedGroupSelect.select).toStrictEqual(['one'])
|
|
|
|
const allDoc = await payload.findByID({
|
|
collection: 'group-fields',
|
|
id: doc.id,
|
|
locale: 'all',
|
|
})
|
|
|
|
expect(allDoc.localizedGroupSelect.en.select).toStrictEqual(['one', 'two'])
|
|
expect(allDoc.localizedGroupSelect.es.select).toStrictEqual(['one'])
|
|
})
|
|
|
|
it('should insert/update/read localized group with relationship inside', async () => {
|
|
const rel_1 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'pro123@gmail.com' },
|
|
})
|
|
|
|
const rel_2 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'frank@gmail.com' },
|
|
})
|
|
|
|
const doc = await payload.create({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
data: {
|
|
group: { text: 'requireddd' },
|
|
localizedGroupRel: {
|
|
email: rel_1.id,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(doc.localizedGroupRel.email).toBe(rel_1.id)
|
|
|
|
const upd = await payload.update({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
id: doc.id,
|
|
locale: 'es',
|
|
data: {
|
|
localizedGroupRel: {
|
|
email: rel_2.id,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(upd.localizedGroupRel.email).toBe(rel_2.id)
|
|
|
|
const docAll = await payload.findByID({
|
|
collection: 'group-fields',
|
|
id: doc.id,
|
|
locale: 'all',
|
|
depth: 0,
|
|
})
|
|
|
|
expect(docAll.localizedGroupRel.en.email).toBe(rel_1.id)
|
|
expect(docAll.localizedGroupRel.es.email).toBe(rel_2.id)
|
|
})
|
|
|
|
it('should insert/update/read localized group with hasMany relationship inside', async () => {
|
|
const rel_1 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'pro123@gmail.com' },
|
|
})
|
|
|
|
const rel_2 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'frank@gmail.com' },
|
|
})
|
|
|
|
const doc = await payload.create({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
data: {
|
|
group: { text: 'requireddd' },
|
|
localizedGroupManyRel: {
|
|
email: [rel_1.id],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(doc.localizedGroupManyRel.email).toStrictEqual([rel_1.id])
|
|
|
|
const upd = await payload.update({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
id: doc.id,
|
|
locale: 'es',
|
|
data: {
|
|
localizedGroupManyRel: {
|
|
email: [rel_2.id],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(upd.localizedGroupManyRel.email).toStrictEqual([rel_2.id])
|
|
|
|
const docAll = await payload.findByID({
|
|
collection: 'group-fields',
|
|
id: doc.id,
|
|
locale: 'all',
|
|
depth: 0,
|
|
})
|
|
|
|
expect(docAll.localizedGroupManyRel.en.email).toStrictEqual([rel_1.id])
|
|
expect(docAll.localizedGroupManyRel.es.email).toStrictEqual([rel_2.id])
|
|
})
|
|
|
|
it('should insert/update/read localized group with poly relationship inside', async () => {
|
|
const rel_1 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'pro123@gmail.com' },
|
|
})
|
|
|
|
const rel_2 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'frank@gmail.com' },
|
|
})
|
|
|
|
const doc = await payload.create({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
data: {
|
|
group: { text: 'requireddd' },
|
|
localizedGroupPolyRel: {
|
|
email: {
|
|
relationTo: 'email-fields',
|
|
value: rel_1.id,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(doc.localizedGroupPolyRel.email).toStrictEqual({
|
|
relationTo: 'email-fields',
|
|
value: rel_1.id,
|
|
})
|
|
|
|
const upd = await payload.update({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
id: doc.id,
|
|
locale: 'es',
|
|
data: {
|
|
localizedGroupPolyRel: {
|
|
email: {
|
|
value: rel_2.id,
|
|
relationTo: 'email-fields',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(upd.localizedGroupPolyRel.email).toStrictEqual({
|
|
value: rel_2.id,
|
|
relationTo: 'email-fields',
|
|
})
|
|
|
|
const docAll = await payload.findByID({
|
|
collection: 'group-fields',
|
|
id: doc.id,
|
|
locale: 'all',
|
|
depth: 0,
|
|
})
|
|
|
|
expect(docAll.localizedGroupPolyRel.en.email).toStrictEqual({
|
|
value: rel_1.id,
|
|
relationTo: 'email-fields',
|
|
})
|
|
expect(docAll.localizedGroupPolyRel.es.email).toStrictEqual({
|
|
value: rel_2.id,
|
|
relationTo: 'email-fields',
|
|
})
|
|
})
|
|
|
|
it('should insert/update/read localized group with poly hasMany relationship inside', async () => {
|
|
const rel_1 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'pro123@gmail.com' },
|
|
})
|
|
|
|
const rel_2 = await payload.create({
|
|
collection: 'email-fields',
|
|
data: { email: 'frank@gmail.com' },
|
|
})
|
|
|
|
const doc = await payload.create({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
data: {
|
|
group: { text: 'requireddd' },
|
|
localizedGroupPolyHasManyRel: {
|
|
email: [
|
|
{
|
|
relationTo: 'email-fields',
|
|
value: rel_1.id,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(doc.localizedGroupPolyHasManyRel.email).toStrictEqual([
|
|
{
|
|
relationTo: 'email-fields',
|
|
value: rel_1.id,
|
|
},
|
|
])
|
|
|
|
const upd = await payload.update({
|
|
collection: 'group-fields',
|
|
depth: 0,
|
|
id: doc.id,
|
|
locale: 'es',
|
|
data: {
|
|
localizedGroupPolyHasManyRel: {
|
|
email: [
|
|
{
|
|
value: rel_2.id,
|
|
relationTo: 'email-fields',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(upd.localizedGroupPolyHasManyRel.email).toStrictEqual([
|
|
{
|
|
value: rel_2.id,
|
|
relationTo: 'email-fields',
|
|
},
|
|
])
|
|
|
|
const docAll = await payload.findByID({
|
|
collection: 'group-fields',
|
|
id: doc.id,
|
|
locale: 'all',
|
|
depth: 0,
|
|
})
|
|
|
|
expect(docAll.localizedGroupPolyHasManyRel.en.email).toStrictEqual([
|
|
{
|
|
value: rel_1.id,
|
|
relationTo: 'email-fields',
|
|
},
|
|
])
|
|
expect(docAll.localizedGroupPolyHasManyRel.es.email).toStrictEqual([
|
|
{
|
|
value: rel_2.id,
|
|
relationTo: 'email-fields',
|
|
},
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('tabs', () => {
|
|
let document
|
|
|
|
beforeEach(async () => {
|
|
document = await payload.create({
|
|
collection: tabsFieldsSlug,
|
|
data: tabsDoc,
|
|
})
|
|
})
|
|
|
|
it('should hot module reload and still be able to create', async () => {
|
|
const testDoc1 = await payload.findByID({
|
|
id: document.id,
|
|
collection: tabsFieldsSlug,
|
|
})
|
|
|
|
await reload(payload.config, payload, true)
|
|
|
|
const testDoc2 = await payload.findByID({
|
|
id: document.id,
|
|
collection: tabsFieldsSlug,
|
|
})
|
|
|
|
expect(testDoc1.id).toStrictEqual(testDoc2.id)
|
|
})
|
|
|
|
it('should create with fields inside a named tab', () => {
|
|
expect(document.tab.text).toStrictEqual(namedTabText)
|
|
})
|
|
|
|
it('should create with defaultValue inside a named tab', () => {
|
|
expect(document.tab.defaultValue).toStrictEqual(namedTabDefaultValue)
|
|
})
|
|
|
|
it('should create with defaultValue inside a named tab with no other values', () => {
|
|
expect(document.namedTabWithDefaultValue.defaultValue).toStrictEqual(namedTabDefaultValue)
|
|
})
|
|
|
|
it('should create with localized text inside a named tab', async () => {
|
|
document = await payload.findByID({
|
|
id: document.id,
|
|
collection: tabsFieldsSlug,
|
|
locale: 'all',
|
|
})
|
|
expect(document.localizedTab.en.text).toStrictEqual(localizedTextValue)
|
|
})
|
|
|
|
it('should allow access control on a named tab', async () => {
|
|
document = await payload.findByID({
|
|
id: document.id,
|
|
collection: tabsFieldsSlug,
|
|
overrideAccess: false,
|
|
})
|
|
expect(document.accessControlTab).toBeUndefined()
|
|
})
|
|
|
|
it('should allow hooks on a named tab', async () => {
|
|
const newDocument = await payload.create({
|
|
collection: tabsFieldsSlug,
|
|
data: tabsDoc,
|
|
})
|
|
expect(newDocument.hooksTab.beforeValidate).toBe(true)
|
|
expect(newDocument.hooksTab.beforeChange).toBe(true)
|
|
expect(newDocument.hooksTab.afterChange).toBe(true)
|
|
expect(newDocument.hooksTab.afterRead).toBe(true)
|
|
})
|
|
|
|
it('should return empty object for groups when no data present', async () => {
|
|
const doc = await payload.create({
|
|
collection: groupFieldsSlug,
|
|
data: namedGroupDoc,
|
|
})
|
|
|
|
expect(doc.potentiallyEmptyGroup).toBeDefined()
|
|
})
|
|
|
|
it('should insert/read camelCase tab with nested arrays + localized', async () => {
|
|
const res = await payload.create({
|
|
collection: 'tabs-fields',
|
|
data: {
|
|
anotherText: 'req',
|
|
array: [{ text: 'req' }],
|
|
blocks: [{ blockType: 'content', text: 'req' }],
|
|
group: { number: 1 },
|
|
numberInRow: 1,
|
|
textInRow: 'req',
|
|
tab: { array: [{ text: 'req' }] },
|
|
|
|
camelCaseTab: {
|
|
array: [
|
|
{
|
|
text: 'text',
|
|
array: [
|
|
{
|
|
text: 'nested',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(res.camelCaseTab.array[0].text).toBe('text')
|
|
expect(res.camelCaseTab.array[0].array[0].text).toBe('nested')
|
|
})
|
|
|
|
it('should show proper validation error message on text field within array within tab', async () => {
|
|
await expect(async () =>
|
|
payload.update({
|
|
id: document.id,
|
|
collection: tabsFieldsSlug,
|
|
data: {
|
|
array: [
|
|
{
|
|
text: 'one',
|
|
},
|
|
{
|
|
text: 'two',
|
|
},
|
|
{
|
|
text: '',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Tab with Array > Array 3 > Text')
|
|
})
|
|
})
|
|
|
|
describe('blocks', () => {
|
|
it('should retrieve doc with blocks', async () => {
|
|
const blockFields = await payload.find({
|
|
collection: 'block-fields',
|
|
})
|
|
|
|
expect(blockFields.docs[0].blocks[0].blockType).toEqual(blocksDoc.blocks[0].blockType)
|
|
expect(blockFields.docs[0].blocks[0].text).toEqual(blocksDoc.blocks[0].text)
|
|
|
|
expect(blockFields.docs[0].blocks[2].blockType).toEqual(blocksDoc.blocks[2].blockType)
|
|
expect(blockFields.docs[0].blocks[2].blockName).toEqual(blocksDoc.blocks[2].blockName)
|
|
expect(blockFields.docs[0].blocks[2].subBlocks[0].number).toEqual(
|
|
blocksDoc.blocks[2].subBlocks[0].number,
|
|
)
|
|
expect(blockFields.docs[0].blocks[2].subBlocks[1].text).toEqual(
|
|
blocksDoc.blocks[2].subBlocks[1].text,
|
|
)
|
|
})
|
|
|
|
it('should query based on richtext data within a block', async () => {
|
|
const blockFieldsSuccess = await payload.find({
|
|
collection: 'block-fields',
|
|
where: {
|
|
'blocks.richText.children.text': {
|
|
like: 'fun',
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(blockFieldsSuccess.docs).toHaveLength(1)
|
|
|
|
const blockFieldsFail = await payload.find({
|
|
collection: 'block-fields',
|
|
where: {
|
|
'blocks.richText.children.text': {
|
|
like: 'funny',
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(blockFieldsFail.docs).toHaveLength(0)
|
|
})
|
|
|
|
it('should query based on richtext data within a localized block, specifying locale', async () => {
|
|
const blockFieldsSuccess = await payload.find({
|
|
collection: 'block-fields',
|
|
where: {
|
|
'localizedBlocks.en.richText.children.text': {
|
|
like: 'fun',
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(blockFieldsSuccess.docs).toHaveLength(1)
|
|
|
|
const blockFieldsFail = await payload.find({
|
|
collection: 'block-fields',
|
|
where: {
|
|
'localizedBlocks.en.richText.children.text': {
|
|
like: 'funny',
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(blockFieldsFail.docs).toHaveLength(0)
|
|
})
|
|
|
|
it('should query based on richtext data within a localized block, without specifying locale', async () => {
|
|
const blockFieldsSuccess = await payload.find({
|
|
collection: 'block-fields',
|
|
where: {
|
|
'localizedBlocks.richText.children.text': {
|
|
like: 'fun',
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(blockFieldsSuccess.docs).toHaveLength(1)
|
|
|
|
const blockFieldsFail = await payload.find({
|
|
collection: 'block-fields',
|
|
where: {
|
|
'localizedBlocks.richText.children.text': {
|
|
like: 'funny',
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(blockFieldsFail.docs).toHaveLength(0)
|
|
})
|
|
|
|
it('should filter based on nested block fields', async () => {
|
|
await payload.create({
|
|
collection: 'block-fields',
|
|
data: {
|
|
blocks: [
|
|
{
|
|
blockType: 'content',
|
|
text: 'green',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
await payload.create({
|
|
collection: 'block-fields',
|
|
data: {
|
|
blocks: [
|
|
{
|
|
blockType: 'content',
|
|
text: 'pink',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
await payload.create({
|
|
collection: 'block-fields',
|
|
data: {
|
|
blocks: [
|
|
{
|
|
blockType: 'content',
|
|
text: 'green',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const blockFields = await payload.find({
|
|
collection: 'block-fields',
|
|
overrideAccess: false,
|
|
user,
|
|
where: {
|
|
and: [
|
|
{
|
|
'blocks.text': {
|
|
equals: 'green',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const { docs } = blockFields
|
|
expect(docs).toHaveLength(2)
|
|
})
|
|
|
|
it('should query blocks with nested relationship', async () => {
|
|
const textDoc = await payload.create({
|
|
collection: textFieldsSlug,
|
|
data: {
|
|
text: 'test',
|
|
},
|
|
})
|
|
const blockDoc = await payload.create({
|
|
collection: blockFieldsSlug,
|
|
data: {
|
|
relationshipBlocks: [
|
|
{
|
|
blockType: 'relationships',
|
|
relationship: textDoc.id,
|
|
},
|
|
],
|
|
},
|
|
})
|
|
const result = await payload.find({
|
|
collection: blockFieldsSlug,
|
|
where: {
|
|
'relationshipBlocks.relationship': { equals: textDoc.id },
|
|
},
|
|
})
|
|
|
|
expect(result.docs).toHaveLength(1)
|
|
expect(result.docs[0]).toMatchObject(blockDoc)
|
|
})
|
|
|
|
it('should query by blockType', async () => {
|
|
const text = 'blockType query test'
|
|
|
|
const hit = await payload.create({
|
|
collection: blockFieldsSlug,
|
|
data: {
|
|
blocks: [
|
|
{
|
|
blockType: 'content',
|
|
text,
|
|
},
|
|
],
|
|
},
|
|
})
|
|
const miss = await payload.create({
|
|
collection: blockFieldsSlug,
|
|
data: {
|
|
blocks: [
|
|
{
|
|
blockType: 'number',
|
|
number: 5,
|
|
},
|
|
],
|
|
duplicate: [
|
|
{
|
|
blockType: 'content',
|
|
text,
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const { docs: equalsDocs } = await payload.find({
|
|
collection: blockFieldsSlug,
|
|
where: {
|
|
and: [
|
|
{
|
|
'blocks.blockType': { equals: 'content' },
|
|
},
|
|
{
|
|
'blocks.text': { equals: text },
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const { docs: inDocs } = await payload.find({
|
|
collection: blockFieldsSlug,
|
|
where: {
|
|
'blocks.blockType': { in: ['content'] },
|
|
},
|
|
})
|
|
|
|
const equalsHitResult = equalsDocs.find(({ id }) => id === hit.id)
|
|
const inHitResult = inDocs.find(({ id }) => id === hit.id)
|
|
const equalsMissResult = equalsDocs.find(({ id }) => id === miss.id)
|
|
const inMissResult = inDocs.find(({ id }) => id === miss.id)
|
|
|
|
expect(equalsHitResult.id).toStrictEqual(hit.id)
|
|
expect(inHitResult.id).toStrictEqual(hit.id)
|
|
expect(equalsMissResult).toBeUndefined()
|
|
expect(inMissResult).toBeUndefined()
|
|
})
|
|
|
|
it('should allow localized array of blocks', async () => {
|
|
const result = await payload.create({
|
|
collection: blockFieldsSlug,
|
|
data: {
|
|
blocksWithLocalizedArray: [
|
|
{
|
|
blockType: 'localizedArray',
|
|
array: [
|
|
{
|
|
text: 'localized',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
expect(result.blocksWithLocalizedArray[0].array[0].text).toEqual('localized')
|
|
})
|
|
|
|
it('ensure localized field within block reference is saved correctly', async () => {
|
|
const blockFields = await payload.find({
|
|
collection: 'block-fields',
|
|
locale: 'all',
|
|
})
|
|
|
|
const doc: BlockField = blockFields.docs[0] as BlockField
|
|
|
|
expect(doc?.localizedReferences?.[0]?.blockType).toEqual('localizedTextReference2')
|
|
expect(doc?.localizedReferences?.[0]?.text).toEqual({ en: 'localized text' })
|
|
})
|
|
|
|
it('ensure localized property is stripped from localized field within localized block reference', async () => {
|
|
const blockFields = await payload.find({
|
|
collection: 'block-fields',
|
|
locale: 'all',
|
|
})
|
|
|
|
const doc: any = blockFields.docs[0]
|
|
|
|
expect(doc?.localizedReferencesLocalizedBlock?.en?.[0]?.blockType).toEqual(
|
|
'localizedTextReference',
|
|
)
|
|
expect(doc?.localizedReferencesLocalizedBlock?.en?.[0]?.text).toEqual('localized text')
|
|
})
|
|
})
|
|
|
|
describe('collapsible', () => {
|
|
it('should show proper validation error message for fields nested in collapsible', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: collapsibleFieldsSlug,
|
|
data: {
|
|
text: 'required',
|
|
group: {
|
|
subGroup: {
|
|
requiredTextWithinSubGroup: '',
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
).rejects.toThrow(
|
|
'The following field is invalid: Collapsible Field > Group > Sub Group > Required Text Within Sub Group',
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('json', () => {
|
|
it('should save json data', async () => {
|
|
const json = { foo: 'bar' }
|
|
const doc = await payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json,
|
|
},
|
|
})
|
|
|
|
expect(doc.json).toStrictEqual({ foo: 'bar' })
|
|
})
|
|
|
|
it('should validate json', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: '{ bad input: true }',
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Json')
|
|
})
|
|
|
|
it('should validate json schema', async () => {
|
|
await expect(async () =>
|
|
payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: { foo: 'bad' },
|
|
},
|
|
}),
|
|
).rejects.toThrow('The following field is invalid: Json')
|
|
})
|
|
|
|
it('should save empty json objects', async () => {
|
|
const jsonFieldsDoc = await payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: {
|
|
state: {},
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(jsonFieldsDoc.json.state).toEqual({})
|
|
|
|
const updatedJsonFieldsDoc = await payload.update({
|
|
id: jsonFieldsDoc.id,
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: {
|
|
state: {},
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(updatedJsonFieldsDoc.json.state).toEqual({})
|
|
})
|
|
|
|
describe('querying', () => {
|
|
let fooBar
|
|
let bazBar
|
|
|
|
beforeEach(async () => {
|
|
fooBar = await payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: { foo: 'foobar', number: 5 },
|
|
},
|
|
})
|
|
bazBar = await payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: { baz: 'bar', number: 10 },
|
|
},
|
|
})
|
|
|
|
// Create content for array 'in' and 'not_in' queries
|
|
for (let i = 1; i < 6; i++) {
|
|
await payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: { value: i },
|
|
},
|
|
})
|
|
}
|
|
})
|
|
|
|
it('should query nested properties - like', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.foo': { like: 'bar' },
|
|
},
|
|
})
|
|
|
|
const docIDs = docs.map(({ id }) => id)
|
|
|
|
expect(docIDs).toContain(fooBar.id)
|
|
expect(docIDs).not.toContain(bazBar.id)
|
|
})
|
|
|
|
it('should query nested properties - not_like', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.baz': { not_like: 'bar' },
|
|
},
|
|
})
|
|
|
|
const docIDs = docs.map(({ id }) => id)
|
|
|
|
expect(docIDs).toContain(fooBar.id)
|
|
expect(docIDs).not.toContain(bazBar.id)
|
|
})
|
|
|
|
it('should query nested properties - equals', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.foo': { equals: 'foobar' },
|
|
},
|
|
})
|
|
|
|
const notEquals = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.foo': { equals: 'bar' },
|
|
},
|
|
})
|
|
|
|
const docIDs = docs.map(({ id }) => id)
|
|
|
|
expect(docIDs).toContain(fooBar.id)
|
|
expect(docIDs).not.toContain(bazBar.id)
|
|
expect(notEquals.docs).toHaveLength(0)
|
|
})
|
|
|
|
it('should query nested numbers - equals', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.number': { equals: 5 },
|
|
},
|
|
})
|
|
|
|
const docIDs = docs.map(({ id }) => id)
|
|
|
|
expect(docIDs).toContain(fooBar.id)
|
|
expect(docIDs).not.toContain(bazBar.id)
|
|
})
|
|
|
|
it('should query nested properties - exists', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.foo': { exists: true },
|
|
},
|
|
})
|
|
|
|
const docIDs = docs.map(({ id }) => id)
|
|
|
|
expect(docIDs).toContain(fooBar.id)
|
|
expect(docIDs).not.toContain(bazBar.id)
|
|
})
|
|
|
|
it('should query - exists', async () => {
|
|
const nullJSON = await payload.create({
|
|
collection: 'json-fields',
|
|
data: {},
|
|
})
|
|
const hasJSON = await payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: [],
|
|
},
|
|
})
|
|
|
|
const docsExistsFalse = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
json: { exists: false },
|
|
},
|
|
})
|
|
const docsExistsTrue = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
json: { exists: true },
|
|
},
|
|
})
|
|
|
|
const existFalseIDs = docsExistsFalse.docs.map(({ id }) => id)
|
|
const existTrueIDs = docsExistsTrue.docs.map(({ id }) => id)
|
|
|
|
expect(existFalseIDs).toContain(nullJSON.id)
|
|
expect(existTrueIDs).not.toContain(nullJSON.id)
|
|
|
|
expect(existTrueIDs).toContain(hasJSON.id)
|
|
expect(existFalseIDs).not.toContain(hasJSON.id)
|
|
})
|
|
|
|
it('exists should not return null values', async () => {
|
|
const { id } = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
select: 'one',
|
|
},
|
|
})
|
|
|
|
const existsResult = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: true },
|
|
},
|
|
})
|
|
|
|
expect(existsResult.docs).toHaveLength(1)
|
|
|
|
const existsFalseResult = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: false },
|
|
},
|
|
})
|
|
|
|
expect(existsFalseResult.docs).toHaveLength(0)
|
|
|
|
await payload.update({
|
|
id,
|
|
collection: 'select-fields',
|
|
data: {
|
|
select: null,
|
|
},
|
|
})
|
|
|
|
const existsTrueResult = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: true },
|
|
},
|
|
})
|
|
|
|
expect(existsTrueResult.docs).toHaveLength(0)
|
|
|
|
const result = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: false },
|
|
},
|
|
})
|
|
|
|
expect(result.docs).toHaveLength(1)
|
|
})
|
|
|
|
it('should query nested numbers - in', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.value': { in: [1, 3] },
|
|
},
|
|
})
|
|
|
|
const docIDs = docs.map(({ json }) => json.value)
|
|
|
|
expect(docIDs).toContain(1)
|
|
expect(docIDs).toContain(3)
|
|
expect(docIDs).not.toContain(2)
|
|
})
|
|
|
|
it('should query nested numbers - not_in', async () => {
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
'json.value': { not_in: [1, 3] },
|
|
},
|
|
})
|
|
|
|
const docIDs = docs.map(({ json }) => json.value)
|
|
|
|
expect(docIDs).not.toContain(1)
|
|
expect(docIDs).not.toContain(3)
|
|
expect(docIDs).toContain(2)
|
|
})
|
|
|
|
it('should query deeply', async () => {
|
|
// eslint-disable-next-line jest/no-conditional-in-test
|
|
if (payload.db.name === 'sqlite') {
|
|
return
|
|
}
|
|
|
|
const json_1 = await payload.create({
|
|
collection: 'json-fields',
|
|
data: {
|
|
json: {
|
|
array: [
|
|
{
|
|
text: 'some-text',
|
|
object: {
|
|
text: 'deep-text',
|
|
array: [10],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
})
|
|
|
|
const { docs } = await payload.find({
|
|
collection: 'json-fields',
|
|
where: {
|
|
and: [
|
|
{
|
|
'json.array.text': {
|
|
equals: 'some-text',
|
|
},
|
|
},
|
|
{
|
|
'json.array.object.text': {
|
|
equals: 'deep-text',
|
|
},
|
|
},
|
|
{
|
|
'json.array.object.array': {
|
|
in: [10, 20],
|
|
},
|
|
},
|
|
{
|
|
'json.array.object.array': {
|
|
exists: true,
|
|
},
|
|
},
|
|
{
|
|
'json.array.object.notexists': {
|
|
exists: false,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
expect(docs).toHaveLength(1)
|
|
expect(docs[0].id).toBe(json_1.id)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('relationships', () => {
|
|
it('should not crash if querying with empty in operator', async () => {
|
|
const query = await payload.find({
|
|
collection: 'relationship-fields',
|
|
where: {
|
|
'relationship.value': {
|
|
in: [],
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(query.docs).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('clearable fields - exists', () => {
|
|
it('exists should not return null values', async () => {
|
|
const { id } = await payload.create({
|
|
collection: 'select-fields',
|
|
data: {
|
|
select: 'one',
|
|
},
|
|
})
|
|
|
|
const existsResult = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: true },
|
|
},
|
|
})
|
|
|
|
expect(existsResult.docs).toHaveLength(1)
|
|
|
|
const existsFalseResult = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: false },
|
|
},
|
|
})
|
|
|
|
expect(existsFalseResult.docs).toHaveLength(0)
|
|
|
|
await payload.update({
|
|
id,
|
|
collection: 'select-fields',
|
|
data: {
|
|
select: null,
|
|
},
|
|
})
|
|
|
|
const existsTrueResult = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: true },
|
|
},
|
|
})
|
|
|
|
expect(existsTrueResult.docs).toHaveLength(0)
|
|
|
|
const result = await payload.find({
|
|
collection: 'select-fields',
|
|
where: {
|
|
id: { equals: id },
|
|
select: { exists: false },
|
|
},
|
|
})
|
|
|
|
expect(result.docs).toHaveLength(1)
|
|
})
|
|
})
|
|
})
|