Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/ui/src/utilities/copyDataFromLocale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ export const copyDataFromLocale = async (args: CopyDataFromLocaleArgs) => {
? payload.findGlobal({
slug: globalSlug,
depth: 0,
draft: true,
locale: fromLocale,
overrideAccess: false,
user,
Expand All @@ -258,6 +259,7 @@ export const copyDataFromLocale = async (args: CopyDataFromLocaleArgs) => {
id: docID,
collection: collectionSlug,
depth: 0,
draft: true,
joins: false,
locale: fromLocale,
overrideAccess: false,
Expand All @@ -268,6 +270,7 @@ export const copyDataFromLocale = async (args: CopyDataFromLocaleArgs) => {
? payload.findGlobal({
slug: globalSlug,
depth: 0,
draft: true,
locale: toLocale,
overrideAccess: false,
user,
Expand All @@ -277,6 +280,7 @@ export const copyDataFromLocale = async (args: CopyDataFromLocaleArgs) => {
id: docID,
collection: collectionSlug,
depth: 0,
draft: true,
joins: false,
locale: toLocale,
overrideAccess: false,
Expand Down Expand Up @@ -310,6 +314,7 @@ export const copyDataFromLocale = async (args: CopyDataFromLocaleArgs) => {
? await payload.updateGlobal({
slug: globalSlug,
data,
draft: true,
locale: toLocale,
overrideAccess: false,
req,
Expand All @@ -319,6 +324,7 @@ export const copyDataFromLocale = async (args: CopyDataFromLocaleArgs) => {
id: docID,
collection: collectionSlug,
data,
draft: true,
locale: toLocale,
overrideAccess: false,
req,
Expand Down
44 changes: 44 additions & 0 deletions test/localization/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,50 @@ describe('Localization', () => {
// Should show error
await expect(page.locator('.payload-toast-container .toast-error')).toBeVisible()
})

test('should not lose source locale data when copying with autosave enabled', async () => {
// This tests that copy-to-locale doesn't cause data loss
// when operating on a collection with autosave enabled (blocks-fields)

// Create a document with blocks content in en locale
await changeLocale(page, defaultLocale)
await page.goto(urlBlocks.create)

// Fill in the title
const titleField = page.locator('#field-title')
await titleField.fill('English Block Title')

// Add a block with content
await addBlock({ page, fieldName: 'content', blockToSelect: 'Block Inside Block' })
const blockTextField = page.locator('#field-content__0__text')
await blockTextField.fill('English block text content')

// Wait for autosave to complete
await waitForAutoSaveToRunAndComplete(page)

// Verify autosave worked
await expect(titleField).toHaveValue('English Block Title')
await expect(blockTextField).toHaveValue('English block text content')

// Copy to Spanish locale
await openCopyToLocaleDrawer(page)
await setToLocale(page, 'Spanish')
await runCopy({ page, toLocale: spanishLocale })

// Wait for the form to be ready after copy/navigation
await waitForFormReady(page)

// Verify Spanish locale has the copied data
await expect(page.locator('#field-title')).toHaveValue('English Block Title')

// CRITICAL: Switch back to English and verify data is NOT lost
await changeLocale(page, defaultLocale)

await expect(page.locator('#field-title')).toHaveValue('English Block Title')
await expect(page.locator('#field-content__0__text')).toHaveValue(
'English block text content',
)
})
})

describe('locale change', () => {
Expand Down
198 changes: 198 additions & 0 deletions test/localization/int.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3117,6 +3117,204 @@ describe('Localization', () => {
// The source data should remain unchanged
expect(refreshedDoc.topLevelArrayLocalized?.[0]?.text).toBe('some-text')
})

it('should copy to locale without losing data when autosave and drafts are enabled', async () => {
// The blocks-fields collection has versions.drafts.autosave: true
// This test verifies that copyToLocale doesn't cause data loss
// when operating on a collection with autosave enabled

// Create a document with content in en locale
const doc = await payload.create({
collection: 'blocks-fields',
locale: 'en',
data: {
title: 'English Title',
content: [
{
blockType: 'blockInsideBlock',
text: 'English block text',
content: [
{
blockType: 'textBlock',
text: 'Nested English text',
},
],
},
],
},
})

// Add content to Spanish locale separately
await payload.update({
collection: 'blocks-fields',
id: doc.id,
locale: 'es',
data: {
title: 'Spanish Title',
content: [
{
blockType: 'blockInsideBlock',
text: 'Spanish block text',
},
],
},
})

// Verify initial state - English data should exist
const enDocBefore = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'en',
})

expect(enDocBefore.title).toBe('English Title')
expect(enDocBefore.content?.[0]?.text).toBe('English block text')

// Copy data from en to es
const req = await createLocalReq({ user }, payload)

await copyDataFromLocaleHandler({
fromLocale: 'en',
req,
toLocale: 'es',
docID: doc.id,
collectionSlug: 'blocks-fields',
overrideData: true,
})

// CRITICAL: Verify English data is NOT lost after copy operation
const enDocAfter = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'en',
})

expect(enDocAfter.title).toBe('English Title')
expect(enDocAfter.content?.[0]?.text).toBe('English block text')
expect(enDocAfter.content?.[0]?.content?.[0]?.text).toBe('Nested English text')

// Verify Spanish locale received the copied data (as a draft)
const esDocAfter = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'es',
draft: true,
})

expect(esDocAfter.title).toBe('English Title')
expect(esDocAfter.content?.[0]?.text).toBe('English block text')
})

it('should copy to locale without losing draft data when autosave is enabled', async () => {
// Create a document with draft content
const doc = await payload.create({
collection: 'blocks-fields',
locale: 'en',
draft: true,
data: {
title: 'Draft English Title',
content: [
{
blockType: 'blockInsideBlock',
text: 'Draft block text',
},
],
},
})

// Verify draft exists
const draftBefore = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'en',
draft: true,
})

expect(draftBefore.title).toBe('Draft English Title')

// Copy draft data to another locale
const req = await createLocalReq({ user }, payload)

await copyDataFromLocaleHandler({
fromLocale: 'en',
req,
toLocale: 'es',
docID: doc.id,
collectionSlug: 'blocks-fields',
})

// Verify the source draft is not lost
const draftAfter = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'en',
draft: true,
})

expect(draftAfter.title).toBe('Draft English Title')
expect(draftAfter.content?.[0]?.text).toBe('Draft block text')
})

it('should not overwrite published content when source has both published and draft versions', async () => {
// Create published doc in en
const doc = await payload.create({
collection: 'blocks-fields',
locale: 'en',
data: {
title: 'Published EN',
},
})

// Create draft with different content
await payload.update({
collection: 'blocks-fields',
id: doc.id,
locale: 'en',
draft: true,
data: {
title: 'Draft EN',
},
})

// Verify both published and draft exist with different content
const enPublishedBefore = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'en',
draft: false,
})
const enDraftBefore = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'en',
draft: true,
})

expect(enPublishedBefore.title).toBe('Published EN')
expect(enDraftBefore.title).toBe('Draft EN')

// Copy to another locale using the actual handler
const req = await createLocalReq({ user }, payload)

await copyDataFromLocaleHandler({
fromLocale: 'en',
req,
toLocale: 'es',
docID: doc.id,
collectionSlug: 'blocks-fields',
overrideData: true,
})

// Verify published content in source locale is NOT overwritten
const enPublishedAfter = await payload.findByID({
id: doc.id,
collection: 'blocks-fields',
locale: 'en',
draft: false,
})

expect(enPublishedAfter.title).toBe('Published EN')
})
})

describe('Multiple fallback locales', () => {
Expand Down
Loading