# Breaking Changes
### New file import locations
Exports from the `payload` package have been _significantly_ cleaned up.
Now, just about everything is able to be imported from `payload`
directly, rather than an assortment of subpath exports. This means that
things like `import { buildConfig } from 'payload/config'` are now just
imported via `import { buildConfig } from 'payload'`. The mental model
is significantly simpler for developers, but you might need to update
some of your imports.
Payload now exposes only three exports:
1. `payload` - all types and server-only Payload code
2. `payload/shared` - utilities that can be used in either the browser
or in Node environments
3. `payload/node` - heavy utilities that should only be imported in Node
scripts and never be imported into bundled code like Next.js
### UI library pre-bundling
With this release, we've dramatically sped up the compile time for
Payload by pre-bundling our entire UI package for use inside of the
Payload admin itself. There are new exports that should be used within
Payload custom components:
1. `@payloadcms/ui/client` - all client components
2. `@payloadcms/ui/server` - all server components
For all of your custom Payload admin UI components, you should be
importing from one of these two pre-compiled barrel files rather than
importing from the more deeply nested exports directly. That will keep
compile times nice and speedy, and will also make sure that the bundled
JS for your admin UI is kept small.
For example, whereas before, if you imported the Payload `Button`, you
would have imported it like this:
```ts
import { Button } from '@payloadcms/ui/elements/Button'
```
Now, you would import it like this:
```ts
import { Button } from '@payloadcms/ui/client'
```
This is a significant DX / performance optimization that we're pretty
pumped about.
However, if you are importing or re-using Payload UI components
_outside_ of the Payload admin UI, for example in your own frontend
apps, you can import from the individual component exports which will
make sure that the bundled JS is kept to a minimum in your frontend
apps. So in your own frontend, you can continue to import directly to
the components that you want to consume rather than importing from the
pre-compiled barrel files.
Individual component exports will now come with their corresponding CSS
and everything will work perfectly as-expected.
### Specific exports have changed
- `'@payloadcms/ui/templates/Default'` and
`'@payloadcms/ui/templates/Minimal`' are now exported from
`'@payloadcms/next/templates'`
- Old: `import { LogOut } from '@payloadcms/ui/icons/LogOut'` new:
`import { LogOutIcon } from '@payloadcms/ui/icons/LogOut'`
## Background info
In effort to make local dev as fast as possible, we need to import as
few files as possible so that the compiler has less to process. One way
we've achieved this in the Admin Panel was to _remove_ all .scss imports
from all components in the `@payloadcms/ui` module using a build
process. This stripped all `import './index.scss'` statements out of
each component before injecting them into `dist`. Instead, it bundles
all of the CSS into a single `main.css` file, and we import _that_ at
the root of the app.
While this concept is _still_ the right solution to the problem, this
particular approach is not viable when using these components outside
the Admin Panel, where not only does this root stylesheet not exist, but
where it would also bloat your app with unused styles. Instead, we need
to _keep_ these .scss imports in place so they are imported directly
alongside your components, as expected. Then, we need create a _new_
build step that _separately_ compiles the components _without_ their
stylesheets—this way your app can consume either as needed from the new
`client` and `server` barrel files within `@payloadcms/ui`, i.e. from
within `@payloadcms/next` and all other admin-specific packages and
plugins.
This way, all other applications will simply import using the direct
file paths, just as they did before. Except now they come with
stylesheets.
And we've gotten a pretty awesome initial compilation performance boost.
---------
Co-authored-by: James <james@trbl.design>
Co-authored-by: Alessio Gravili <alessio@gravili.de>
1536 lines
41 KiB
TypeScript
1536 lines
41 KiB
TypeScript
import type { Payload } from 'payload'
|
|
|
|
import { ValidationError } from 'payload'
|
|
|
|
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
|
|
|
|
import { devUser } from '../credentials.js'
|
|
import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
|
import { clearAndSeedEverything } from './clearAndSeedEverything.js'
|
|
import AutosavePosts from './collections/Autosave.js'
|
|
import configPromise from './config.js'
|
|
import AutosaveGlobal from './globals/Autosave.js'
|
|
import { autosaveCollectionSlug, draftCollectionSlug } from './slugs.js'
|
|
|
|
let payload: Payload
|
|
let restClient: NextRESTClient
|
|
|
|
let collectionLocalPostID: string
|
|
let collectionLocalVersionID
|
|
|
|
let token
|
|
|
|
let collectionGraphQLPostID
|
|
let collectionGraphQLVersionID
|
|
const collectionGraphQLOriginalTitle = 'autosave title'
|
|
|
|
const collection = AutosavePosts.slug
|
|
const globalSlug = AutosaveGlobal.slug
|
|
|
|
let globalLocalVersionID
|
|
let globalGraphQLVersionID
|
|
const globalGraphQLOriginalTitle = 'updated global title'
|
|
const updatedTitle = 'Here is an updated post title in EN'
|
|
|
|
const formatGraphQLID = (id: number | string) =>
|
|
payload.db.defaultIDType === 'number' ? id : `"${id}"`
|
|
|
|
describe('Versions', () => {
|
|
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(configPromise))
|
|
})
|
|
|
|
afterAll(async () => {
|
|
if (typeof payload.db.destroy === 'function') {
|
|
await payload.db.destroy()
|
|
}
|
|
})
|
|
|
|
beforeEach(async () => {
|
|
await clearAndSeedEverything(payload)
|
|
|
|
const login = `
|
|
mutation {
|
|
loginUser(
|
|
email: "${devUser.email}",
|
|
password: "${devUser.password}"
|
|
) {
|
|
token
|
|
}
|
|
}`
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({ body: JSON.stringify({ query: login }) })
|
|
.then((res) => res.json())
|
|
|
|
token = data.loginUser.token
|
|
|
|
// now: initialize
|
|
const autosavePost = await payload.create({
|
|
collection,
|
|
data: {
|
|
description: '345j23o4ifj34jf54g',
|
|
title: 'Here is an autosave post in EN',
|
|
},
|
|
})
|
|
collectionLocalPostID = autosavePost.id
|
|
|
|
await payload.update({
|
|
id: collectionLocalPostID,
|
|
collection,
|
|
data: {
|
|
title: updatedTitle,
|
|
},
|
|
})
|
|
|
|
const versions = await payload.findVersions({
|
|
collection,
|
|
})
|
|
|
|
collectionLocalVersionID = versions.docs[0].id
|
|
})
|
|
|
|
describe('Collections - Local', () => {
|
|
describe('Create', () => {
|
|
it('should allow creating a draft with missing required field data', async () => {
|
|
const draft = await payload.create({
|
|
collection: autosaveCollectionSlug,
|
|
data: {
|
|
description: undefined,
|
|
title: 'i have a title',
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
expect(draft.id).toBeDefined()
|
|
})
|
|
|
|
it('should allow a new version to be created and updated', async () => {
|
|
const updatedPost = await payload.findByID({
|
|
id: collectionLocalPostID,
|
|
collection,
|
|
})
|
|
expect(updatedPost.title).toBe(updatedTitle)
|
|
expect(updatedPost._status).toStrictEqual('draft')
|
|
expect(collectionLocalVersionID).toBeDefined()
|
|
})
|
|
|
|
it('should paginate versions', async () => {
|
|
const versions = await payload.findVersions({
|
|
collection: draftCollectionSlug,
|
|
limit: 5,
|
|
})
|
|
const versionsPage2 = await payload.findVersions({
|
|
collection: draftCollectionSlug,
|
|
limit: 5,
|
|
page: 2,
|
|
})
|
|
|
|
expect(versions.docs).toHaveLength(5)
|
|
expect(versions.page).toBe(1)
|
|
expect(versionsPage2.docs).toHaveLength(5)
|
|
expect(versionsPage2.page).toBe(2)
|
|
|
|
expect(versions.docs[0].id).not.toBe(versionsPage2.docs[0].id)
|
|
})
|
|
|
|
it('should allow saving multiple versions of models with unique fields', async () => {
|
|
const autosavePost = await payload.create({
|
|
collection,
|
|
data: {
|
|
description: 'description 1',
|
|
title: 'unique unchanging title',
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
id: autosavePost.id,
|
|
collection,
|
|
data: {
|
|
description: 'description 2',
|
|
},
|
|
})
|
|
|
|
const finalDescription = 'final description'
|
|
|
|
const secondUpdate = await payload.update({
|
|
id: autosavePost.id,
|
|
collection,
|
|
data: {
|
|
description: finalDescription,
|
|
},
|
|
})
|
|
|
|
expect(secondUpdate.description).toBe(finalDescription)
|
|
})
|
|
|
|
it('should allow a version to be retrieved by ID', async () => {
|
|
const version = await payload.findVersionByID({
|
|
id: collectionLocalVersionID,
|
|
collection,
|
|
})
|
|
|
|
expect(version.id).toStrictEqual(collectionLocalVersionID)
|
|
})
|
|
|
|
it('should allow a version to save locales properly', async () => {
|
|
const englishTitle = 'Title in EN'
|
|
const spanishTitle = 'Title in ES'
|
|
|
|
await payload.update({
|
|
id: collectionLocalPostID,
|
|
collection,
|
|
data: {
|
|
title: englishTitle,
|
|
},
|
|
})
|
|
|
|
const updatedPostES = await payload.update({
|
|
id: collectionLocalPostID,
|
|
collection,
|
|
data: {
|
|
title: spanishTitle,
|
|
},
|
|
locale: 'es',
|
|
})
|
|
|
|
expect(updatedPostES.title).toBe(spanishTitle)
|
|
|
|
const newEnglishTitle = 'New title in EN'
|
|
|
|
await payload.update({
|
|
id: collectionLocalPostID,
|
|
collection,
|
|
data: {
|
|
title: newEnglishTitle,
|
|
},
|
|
})
|
|
|
|
const versions = await payload.findVersions({
|
|
collection,
|
|
locale: 'all',
|
|
where: {
|
|
parent: {
|
|
equals: collectionLocalPostID,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(versions.docs[0].version.title.en).toStrictEqual(newEnglishTitle)
|
|
expect(versions.docs[0].version.title.es).toStrictEqual(spanishTitle)
|
|
})
|
|
|
|
it('should query drafts with sort', async () => {
|
|
const draftsAscending = await payload.find({
|
|
collection: draftCollectionSlug,
|
|
draft: true,
|
|
sort: 'title',
|
|
})
|
|
|
|
const draftsDescending = await payload.find({
|
|
collection: draftCollectionSlug,
|
|
draft: true,
|
|
sort: '-title',
|
|
})
|
|
|
|
expect(draftsAscending).toBeDefined()
|
|
expect(draftsDescending).toBeDefined()
|
|
expect(draftsAscending.docs[0]).toMatchObject(
|
|
draftsDescending.docs[draftsDescending.docs.length - 1],
|
|
)
|
|
})
|
|
|
|
// https://github.com/payloadcms/payload/issues/4827
|
|
it('should query drafts with relation', async () => {
|
|
const draftPost = await payload.create({
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
description: 'Description',
|
|
title: 'Some Title',
|
|
},
|
|
})
|
|
|
|
await payload.create({
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
description: 'Description',
|
|
relation: draftPost.id,
|
|
title: 'With Relation',
|
|
},
|
|
})
|
|
|
|
const query = {
|
|
collection: draftCollectionSlug,
|
|
where: {
|
|
relation: {
|
|
equals: draftPost.id,
|
|
},
|
|
},
|
|
}
|
|
const all = await payload.find(query)
|
|
const drafts = await payload.find({ ...query, draft: true })
|
|
|
|
expect(all.docs).toHaveLength(1)
|
|
expect(drafts.docs).toHaveLength(1)
|
|
})
|
|
|
|
it('should `findVersions` with sort', async () => {
|
|
const draftsAscending = await payload.findVersions({
|
|
collection: draftCollectionSlug,
|
|
draft: true,
|
|
limit: 100,
|
|
sort: 'createdAt',
|
|
})
|
|
|
|
const draftsDescending = await payload.findVersions({
|
|
collection: draftCollectionSlug,
|
|
draft: true,
|
|
limit: 100,
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
expect(draftsAscending).toBeDefined()
|
|
expect(draftsDescending).toBeDefined()
|
|
expect(draftsAscending.docs[0]).toMatchObject(
|
|
draftsDescending.docs[draftsDescending.docs.length - 1],
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('Restore', () => {
|
|
it('should return `findVersions` in correct order', async () => {
|
|
const somePost = await payload.create({
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
description: 'description 1',
|
|
title: 'first post',
|
|
},
|
|
})
|
|
|
|
const updatedPost = await payload.update({
|
|
id: somePost.id,
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
title: 'This should be the latest version',
|
|
},
|
|
})
|
|
|
|
const versions = await payload.findVersions({
|
|
collection: draftCollectionSlug,
|
|
where: {
|
|
parent: { equals: somePost.id },
|
|
},
|
|
})
|
|
|
|
expect(versions.docs[0].version.title).toBe(updatedPost.title)
|
|
})
|
|
it('should allow a version to be restored', async () => {
|
|
const title2 = 'Another updated post title in EN'
|
|
const updated = 'updated'
|
|
|
|
const versionedPost = await payload.create({
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
description: 'version description',
|
|
title: 'version title',
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
let updatedPost = await payload.update({
|
|
id: versionedPost.id,
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
blocksField: [
|
|
{
|
|
blockType: 'block',
|
|
localized: 'text',
|
|
text: 'text',
|
|
},
|
|
],
|
|
title: title2,
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
updatedPost = await payload.update({
|
|
id: versionedPost.id,
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
blocksField: [
|
|
{
|
|
id: updatedPost.blocksField[0].id,
|
|
blockName: 'breakpoint',
|
|
blockType: 'block',
|
|
localized: updated,
|
|
text: updated,
|
|
},
|
|
],
|
|
title: title2,
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
expect(updatedPost.title).toBe(title2)
|
|
expect(updatedPost.blocksField[0].text).toBe(updated)
|
|
expect(updatedPost.blocksField[0].localized).toBe(updated)
|
|
|
|
// Make sure it was updated correctly
|
|
const draftFromUpdatedPost = await payload.findByID({
|
|
id: versionedPost.id,
|
|
collection: draftCollectionSlug,
|
|
draft: true,
|
|
})
|
|
expect(draftFromUpdatedPost.title).toBe(title2)
|
|
expect(draftFromUpdatedPost.blocksField).toHaveLength(1)
|
|
expect(draftFromUpdatedPost.blocksField[0].localized).toStrictEqual(updated)
|
|
|
|
const versions = await payload.findVersions({
|
|
collection: draftCollectionSlug,
|
|
where: {
|
|
parent: {
|
|
equals: versionedPost.id,
|
|
},
|
|
},
|
|
})
|
|
|
|
const versionToRestore = versions.docs[versions.docs.length - 1]
|
|
// restore to previous version
|
|
const restoredVersion = await payload.restoreVersion({
|
|
id: versionToRestore.id,
|
|
collection: draftCollectionSlug,
|
|
})
|
|
|
|
expect({ ...restoredVersion }).toMatchObject({
|
|
...versionToRestore.version,
|
|
updatedAt: restoredVersion.updatedAt,
|
|
})
|
|
|
|
const latestDraft = await payload.findByID({
|
|
id: versionedPost.id,
|
|
collection: draftCollectionSlug,
|
|
draft: true,
|
|
})
|
|
|
|
expect(latestDraft).toMatchObject({
|
|
...versionToRestore.version,
|
|
updatedAt: latestDraft.updatedAt,
|
|
})
|
|
expect(latestDraft.blocksField).toHaveLength(0)
|
|
})
|
|
})
|
|
|
|
describe('Update', () => {
|
|
it('should allow a draft to be patched', async () => {
|
|
const originalTitle = 'Here is a published post'
|
|
|
|
const originalPublishedPost = await payload.create({
|
|
collection,
|
|
data: {
|
|
_status: 'published',
|
|
description: 'kjnjyhbbdsfseankuhsjsfghb',
|
|
title: originalTitle,
|
|
},
|
|
})
|
|
|
|
const patchedTitle = 'Here is a draft post with a patched title'
|
|
|
|
await payload.update({
|
|
id: originalPublishedPost.id,
|
|
collection,
|
|
data: {
|
|
title: patchedTitle,
|
|
_status: 'draft',
|
|
},
|
|
draft: true,
|
|
locale: 'en',
|
|
})
|
|
|
|
const spanishTitle = 'es title'
|
|
|
|
// second update to existing draft
|
|
await payload.update({
|
|
id: originalPublishedPost.id,
|
|
collection,
|
|
data: {
|
|
title: spanishTitle,
|
|
_status: 'draft',
|
|
},
|
|
draft: true,
|
|
locale: 'es',
|
|
})
|
|
|
|
const publishedPost = await payload.findByID({
|
|
id: originalPublishedPost.id,
|
|
collection,
|
|
})
|
|
|
|
const draftPost = await payload.findByID({
|
|
id: originalPublishedPost.id,
|
|
collection,
|
|
draft: true,
|
|
locale: 'all',
|
|
})
|
|
|
|
expect(publishedPost.title).toBe(originalTitle)
|
|
expect(draftPost.title.en).toBe(patchedTitle)
|
|
expect(draftPost.title.es).toBe(spanishTitle)
|
|
})
|
|
|
|
it('should validate when publishing with the draft arg', async () => {
|
|
// no title (not valid for publishing)
|
|
const doc = await payload.create({
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
description: 'desc',
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
await expect(async () => {
|
|
// should not be able to publish a doc that fails validation
|
|
await payload.update({
|
|
id: doc.id,
|
|
collection: draftCollectionSlug,
|
|
data: { _status: 'published' },
|
|
draft: true,
|
|
})
|
|
}).rejects.toThrow(ValidationError)
|
|
|
|
// succeeds but returns zero docs updated, with an error
|
|
const updateManyResult = await payload.update({
|
|
collection: draftCollectionSlug,
|
|
data: { _status: 'published' },
|
|
draft: true,
|
|
where: {
|
|
id: { equals: doc.id },
|
|
},
|
|
})
|
|
|
|
expect(updateManyResult.docs).toHaveLength(0)
|
|
expect(updateManyResult.errors).toStrictEqual([
|
|
{ id: doc.id, message: 'The following field is invalid: title' },
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('Update Many', () => {
|
|
it('should update many using drafts', async () => {
|
|
const doc = await payload.create({
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
title: 'initial value',
|
|
description: 'description to bulk update',
|
|
_status: 'published',
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
collection: draftCollectionSlug,
|
|
id: doc.id,
|
|
draft: true,
|
|
data: {
|
|
title: 'updated title',
|
|
},
|
|
})
|
|
|
|
// bulk publish
|
|
const updated = await payload.update({
|
|
collection: draftCollectionSlug,
|
|
data: {
|
|
_status: 'published',
|
|
description: 'updated description',
|
|
},
|
|
draft: true,
|
|
where: {
|
|
id: {
|
|
in: [doc.id],
|
|
},
|
|
},
|
|
})
|
|
|
|
const updatedDoc = updated.docs?.[0]
|
|
|
|
// get the published doc
|
|
const findResult = await payload.find({
|
|
collection: draftCollectionSlug,
|
|
where: {
|
|
id: { equals: doc.id },
|
|
},
|
|
})
|
|
|
|
const findDoc = findResult.docs?.[0]
|
|
|
|
expect(updatedDoc.description).toStrictEqual('updated description')
|
|
expect(updatedDoc.title).toStrictEqual('updated title')
|
|
expect(findDoc.title).toStrictEqual('updated title')
|
|
expect(findDoc.description).toStrictEqual('updated description')
|
|
})
|
|
})
|
|
|
|
describe('Delete', () => {
|
|
let postToDelete
|
|
beforeEach(async () => {
|
|
postToDelete = await payload.create({
|
|
collection,
|
|
data: {
|
|
_status: 'draft',
|
|
description: 'description',
|
|
title: 'title to delete',
|
|
},
|
|
})
|
|
})
|
|
it('should delete drafts', async () => {
|
|
const drafts = await payload.db.queryDrafts({
|
|
collection,
|
|
where: {
|
|
parent: {
|
|
equals: postToDelete.id,
|
|
},
|
|
},
|
|
})
|
|
|
|
await payload.delete({
|
|
collection,
|
|
where: {
|
|
id: { equals: postToDelete.id },
|
|
},
|
|
})
|
|
|
|
const result = await payload.db.queryDrafts({
|
|
collection,
|
|
where: {
|
|
id: {
|
|
in: drafts.docs.map(({ id }) => id),
|
|
},
|
|
// appendVersionToQueryKey,
|
|
},
|
|
})
|
|
|
|
expect(result.docs).toHaveLength(0)
|
|
})
|
|
})
|
|
|
|
describe('Draft Count', () => {
|
|
it('creates proper number of drafts', async () => {
|
|
const originalDraft = await payload.create({
|
|
collection: 'draft-posts',
|
|
data: {
|
|
_status: 'draft',
|
|
description: 'A',
|
|
title: 'A',
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
await payload.update({
|
|
id: originalDraft.id,
|
|
collection: 'draft-posts',
|
|
data: {
|
|
_status: 'draft',
|
|
description: 'B',
|
|
title: 'B',
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
await payload.update({
|
|
id: originalDraft.id,
|
|
collection: 'draft-posts',
|
|
data: {
|
|
_status: 'draft',
|
|
description: 'C',
|
|
title: 'C',
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
const mostRecentDraft = await payload.findByID({
|
|
id: originalDraft.id,
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
})
|
|
|
|
expect(mostRecentDraft.title).toStrictEqual('C')
|
|
|
|
const versions = await payload.findVersions({
|
|
collection: 'draft-posts',
|
|
where: {
|
|
parent: {
|
|
equals: originalDraft.id,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(versions.docs).toHaveLength(3)
|
|
})
|
|
})
|
|
|
|
describe('Max Versions', () => {
|
|
// create 2 documents with 3 versions each
|
|
// expect 2 documents with 2 versions each
|
|
it('retains correct versions', async () => {
|
|
const doc1 = await payload.create({
|
|
collection: 'version-posts',
|
|
data: {
|
|
description: 'A',
|
|
title: 'A',
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
id: doc1.id,
|
|
collection: 'version-posts',
|
|
data: {
|
|
description: 'B',
|
|
title: 'B',
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
id: doc1.id,
|
|
collection: 'version-posts',
|
|
data: {
|
|
description: 'C',
|
|
title: 'C',
|
|
},
|
|
})
|
|
|
|
const doc2 = await payload.create({
|
|
collection: 'version-posts',
|
|
data: {
|
|
description: 'D',
|
|
title: 'D',
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
id: doc2.id,
|
|
collection: 'version-posts',
|
|
data: {
|
|
description: 'E',
|
|
title: 'E',
|
|
},
|
|
})
|
|
|
|
await payload.update({
|
|
id: doc2.id,
|
|
collection: 'version-posts',
|
|
data: {
|
|
description: 'F',
|
|
title: 'F',
|
|
},
|
|
})
|
|
|
|
const doc1Versions = await payload.findVersions({
|
|
collection: 'version-posts',
|
|
sort: '-updatedAt',
|
|
where: {
|
|
parent: {
|
|
equals: doc1.id,
|
|
},
|
|
},
|
|
})
|
|
|
|
const doc2Versions = await payload.findVersions({
|
|
collection: 'version-posts',
|
|
sort: '-updatedAt',
|
|
where: {
|
|
parent: {
|
|
equals: doc2.id,
|
|
},
|
|
},
|
|
})
|
|
|
|
// correctly retains 2 documents in the versions collection
|
|
expect(doc1Versions.totalDocs).toStrictEqual(2)
|
|
// correctly retains the most recent 2 versions
|
|
expect(doc1Versions.docs[1].version.title).toStrictEqual('B')
|
|
|
|
// correctly retains 2 documents in the versions collection
|
|
expect(doc2Versions.totalDocs).toStrictEqual(2)
|
|
// correctly retains the most recent 2 versions
|
|
expect(doc2Versions.docs[1].version.title).toStrictEqual('E')
|
|
|
|
const docs = await payload.find({
|
|
collection: 'version-posts',
|
|
})
|
|
|
|
// correctly retains 2 documents in the actual collection
|
|
expect(docs.totalDocs).toStrictEqual(2)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Querying', () => {
|
|
const originalTitle = 'original title'
|
|
const updatedTitle1 = 'new title 1'
|
|
const updatedTitle2 = 'new title 2'
|
|
let firstDraft
|
|
|
|
beforeEach(async () => {
|
|
// This will be created in the `draft-posts` collection
|
|
firstDraft = await payload.create({
|
|
collection: 'draft-posts',
|
|
data: {
|
|
description: 'my description',
|
|
radio: 'test',
|
|
title: originalTitle,
|
|
},
|
|
})
|
|
|
|
// This will be created in the `_draft-posts_versions` collection
|
|
await payload.update({
|
|
id: firstDraft.id,
|
|
collection: 'draft-posts',
|
|
data: {
|
|
title: updatedTitle1,
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
// This will be created in the `_draft-posts_versions` collection
|
|
// and will be the newest draft, able to be queried on
|
|
await payload.update({
|
|
id: firstDraft.id,
|
|
collection: 'draft-posts',
|
|
data: {
|
|
title: updatedTitle2,
|
|
},
|
|
draft: true,
|
|
})
|
|
})
|
|
|
|
it('should allow querying a draft doc from main collection', async () => {
|
|
const findResults = await payload.find({
|
|
collection: 'draft-posts',
|
|
where: {
|
|
title: {
|
|
equals: originalTitle,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(findResults.docs[0].title).toStrictEqual(originalTitle)
|
|
})
|
|
|
|
it('should return more than 10 `totalDocs`', async () => {
|
|
const { id } = await payload.create({
|
|
collection: 'draft-posts',
|
|
data: {
|
|
description: 'Description',
|
|
title: 'Title',
|
|
},
|
|
})
|
|
|
|
const createVersions = async (int: number = 1) => {
|
|
for (let i = 0; i < int; i++) {
|
|
await payload.update({
|
|
id,
|
|
collection: 'draft-posts',
|
|
data: {
|
|
title: `Title ${i}`,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
await createVersions(10)
|
|
|
|
const findResults = await payload.findVersions({
|
|
collection: 'draft-posts',
|
|
where: {
|
|
parent: {
|
|
equals: id,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(findResults.totalDocs).toBe(11)
|
|
})
|
|
|
|
it('should not be able to query an old draft version with draft=true', async () => {
|
|
const draftFindResults = await payload.find({
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
where: {
|
|
title: {
|
|
equals: updatedTitle1,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(draftFindResults.docs).toHaveLength(0)
|
|
})
|
|
|
|
it('should be able to query the newest draft version with draft=true', async () => {
|
|
const draftFindResults = await payload.find({
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
where: {
|
|
title: {
|
|
equals: updatedTitle2,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(draftFindResults.docs[0].title).toStrictEqual(updatedTitle2)
|
|
})
|
|
|
|
it("should not be able to query old drafts that don't match with draft=true", async () => {
|
|
const draftFindResults = await payload.find({
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
where: {
|
|
title: {
|
|
equals: originalTitle,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(draftFindResults.docs).toHaveLength(0)
|
|
})
|
|
|
|
it('should be able to query by id with draft=true', async () => {
|
|
const allDocs = await payload.find({
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
})
|
|
|
|
expect(allDocs.docs.length).toBeGreaterThan(1)
|
|
|
|
const byID = await payload.find({
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
where: {
|
|
id: {
|
|
equals: allDocs.docs[0].id,
|
|
},
|
|
},
|
|
})
|
|
|
|
expect(byID.docs).toHaveLength(1)
|
|
})
|
|
|
|
it('should be able to query by id AND any other field with draft=true', async () => {
|
|
const allDocs = await payload.find({
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
})
|
|
|
|
expect(allDocs.docs.length).toBeGreaterThan(1)
|
|
|
|
const results = await payload.find({
|
|
collection: 'draft-posts',
|
|
draft: true,
|
|
where: {
|
|
and: [
|
|
{
|
|
id: {
|
|
not_in: allDocs.docs[0].id,
|
|
},
|
|
},
|
|
{
|
|
title: {
|
|
like: 'Published',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
expect(results.docs).toHaveLength(1)
|
|
})
|
|
})
|
|
|
|
describe('Collections - GraphQL', () => {
|
|
beforeEach(async () => {
|
|
const description = 'autosave description'
|
|
|
|
const query = `mutation {
|
|
createAutosavePost(data: {title: "${collectionGraphQLOriginalTitle}", description: "${description}"}) {
|
|
id
|
|
title
|
|
description
|
|
createdAt
|
|
updatedAt
|
|
_status
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
collectionGraphQLPostID = data.createAutosavePost.id
|
|
})
|
|
describe('Create', () => {
|
|
it('should allow a new doc to be created with draft status', async () => {
|
|
const description2 = 'other autosave description'
|
|
|
|
const query = `mutation {
|
|
createAutosavePost(data: {title: "${'Some other title'}", description: "${description2}"}) {
|
|
id
|
|
title
|
|
description
|
|
createdAt
|
|
updatedAt
|
|
_status
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
expect(data.createAutosavePost._status).toStrictEqual('draft')
|
|
})
|
|
})
|
|
|
|
describe('Read', () => {
|
|
const updatedTitle2 = 'updated title'
|
|
|
|
beforeEach(async () => {
|
|
// modify the post to create a new version
|
|
// language=graphQL
|
|
const update = `mutation {
|
|
updateAutosavePost(id: ${formatGraphQLID(
|
|
collectionGraphQLPostID,
|
|
)}, data: {title: "${updatedTitle2}"}) {
|
|
title
|
|
updatedAt
|
|
createdAt
|
|
}
|
|
}`
|
|
await restClient.GRAPHQL_POST({
|
|
body: JSON.stringify({ query: update }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
|
|
// language=graphQL
|
|
const query = `query {
|
|
versionsAutosavePosts(where: { parent: { equals: ${formatGraphQLID(
|
|
collectionGraphQLPostID,
|
|
)} } }) {
|
|
docs {
|
|
id
|
|
}
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
collectionGraphQLVersionID = data.versionsAutosavePosts.docs[0].id
|
|
})
|
|
|
|
it('should allow read of versions by version id', async () => {
|
|
const query = `query {
|
|
versionAutosavePost(id: ${formatGraphQLID(collectionGraphQLVersionID)}) {
|
|
id
|
|
parent {
|
|
id
|
|
}
|
|
version {
|
|
title
|
|
}
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
expect(data.versionAutosavePost.id).toBeDefined()
|
|
expect(data.versionAutosavePost.parent.id).toStrictEqual(collectionGraphQLPostID)
|
|
expect(data.versionAutosavePost.version.title).toStrictEqual(updatedTitle2)
|
|
})
|
|
|
|
it('should allow read of versions by querying version content', async () => {
|
|
// language=graphQL
|
|
const query = `query {
|
|
versionsAutosavePosts(where: { version__title: {equals: "${collectionGraphQLOriginalTitle}" } }) {
|
|
docs {
|
|
id
|
|
parent {
|
|
id
|
|
}
|
|
version {
|
|
title
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
const doc = data.versionsAutosavePosts.docs[0]
|
|
|
|
expect(doc.id).toBeDefined()
|
|
expect(doc.parent.id).toStrictEqual(collectionGraphQLPostID)
|
|
expect(doc.version.title).toStrictEqual(collectionGraphQLOriginalTitle)
|
|
})
|
|
})
|
|
|
|
describe('Restore', () => {
|
|
beforeEach(async () => {
|
|
// modify the post to create a new version
|
|
// language=graphQL
|
|
const update = `mutation {
|
|
updateAutosavePost(id: ${formatGraphQLID(
|
|
collectionGraphQLPostID,
|
|
)}, data: {title: "${collectionGraphQLOriginalTitle}"}) {
|
|
title
|
|
updatedAt
|
|
createdAt
|
|
}
|
|
}`
|
|
await restClient.GRAPHQL_POST({
|
|
body: JSON.stringify({ query: update }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
|
|
// language=graphQL
|
|
const query = `query {
|
|
versionsAutosavePosts(where: { parent: { equals: ${formatGraphQLID(
|
|
collectionGraphQLPostID,
|
|
)} } }) {
|
|
docs {
|
|
id
|
|
}
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
collectionGraphQLVersionID = data.versionsAutosavePosts.docs[0].id
|
|
})
|
|
it('should allow a version to be restored', async () => {
|
|
// Update it
|
|
const update = `mutation {
|
|
updateAutosavePost(id: ${formatGraphQLID(
|
|
collectionGraphQLPostID,
|
|
)}, data: {title: "${'Wrong title'}"}) {
|
|
title
|
|
updatedAt
|
|
createdAt
|
|
}
|
|
}`
|
|
await restClient.GRAPHQL_POST({
|
|
body: JSON.stringify({ query: update }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
|
|
// restore a versionsPost
|
|
const restore = `mutation {
|
|
restoreVersionAutosavePost(id: ${formatGraphQLID(collectionGraphQLVersionID)}) {
|
|
title
|
|
}
|
|
}`
|
|
|
|
await restClient.GRAPHQL_POST({
|
|
body: JSON.stringify({ query: restore }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
|
|
const query = `query {
|
|
AutosavePost(id: ${formatGraphQLID(collectionGraphQLPostID)}) {
|
|
title
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
expect(data.AutosavePost.title).toStrictEqual(collectionGraphQLOriginalTitle)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Globals - Local', () => {
|
|
beforeEach(async () => {
|
|
const title2 = 'Here is an updated global title in EN'
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
title: 'Test Global',
|
|
},
|
|
})
|
|
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
title: title2,
|
|
},
|
|
})
|
|
|
|
const versions = await payload.findGlobalVersions({
|
|
slug: globalSlug,
|
|
})
|
|
|
|
globalLocalVersionID = versions.docs[0].id
|
|
})
|
|
describe('Create', () => {
|
|
it('should allow a new version to be created', async () => {
|
|
const title2 = 'Here is an updated global title in EN'
|
|
const updatedGlobal = await payload.findGlobal({
|
|
slug: globalSlug,
|
|
})
|
|
expect(updatedGlobal.title).toBe(title2)
|
|
expect(updatedGlobal._status).toStrictEqual('draft')
|
|
expect(globalLocalVersionID).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('Read', () => {
|
|
it('should allow a version to be retrieved by ID', async () => {
|
|
const version = await payload.findGlobalVersionByID({
|
|
id: globalLocalVersionID,
|
|
slug: globalSlug,
|
|
})
|
|
|
|
expect(version.id).toStrictEqual(globalLocalVersionID)
|
|
})
|
|
})
|
|
|
|
describe('Update', () => {
|
|
it('should allow a version to save locales properly', async () => {
|
|
const englishTitle = 'Title in EN'
|
|
const spanishTitle = 'Title in ES'
|
|
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
title: englishTitle,
|
|
},
|
|
})
|
|
|
|
const updatedGlobalES = await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
title: spanishTitle,
|
|
},
|
|
locale: 'es',
|
|
})
|
|
|
|
expect(updatedGlobalES.title).toBe(spanishTitle)
|
|
|
|
const newEnglishTitle = 'New title in EN'
|
|
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
title: newEnglishTitle,
|
|
},
|
|
})
|
|
|
|
const versions = await payload.findGlobalVersions({
|
|
slug: globalSlug,
|
|
locale: 'all',
|
|
})
|
|
|
|
expect(versions.docs[0].version.title.en).toStrictEqual(newEnglishTitle)
|
|
expect(versions.docs[0].version.title.es).toStrictEqual(spanishTitle)
|
|
})
|
|
})
|
|
|
|
describe('Restore', () => {
|
|
it('should allow a version to be restored', async () => {
|
|
const title2 = 'Another updated title in EN'
|
|
|
|
const updatedGlobal = await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
title: title2,
|
|
},
|
|
})
|
|
|
|
expect(updatedGlobal.title).toBe(title2)
|
|
|
|
// Make sure it was updated correctly
|
|
const foundUpdatedGlobal = await payload.findGlobal({
|
|
slug: globalSlug,
|
|
draft: true,
|
|
})
|
|
expect(foundUpdatedGlobal.title).toBe(title2)
|
|
|
|
const versions = await payload.findGlobalVersions({
|
|
slug: globalSlug,
|
|
})
|
|
|
|
globalLocalVersionID = versions.docs[1].id
|
|
|
|
const restore = await payload.restoreGlobalVersion({
|
|
id: globalLocalVersionID,
|
|
slug: globalSlug,
|
|
})
|
|
|
|
expect(restore.title).toBeDefined()
|
|
|
|
const restoredGlobal = await payload.findGlobal({
|
|
slug: globalSlug,
|
|
draft: true,
|
|
})
|
|
|
|
expect(restoredGlobal.title).toBe(restore.title)
|
|
})
|
|
})
|
|
|
|
describe('Patch', () => {
|
|
it('should allow a draft to be patched', async () => {
|
|
const originalTitle = 'Here is a published global'
|
|
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
_status: 'published',
|
|
description: 'kjnjyhbbdsfseankuhsjsfghb',
|
|
title: originalTitle,
|
|
},
|
|
})
|
|
|
|
const publishedGlobal = await payload.findGlobal({
|
|
slug: globalSlug,
|
|
draft: true,
|
|
})
|
|
|
|
const updatedTitle2 = 'Here is a draft global with a patched title'
|
|
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
_status: 'draft',
|
|
title: updatedTitle2,
|
|
},
|
|
draft: true,
|
|
locale: 'en',
|
|
})
|
|
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
_status: 'draft',
|
|
title: updatedTitle2,
|
|
},
|
|
draft: true,
|
|
locale: 'es',
|
|
})
|
|
|
|
const updatedGlobal = await payload.findGlobal({
|
|
slug: globalSlug,
|
|
draft: true,
|
|
locale: 'all',
|
|
})
|
|
|
|
expect(publishedGlobal.title).toBe(originalTitle)
|
|
expect(updatedGlobal.title.en).toBe(updatedTitle2)
|
|
expect(updatedGlobal.title.es).toBe(updatedTitle2)
|
|
})
|
|
|
|
it('should allow a draft to be published', async () => {
|
|
const originalTitle = 'Here is a draft'
|
|
|
|
await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
_status: 'draft',
|
|
title: originalTitle,
|
|
},
|
|
draft: true,
|
|
})
|
|
|
|
const updatedTitle2 = 'Now try to publish'
|
|
|
|
const result = await payload.updateGlobal({
|
|
slug: globalSlug,
|
|
data: {
|
|
_status: 'published',
|
|
title: updatedTitle2,
|
|
},
|
|
})
|
|
|
|
expect(result.title).toBe(updatedTitle2)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Globals - GraphQL', () => {
|
|
beforeEach(async () => {
|
|
// language=graphql
|
|
const update = `mutation {
|
|
updateAutosaveGlobal(draft: true, data: {
|
|
title: "${globalGraphQLOriginalTitle}"
|
|
}) {
|
|
_status
|
|
title
|
|
}
|
|
}`
|
|
await restClient.GRAPHQL_POST({
|
|
body: JSON.stringify({ query: update }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
|
|
// language=graphQL
|
|
const query = `query {
|
|
versionsAutosaveGlobal(where: { version__title: { equals: "${globalGraphQLOriginalTitle}" } }) {
|
|
docs {
|
|
id
|
|
version {
|
|
title
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
globalGraphQLVersionID = data.versionsAutosaveGlobal.docs[0].id
|
|
})
|
|
describe('Read', () => {
|
|
it('should allow read of versions by version id', async () => {
|
|
// language=graphql
|
|
const query = `query {
|
|
versionAutosaveGlobal(id: ${formatGraphQLID(globalGraphQLVersionID)}) {
|
|
id
|
|
version {
|
|
title
|
|
}
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
expect(data.versionAutosaveGlobal.id).toBeDefined()
|
|
expect(data.versionAutosaveGlobal.version.title).toStrictEqual(globalGraphQLOriginalTitle)
|
|
})
|
|
|
|
it('should allow read of versions by querying version content', async () => {
|
|
// language=graphQL
|
|
const query = `query {
|
|
versionsAutosaveGlobal(where: { version__title: {equals: "${globalGraphQLOriginalTitle}" } }) {
|
|
docs {
|
|
id
|
|
version {
|
|
title
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
|
|
const doc = data.versionsAutosaveGlobal.docs[0]
|
|
|
|
expect(doc.id).toBeDefined()
|
|
expect(doc.version.title).toStrictEqual(globalGraphQLOriginalTitle)
|
|
})
|
|
})
|
|
|
|
describe('Restore', () => {
|
|
it('should allow a version to be restored', async () => {
|
|
// language=graphql
|
|
const restore = `mutation {
|
|
restoreVersionAutosaveGlobal(id: ${formatGraphQLID(globalGraphQLVersionID)}) {
|
|
title
|
|
}
|
|
}`
|
|
|
|
await restClient.GRAPHQL_POST({
|
|
body: JSON.stringify({ query: restore }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
|
|
const query = `query {
|
|
AutosaveGlobal {
|
|
title
|
|
}
|
|
}`
|
|
|
|
const { data } = await restClient
|
|
.GRAPHQL_POST({
|
|
body: JSON.stringify({ query }),
|
|
headers: {
|
|
Authorization: `JWT ${token}`,
|
|
},
|
|
})
|
|
.then((res) => res.json())
|
|
expect(data.AutosaveGlobal.title).toStrictEqual(globalGraphQLOriginalTitle)
|
|
})
|
|
})
|
|
})
|
|
})
|