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
136 changes: 135 additions & 1 deletion src/__testing__/RJSFFormWrapper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Surface-level smoke test for the RJSFFormWrapper / RJSFFormModal
* exports added in layer5io/sistent#1533.
*
* Two assertions:
* Three assertions:
*
* 1. The wrapper module loads cleanly with the @rjsf/* peer-deps
* installed (deep-path import).
Expand All @@ -18,11 +18,27 @@
* importing them at runtime, because the runtime barrel pulls
* in sistent's `Markdown` -> `react-markdown` ESM chain that
* would need a widened jest `transformIgnorePatterns`.
* The same constraint applies to `src/custom/RJSFFormWrapper/index.ts`
* which re-exports RJSFFormModal (and thus the same Modal chain),
* so RJSFFormModal coverage also stays as a static text check.
*
* 3. Runtime imports from the theme sub-barrel validate that all
* theme generators and theme objects are defined. The theme
* sub-barrel (templates/widgets/generateTheme) does not pull in
* the Modal -> react-markdown chain, so it is safe to import.
*/

import * as fs from 'fs';
import * as path from 'path';
import { RJSFFormWrapper } from '../custom/RJSFFormWrapper/RJSFFormWrapper';
import {
sistentTheme,
sistentTemplates,
sistentWidgets,
generateTheme,
generateTemplates,
generateWidgets
} from '../custom/RJSFFormWrapper/theme';

describe('RJSFFormWrapper (sistent#1533)', () => {
it('exports a function with stable displayName from the deep path', () => {
Expand All @@ -44,4 +60,122 @@ describe('RJSFFormWrapper (sistent#1533)', () => {
expect(source).toMatch(/export\s+\*\s+from\s+['"]\.\/RJSFFormWrapper['"]/);
}
);

it('src/custom/RJSFFormWrapper/index.ts re-exports the theme module', () => {
const full = path.resolve(__dirname, '..', 'custom', 'RJSFFormWrapper', 'index.ts');
expect(fs.existsSync(full)).toBe(true);
const source = fs.readFileSync(full, 'utf8');
expect(source).toMatch(/export\s+\*\s+from\s+['"]\.\/theme['"]/);
});

it('src/index.tsx explicitly exports RJSFFormWrapper, RJSFFormModal, and all theme symbols in export statements', () => {
const full = path.resolve(__dirname, '..', 'index.tsx');
expect(fs.existsSync(full)).toBe(true);
const source = fs.readFileSync(full, 'utf8');

// Parse all exported identifier names from export { ... } statements
const exportedSymbols = new Set<string>();
for (const match of source.matchAll(/export\s*\{([^{}]*)\}\s*;?/g)) {
const items = match[1].split(',').map((x) => x.trim()).filter(Boolean);
for (const item of items) {
const exportedName = item.replace(/^type\s+/, '').split(/\s+as\s+/).pop()!.trim();
exportedSymbols.add(exportedName);
}
}

const expectedExports = [
'RJSFFormModal',
'RJSFFormWrapper',
'hideRootObjectTitle',
'sistentTheme',
'sistentTemplates',
'sistentWidgets',
'generateTheme',
'generateTemplates',
'generateWidgets',
'RJSFFormModalProps',
'RJSFFormWrapperProps',
'RJSFValidationError'
];

for (const exp of expectedExports) {
expect(exportedSymbols.has(exp)).toBe(true);
}
});

it('theme generators and theme objects are defined at the theme sub-barrel', () => {
expect(typeof generateTheme).toBe('function');
expect(typeof generateTemplates).toBe('function');
expect(typeof generateWidgets).toBe('function');
expect(sistentTheme).toBeDefined();
expect(sistentTemplates).toBeDefined();
expect(sistentWidgets).toBeDefined();
});

it('published declaration bundle dist/index.d.ts exports RJSF and theme symbols when built', () => {
const dtsPath = path.resolve(__dirname, '..', '..', 'dist', 'index.d.ts');
if (!fs.existsSync(dtsPath)) {
// Local jest run before build; skip gracefully
return;
}
const dts = fs.readFileSync(dtsPath, 'utf8');
const dtsExportedSymbols = new Set<string>();
for (const match of dts.matchAll(/export\s*\{([^{}]*)\}\s*;?/g)) {
const items = match[1].split(',').map((x) => x.trim()).filter(Boolean);
for (const item of items) {
const exportedName = item.replace(/^type\s+/, '').split(/\s+as\s+/).pop()!.trim();
dtsExportedSymbols.add(exportedName);
}
}

const expectedDtsSymbols = [
'RJSFFormModal',
'RJSFFormWrapper',
'hideRootObjectTitle',
'sistentTheme',
'sistentTemplates',
'sistentWidgets',
'generateTheme',
'generateTemplates',
'generateWidgets',
'RJSFFormModalProps',
'RJSFFormWrapperProps',
'RJSFValidationError'
];
for (const sym of expectedDtsSymbols) {
expect(dtsExportedSymbols.has(sym)).toBe(true);
}
});

it('published runtime bundle dist/index.mjs exports RJSF and theme symbols when built', () => {
const mjsPath = path.resolve(__dirname, '..', '..', 'dist', 'index.mjs');
if (!fs.existsSync(mjsPath)) {
// Local jest run before build; skip gracefully
return;
}
const mjs = fs.readFileSync(mjsPath, 'utf8');
const mjsExportedSymbols = new Set<string>();
for (const match of mjs.matchAll(/export\s*\{([^{}]*)\}\s*;?/g)) {
const items = match[1].split(',').map((x) => x.trim()).filter(Boolean);
for (const item of items) {
const exportedName = item.replace(/^type\s+/, '').split(/\s+as\s+/).pop()!.trim();
mjsExportedSymbols.add(exportedName);
}
}

const expectedRuntimeSymbols = [
'RJSFFormModal',
'RJSFFormWrapper',
'hideRootObjectTitle',
'sistentTheme',
'sistentTemplates',
'sistentWidgets',
'generateTheme',
'generateTemplates',
'generateWidgets'
];
for (const sym of expectedRuntimeSymbols) {
expect(mjsExportedSymbols.has(sym)).toBe(true);
}
});
});
Loading
Loading