import type React from 'react'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { visuallyHiddenStyle } from '@shoptet/ui-core-web'; import { iconGlyphChar } from '../Icon/iconGlyphChar'; import { DEFAULT_SYMBOL } from './StatusIndicator'; import { SHAPE_GEOMETRY, shapeForState } from './StatusIndicatorGeometry'; // StatusIndicatorRenderer duplicates the rendered markup as static strings // (no React runtime in PHP rendering). This guards that duplicate against drift. const dirname = path.dirname(fileURLToPath(import.meta.url)); const PHP_PLUGIN_PATH = path.join(dirname, '../../../../../../../../cms/packages/View/StatusIndicatorRenderer.php'); const STATES = Object.keys(DEFAULT_SYMBOL) as (keyof typeof DEFAULT_SYMBOL)[]; const php = fs.existsSync(PHP_PLUGIN_PATH) ? fs.readFileSync(PHP_PLUGIN_PATH, 'utf8') : ''; describe('StatusIndicatorRenderer.php markup contract', () => { it('resolves the PHP plugin path', () => { expect(fs.existsSync(PHP_PLUGIN_PATH)).toBe(true); }); it('keeps GEOMETRY in sync with SHAPE_GEOMETRY.full from StatusIndicatorGeometry.tsx', () => { const outOfSync = STATES.filter(state => { const shape = shapeForState(state); const element = SHAPE_GEOMETRY.full[shape] as React.ReactElement<{ d?: string; cx?: string; cy?: string; r?: string; }>; const { d, cx, cy, r } = element.props; const attr = shape === 'circle' ? `cx="${cx}" cy="${cy}" r="${r}"` : `d="${d}"`; return !php.includes(attr); }).map(state => `${state} (${shapeForState(state)})`); expect(outOfSync).toEqual([]); }); it('keeps SYMBOL in sync with DEFAULT_SYMBOL from StatusIndicator.tsx', () => { // PHP names each glyph after its icon (shp-critical-status-symbol => GLYPH_CRITICAL_STATUS_SYMBOL) // and stores it as the "\u{HEX}" escape of the shp.json codepoint const outOfSync = STATES.filter(state => { const iconName = DEFAULT_SYMBOL[state]; const constant = `GLYPH_${iconName.replace(/^shp-/, '').replaceAll('-', '_').toUpperCase()}`; const codepoint = iconGlyphChar(iconName).codePointAt(0); return ( codepoint === undefined || !php.includes(`${constant} = "\\u{${codepoint.toString(16).toUpperCase()}}"`) || !php.includes(`'${state}' => self::${constant}`) ); }); expect(outOfSync).toEqual([]); }); it('emits the same svg wrapper and symbol element as StatusIndicatorShape.tsx', () => { const fragments = [ '