/** * The admin panel does not import field components directly. Payload sends the * client a *path* for each one — a richText field's is * `@payloadcms/richtext-lexical/rsc#RscEntryLexicalField` — and resolves it * through this generated map. An entry that is missing from the map is not an * error the panel reports: the field simply does not render. * * That failure is quietly awful, because `required: true` is enforced on the * server regardless. A writer gets a new-post form with no Content editor and * a save that refuses on a field they were never shown. * * The map is generated by `npx payload generate:importmap`, so it drifts every * time a field or a lexical feature is added and nobody re-runs it. These * assert the entries the current config needs. */ import fs from 'fs'; import path from 'path'; const MAP = fs.readFileSync( path.join(__dirname, '..', '..', 'app', '(payload)', 'admin', 'importMap.js'), 'utf8', ); const POSTS = fs.readFileSync( path.join(__dirname, '..', '..', 'collections', 'Posts.ts'), 'utf8', ); describe('admin import map', () => { it('resolves the richText field, so Content renders in the editor', () => { // Guarded because Posts.content is required: without this entry the field // is invisible and the post is unsaveable. expect(POSTS).toMatch(/type:\s*'richText'/); expect(MAP).toContain('@payloadcms/richtext-lexical/rsc#RscEntryLexicalField'); }); it('resolves the richText cell, so the list view can render the column', () => { expect(MAP).toContain('@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell'); }); it('resolves the diff component, which the drafts UI needs', () => { // versions.drafts is on, so the panel offers version comparison. expect(POSTS).toMatch(/drafts:\s*true/); expect(MAP).toContain('@payloadcms/richtext-lexical/rsc#LexicalDiffComponent'); }); it('resolves BlocksFeature, so the Callout block is insertable', () => { expect(POSTS).toContain('BlocksFeature'); expect(MAP).toContain('@payloadcms/richtext-lexical/client#BlocksFeatureClient'); }); it('resolves the default toolbar features the editor is built with', () => { // defaultFeatures is spread into the editor config; each one contributes a // client component the toolbar cannot render without. for (const feature of [ 'BoldFeatureClient', 'ItalicFeatureClient', 'HeadingFeatureClient', 'LinkFeatureClient', 'UploadFeatureClient', 'UnorderedListFeatureClient', 'OrderedListFeatureClient', 'InlineToolbarFeatureClient', ]) { expect(MAP).toContain(`@payloadcms/richtext-lexical/client#${feature}`); } }); });