/** * This Source Code is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright (c) Infonomic Company Limited */ import { act } from 'react' import { defineAdminConfig } from '@byline/core' import { adminTranslations } from '@byline/i18n/admin' import { I18nProvider } from '@byline/i18n/react' import { createRoot, type Root } from 'react-dom/client' import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { BylineFieldServicesProvider } from '../fields/field-services-context' import { FormRenderer } from './form-renderer' const globalWithAct = globalThis as any globalWithAct.IS_REACT_ACT_ENVIRONMENT = true defineAdminConfig({ i18n: { admin: { defaultLocale: 'en', locales: ['en'] }, content: { defaultLocale: 'en', locales: ['en', 'fr'] }, }, collections: [ { path: 'pages', labels: { singular: 'Page', plural: 'Pages' }, fields: [{ name: 'title', label: 'Title', type: 'text' }], }, ], slugifier: (value: string) => value.toLowerCase().trim().replace(/\s+/g, '-'), }) const fields = [ { name: 'title', label: 'Title', type: 'text' as const }, { name: 'seoTitle', label: 'SEO title', type: 'text' as const }, ] const adminConfig = { layout: { main: ['content'] }, tabSets: [ { name: 'content', tabs: [ { name: 'general', label: 'General', fields: ['title'] }, { name: 'seo', label: 'SEO', fields: ['seoTitle'] }, ], }, ], } let container: HTMLDivElement let root: Root beforeEach(() => { container = document.createElement('div') document.body.appendChild(container) root = createRoot(container) }) afterEach(() => { act(() => { root.unmount() }) container.remove() }) const mount = (locale: string, versionId: string) => { act(() => { root.render( ({ docs: [], total: 0 }), uploadField: async () => ({}), } as any } > {}} onCancel={() => {}} /> ) }) } const selectedTabLabel = () => container.querySelector('[role="tab"][aria-selected="true"]')?.textContent describe('FormRenderer tab persistence across keyed remounts', () => { // FormProvider is keyed on `${initialLocale}-${versionId}`, so changing either // remounts the whole subtree. Tab selection is lifted above that key on // purpose; this asserts the wiring, which a controlled-prop test on // FormLayout alone cannot reach. // // Adopted from the reviewer's Checkpoint 2 regression fixture. it('retains the selected tab through locale and version remounts', () => { mount('en', 'v1') const seoTab = [...container.querySelectorAll('[role="tab"]')].find( (t) => t.textContent === 'SEO' ) if (seoTab == null) throw new Error('SEO tab not found') act(() => { ;(seoTab as HTMLElement).click() }) const first = container.querySelector('input[name="seoTitle"]') expect(first).not.toBeNull() mount('fr', 'v1') // locale change remounts FormProvider via its key const french = container.querySelector('input[name="seoTitle"]') expect(french).not.toBeNull() expect(french).not.toBe(first) expect(french?.value).toBe('fr SEO') expect(selectedTabLabel()).toBe('SEO') mount('fr', 'v2') // version change remounts it again const versioned = container.querySelector('input[name="seoTitle"]') expect(versioned).not.toBeNull() expect(versioned).not.toBe(french) expect(selectedTabLabel()).toBe('SEO') }) })