@memberjunction/react-test-harness 2.98.0 → 2.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -58,8 +58,9 @@ export declare class ComponentRunner {
58
58
  private loadComponentLibraries;
59
59
  /**
60
60
  * Set up error tracking in the page
61
+ * @deprecated Moved inline to page.evaluate after library loading to avoid false positives
61
62
  */
62
- private setupErrorTracking;
63
+ private setupErrorTracking_DEPRECATED;
63
64
  /**
64
65
  * Collect runtime errors from the page
65
66
  */
@@ -1 +1 @@
1
- {"version":3,"file":"component-runner.d.ts","sourceRoot":"","sources":["../../src/lib/component-runner.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,KAAK,EAAiC,QAAQ,EAAyD,MAAM,sBAAsB,CAAC;AAC3I,OAAO,EAAmB,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,EAMd,MAAM,6CAA6C,CAAC;AAMrD,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,aAAa,CAAC;IAC/D,WAAW,EAAE,QAAQ,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,SAAS,EAAE,CAAC;CAC9B;AAED;;GAEG;AACH,qBAAa,eAAe;IAkBd,OAAO,CAAC,cAAc;IAhBlC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAS/C;IAKF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE7B,cAAc,EAAE,cAAc;IAElD;;OAEG;IACG,aAAa,CACjB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,GAAG,EACnB,eAAe,CAAC,EAAE,OAAO,EACzB,WAAW,CAAC,EAAE,QAAQ,EACtB,OAAO,CAAC,EAAE,GAAG,GACZ,OAAO,CAAC;QAAE,UAAU,EAAE,SAAS,EAAE,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAmBrD,gBAAgB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAiuB7F;;;OAGG;YACW,oBAAoB;IA0ElC;;OAEG;YACW,sBAAsB;IAqHpC;;OAEG;YACW,kBAAkB;IA6PhC;;OAEG;YACW,oBAAoB;IAmHlC;;OAEG;YACW,eAAe;IAkB7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;YAyBb,qBAAqB;cAqBnB,uBAAuB,CAAC,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC;IA2JtF;;OAEG;YACW,iBAAiB;IAsT/B;;OAEG;IACH,OAAO,CAAC,aAAa;CAuBtB"}
1
+ {"version":3,"file":"component-runner.d.ts","sourceRoot":"","sources":["../../src/lib/component-runner.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,KAAK,EAAiC,QAAQ,EAAyD,MAAM,sBAAsB,CAAC;AAC3I,OAAO,EAAmB,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,EAMd,MAAM,6CAA6C,CAAC;AAkCrD,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,aAAa,CAAC;IAC/D,WAAW,EAAE,QAAQ,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,SAAS,EAAE,CAAC;CAC9B;AAED;;GAEG;AACH,qBAAa,eAAe;IAkBd,OAAO,CAAC,cAAc;IAhBlC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAS/C;IAKF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE7B,cAAc,EAAE,cAAc;IAElD;;OAEG;IACG,aAAa,CACjB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,GAAG,EACnB,eAAe,CAAC,EAAE,OAAO,EACzB,WAAW,CAAC,EAAE,QAAQ,EACtB,OAAO,CAAC,EAAE,GAAG,GACZ,OAAO,CAAC;QAAE,UAAU,EAAE,SAAS,EAAE,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAmBrD,gBAAgB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IA28B7F;;;OAGG;YACW,oBAAoB;IA0ElC;;OAEG;YACW,sBAAsB;IAqHpC;;;OAGG;YACW,6BAA6B;IA6P3C;;OAEG;YACW,oBAAoB;IAmHlC;;OAEG;YACW,eAAe;IAkB7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;YAyBb,qBAAqB;cAqBnB,uBAAuB,CAAC,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC;IA2JtF;;OAEG;YACW,iBAAiB;IAsT/B;;OAEG;IACH,OAAO,CAAC,aAAa;CAuBtB"}
@@ -29,6 +29,27 @@ const component_linter_1 = require("./component-linter");
29
29
  const core_entities_1 = require("@memberjunction/core-entities");
30
30
  const ai_vectors_memory_1 = require("@memberjunction/ai-vectors-memory");
31
31
  const aiengine_1 = require("@memberjunction/aiengine");
32
+ /**
33
+ * Pre-resolve a component spec for browser execution
34
+ * Converts registry components to embedded format with all code included
35
+ */
36
+ async function preResolveComponentSpec(spec, contextUser) {
37
+ // If already embedded with code, return as-is
38
+ if (spec.location === 'embedded' && spec.code) {
39
+ return spec;
40
+ }
41
+ // For registry components, we need to fetch and embed everything
42
+ if (spec.location === 'registry' && spec.registry) {
43
+ // In test harness context, we likely don't have GraphQL access
44
+ // Registry components would need to be pre-resolved before being passed to test harness
45
+ console.warn(`Registry component ${spec.name} cannot be resolved in test harness context - GraphQL not available`);
46
+ console.warn('Registry components should be pre-resolved before passing to test harness');
47
+ // Return the spec as-is, which will likely fail in browser but at least won't crash here
48
+ return spec;
49
+ }
50
+ // For other types, return as-is
51
+ return spec;
52
+ }
32
53
  /**
33
54
  * ComponentRunner that uses the actual React runtime via Playwright UMD bundle
34
55
  */
@@ -118,8 +139,8 @@ class ComponentRunner {
118
139
  if (!runtimeCheck.hasMJRuntime) {
119
140
  throw new Error('Failed to inject MJReactRuntime into page context');
120
141
  }
121
- // Set up error tracking
122
- await this.setupErrorTracking(page, options.componentSpec, allLibraries);
142
+ // NOTE: Error tracking setup moved to after library loading to avoid false positives
143
+ // during library initialization (e.g., antd's UMD bundle setup)
123
144
  // Set up console logging
124
145
  this.setupConsoleLogging(page, consoleLogs, warnings);
125
146
  // Expose MJ utilities to the page
@@ -143,6 +164,14 @@ class ComponentRunner {
143
164
  // Total available libraries in metadata (for context only)
144
165
  console.log(' - total available libraries in metadata:', allLibraries?.length || 0);
145
166
  }
167
+ // // Pre-resolve the spec for browser execution (convert registry components to embedded)
168
+ // const resolvedSpec = await preResolveComponentSpec(options.componentSpec, options.contextUser);
169
+ // if (debug) {
170
+ // console.log('📦 Pre-resolved spec for browser execution:', {
171
+ // original: { location: options.componentSpec.location, registry: options.componentSpec.registry },
172
+ // resolved: { location: resolvedSpec.location, registry: resolvedSpec.registry, hasCode: !!resolvedSpec.code }
173
+ // });
174
+ // }
146
175
  // Execute the component using the real React runtime with timeout (Recommendation #1)
147
176
  const executionPromise = page.evaluate(async ({ spec, props, debug, componentLibraries }) => {
148
177
  if (debug) {
@@ -157,7 +186,7 @@ class ComponentRunner {
157
186
  if (!MJRuntime) {
158
187
  throw new Error('React runtime not loaded');
159
188
  }
160
- const { ComponentCompiler, ComponentRegistry, ComponentHierarchyRegistrar, SetupStyles } = MJRuntime;
189
+ const { ComponentCompiler, ComponentRegistry, ComponentHierarchyRegistrar, ComponentManager, SetupStyles } = MJRuntime;
161
190
  if (debug) {
162
191
  console.log('🚀 Starting component execution with real runtime');
163
192
  console.log('Available runtime classes:', Object.keys(MJRuntime));
@@ -181,6 +210,21 @@ class ComponentRunner {
181
210
  // Create runtime context
182
211
  // Note: Component libraries are loaded by the ComponentCompiler itself
183
212
  // via loadRequiredLibraries, so we don't need to pass them here
213
+ // Diagnostic: Check if React is available before creating context
214
+ if (!window.React) {
215
+ console.error('🔴 CRITICAL: React is NULL when creating runtimeContext!');
216
+ console.error('Window keys:', Object.keys(window).filter(k => k.toLowerCase().includes('react')));
217
+ throw new Error('React is not available in window context');
218
+ }
219
+ if (debug) {
220
+ console.log('✅ React is available:', typeof window.React);
221
+ console.log('✅ React hooks check:', {
222
+ useState: typeof window.React?.useState,
223
+ useEffect: typeof window.React?.useEffect,
224
+ useRef: typeof window.React?.useRef,
225
+ useMemo: typeof window.React?.useMemo
226
+ });
227
+ }
184
228
  const runtimeContext = {
185
229
  React: window.React,
186
230
  ReactDOM: window.ReactDOM,
@@ -192,7 +236,14 @@ class ComponentRunner {
192
236
  // IMPORTANT: Configure the LibraryRegistry in the browser context
193
237
  // This is needed for the compiler to know about approved libraries
194
238
  if (window.MJReactRuntime && window.MJReactRuntime.LibraryRegistry) {
195
- const { LibraryRegistry } = window.MJReactRuntime;
239
+ const { LibraryRegistry, LibraryLoader } = window.MJReactRuntime;
240
+ // Enable progressive delay for library initialization in test harness
241
+ if (LibraryLoader) {
242
+ LibraryLoader.enableProgressiveDelay = true;
243
+ if (debug) {
244
+ console.log('⚙️ Enabled progressive delay for library initialization');
245
+ }
246
+ }
196
247
  // Configure the registry with the component libraries
197
248
  // Note: LibraryRegistry.Config expects ComponentLibraryEntity[]
198
249
  await LibraryRegistry.Config(false, componentLibraries || []);
@@ -201,7 +252,9 @@ class ComponentRunner {
201
252
  }
202
253
  }
203
254
  const registry = new ComponentRegistry();
204
- const registrar = new ComponentHierarchyRegistrar(compiler, registry, runtimeContext);
255
+ // NEW: Use ComponentManager instead of ComponentHierarchyRegistrar
256
+ const manager = new ComponentManager(compiler, registry, runtimeContext, { debug: true, enableUsageTracking: false } // Force debug on for better diagnostics
257
+ );
205
258
  // Use the utilities we already created with mock metadata
206
259
  // Don't call createRuntimeUtilities() as it tries to create new Metadata() which fails
207
260
  const utilities = window.__mjUtilities;
@@ -249,13 +302,57 @@ class ComponentRunner {
249
302
  }
250
303
  }
251
304
  let registrationResult;
305
+ let loadResult; // Declare loadResult in outer scope
252
306
  try {
253
- registrationResult = await registrar.registerHierarchy(spec, {
254
- styles,
255
- namespace: 'Global',
256
- version: 'v1', // Use v1 to match the registry defaults
257
- allLibraries: componentLibraries || [] // Pass the component libraries for LibraryRegistry
307
+ if (debug) {
308
+ console.log('📋 [BROWSER] Spec before loadHierarchy:', {
309
+ name: spec.name,
310
+ location: spec.location,
311
+ registry: spec.registry,
312
+ hasCode: !!spec.code,
313
+ codeLength: spec.code?.length,
314
+ libraries: spec.libraries,
315
+ dependencies: spec.dependencies?.map((d) => ({
316
+ name: d.name,
317
+ location: d.location,
318
+ hasCode: !!d.code
319
+ }))
320
+ });
321
+ }
322
+ // NEW: Use ComponentManager.loadHierarchy instead of registrar.registerHierarchy
323
+ // Note: In browser context, we don't have access to contextUser or database
324
+ // This is fine for embedded components which are self-contained
325
+ loadResult = await manager.loadHierarchy(spec, {
326
+ contextUser: undefined, // No user context in browser
327
+ defaultNamespace: 'Global',
328
+ defaultVersion: 'v1',
329
+ returnType: 'both',
330
+ resolutionMode: 'embed', // Convert to embedded format for browser execution
331
+ allLibraries: componentLibraries || [] // Pass libraries for compiler
258
332
  });
333
+ if (debug) {
334
+ console.log('📋 [BROWSER] LoadHierarchy result:', {
335
+ success: loadResult.success,
336
+ rootComponent: !!loadResult.rootComponent,
337
+ resolvedSpec: loadResult.resolvedSpec ? {
338
+ name: loadResult.resolvedSpec.name,
339
+ location: loadResult.resolvedSpec.location,
340
+ registry: loadResult.resolvedSpec.registry,
341
+ libraries: loadResult.resolvedSpec.libraries,
342
+ hasCode: !!loadResult.resolvedSpec.code
343
+ } : null,
344
+ loadedComponents: loadResult.loadedComponents,
345
+ errors: loadResult.errors
346
+ });
347
+ }
348
+ // Convert to old format for compatibility
349
+ registrationResult = {
350
+ success: loadResult.success,
351
+ registeredComponents: loadResult.loadedComponents,
352
+ errors: loadResult.errors.map((e) => ({ componentName: e.componentName || '', error: e.message, phase: e.phase })),
353
+ warnings: [],
354
+ resolvedSpec: loadResult.resolvedSpec
355
+ };
259
356
  }
260
357
  catch (registrationError) {
261
358
  // Capture the actual error before it gets obscured
@@ -288,32 +385,140 @@ class ComponentRunner {
288
385
  // Note: ComponentRegistry doesn't expose internal components Map directly
289
386
  // We can see what was registered through the registrationResult
290
387
  }
291
- // Get the root component object - explicitly pass namespace and version
292
- const RootComponentObject = registry.get(spec.name, 'Global', 'v1');
388
+ // NEW: With ComponentManager, we already have the components from loadResult
389
+ if (!loadResult) {
390
+ throw new Error('Component loading failed - no result returned');
391
+ }
392
+ const RootComponentObject = loadResult.rootComponent;
293
393
  if (!RootComponentObject) {
294
394
  // Enhanced error message with debugging info
295
- console.error('Failed to find component:', spec.name);
296
- console.error('Registry keys:', Array.from(registry.components.keys()));
297
- throw new Error('Root component not found: ' + spec.name);
395
+ console.error('Failed to load component:', spec.name);
396
+ console.error('Load errors:', loadResult.errors);
397
+ throw new Error('Root component not loaded: ' + spec.name);
298
398
  }
299
399
  // Extract the React component from the ComponentObject
300
400
  const RootComponent = RootComponentObject.component;
301
401
  if (!RootComponent || typeof RootComponent !== 'function') {
302
402
  throw new Error('Component object does not contain a valid React component');
303
403
  }
304
- // Get all registered component objects and extract React components
305
- const componentObjects = registry.getAll('Global', 'v1');
306
- const components = {};
307
- for (const [name, componentObj] of Object.entries(componentObjects)) {
308
- // ComponentObject has a component property that's the React component
309
- components[name] = componentObj.component;
310
- }
404
+ // Get all loaded components from the result
405
+ // ComponentManager now returns unwrapped components directly
406
+ const components = loadResult.components || {};
311
407
  if (debug) {
312
408
  console.log('📚 Registered components for dependencies:', Object.keys(components));
313
409
  console.log('📋 Component spec dependencies:', spec.dependencies?.map((d) => d.name) || []);
410
+ // Check what libraries are actually available in global scope
411
+ console.log('🌍 [BROWSER] Global library check after loading:', {
412
+ ApexCharts: typeof window.ApexCharts,
413
+ antd: typeof window.antd,
414
+ React: typeof window.React,
415
+ ReactDOM: typeof window.ReactDOM,
416
+ windowKeys: Object.keys(window).filter(k => k.toLowerCase().includes('apex') ||
417
+ k.toLowerCase().includes('antd') ||
418
+ k === 'ApexCharts' ||
419
+ k === 'antd')
420
+ });
421
+ // If libraries were supposed to be loaded, check their actual presence
422
+ if (spec.libraries && spec.libraries.length > 0) {
423
+ console.log('🔍 [BROWSER] Checking required libraries:');
424
+ for (const lib of spec.libraries) {
425
+ const globalVar = lib.globalVariable;
426
+ const exists = !!window[globalVar];
427
+ const type = typeof window[globalVar];
428
+ console.log(` - ${lib.name} (${globalVar}): ${exists ? `✅ Present (${type})` : '❌ Missing'}`);
429
+ }
430
+ }
314
431
  }
315
432
  // Note: Library components are now handled by the runtime's compiler
316
433
  // which loads them into the appropriate context/closure
434
+ // NOW set up enhanced error tracking - AFTER libraries are loaded
435
+ // This avoids false positives from library initialization code (e.g., antd)
436
+ if (!window.__testHarnessErrorTrackingSetup) {
437
+ window.__testHarnessErrorTrackingSetup = true;
438
+ // Initialize error tracking arrays if not already done
439
+ window.__testHarnessRuntimeErrors = window.__testHarnessRuntimeErrors || [];
440
+ window.__testHarnessConsoleErrors = window.__testHarnessConsoleErrors || [];
441
+ window.__testHarnessConsoleWarnings = window.__testHarnessConsoleWarnings || [];
442
+ window.__testHarnessTestFailed = window.__testHarnessTestFailed || false;
443
+ window.__testHarnessRenderCount = window.__testHarnessRenderCount || 0;
444
+ // Wrap React.createElement to detect invalid element types
445
+ const originalCreateElement = window.React?.createElement;
446
+ if (originalCreateElement) {
447
+ window.React.createElement = function (type, props, ...children) {
448
+ window.__testHarnessRenderCount++;
449
+ // Enhanced error detection for invalid element types
450
+ if (type !== null && type !== undefined) {
451
+ const typeOf = typeof type;
452
+ // Check for the common "object instead of component" error
453
+ if (typeOf === 'object' && !window.React.isValidElement(type)) {
454
+ // Try to get a meaningful name for the object
455
+ let objectInfo = 'unknown object';
456
+ try {
457
+ if (type.constructor && type.constructor.name) {
458
+ objectInfo = type.constructor.name;
459
+ }
460
+ else if (type.name) {
461
+ objectInfo = type.name;
462
+ }
463
+ else {
464
+ // Try to show what properties it has
465
+ const keys = Object.keys(type).slice(0, 5);
466
+ if (keys.length > 0) {
467
+ objectInfo = `object with properties: ${keys.join(', ')}`;
468
+ }
469
+ }
470
+ }
471
+ catch (e) {
472
+ // Ignore errors in trying to get object info
473
+ }
474
+ // Generate helpful error message
475
+ const errorMsg = [
476
+ `Invalid JSX element type: React received an object (${objectInfo}) instead of a React component function.`,
477
+ '',
478
+ 'This often occurs when JSX elements or React.createElement receive an object instead of a valid component function.',
479
+ '',
480
+ 'Inspect all instances where you are using JSX elements that come from libraries or components to ensure they are properly referenced.',
481
+ '',
482
+ 'The exact fix depends on the specific library or component structure.'
483
+ ].join('\\n');
484
+ // Log to both console and error tracking
485
+ console.error('🔴 Invalid JSX Element Type Detected:', errorMsg);
486
+ // Store the error for later collection
487
+ window.__testHarnessRuntimeErrors.push({
488
+ message: errorMsg,
489
+ type: 'invalid-element-type',
490
+ phase: 'createElement',
491
+ source: 'enhanced-detection',
492
+ elementInfo: objectInfo
493
+ });
494
+ // Still try to call the original to get React's error too
495
+ // This will provide the component stack trace
496
+ }
497
+ }
498
+ else if (type === undefined) {
499
+ // Undefined component - likely a failed destructure or missing import
500
+ const errorMsg = [
501
+ 'Invalid JSX element type: component is undefined.',
502
+ '',
503
+ 'This occurs when a JSX element references a component that is undefined at runtime.',
504
+ '',
505
+ 'Inspect how this component is being accessed - it may not exist in the expected location or may have a different name.',
506
+ '',
507
+ 'Check that the component exists in your dependencies or libraries and is properly referenced.'
508
+ ].join('\\n');
509
+ console.error('🔴 Undefined JSX Component:', errorMsg);
510
+ window.__testHarnessRuntimeErrors.push({
511
+ message: errorMsg,
512
+ type: 'undefined-component',
513
+ phase: 'createElement',
514
+ source: 'enhanced-detection'
515
+ });
516
+ }
517
+ // Call original createElement
518
+ return originalCreateElement.apply(this, [type, props, ...children]);
519
+ };
520
+ }
521
+ }
317
522
  // Render the component
318
523
  const rootElement = document.getElementById('root');
319
524
  if (!rootElement) {
@@ -495,7 +700,15 @@ class ComponentRunner {
495
700
  renderCount = await page.evaluate(() => window.__testHarnessRenderCount || 0);
496
701
  // Collect all errors with source information
497
702
  const runtimeErrorsWithSource = await this.collectRuntimeErrors(page);
498
- errors.push(...runtimeErrorsWithSource.map(e => e.message)); // Extract messages for backward compat
703
+ // Filter out JSX element type errors when adding to errors array
704
+ errors.push(...runtimeErrorsWithSource
705
+ .filter(e => {
706
+ // Skip JSX element type errors from error count
707
+ const isJSXError = e.type === 'invalid-element-type' ||
708
+ e.type === 'undefined-component';
709
+ return !isJSXError;
710
+ })
711
+ .map(e => e.message)); // Extract messages for backward compat
499
712
  // Collect warnings (separate from errors)
500
713
  const collectedWarnings = await this.collectWarnings(page);
501
714
  warnings.push(...collectedWarnings);
@@ -503,12 +716,18 @@ class ComponentRunner {
503
716
  const asyncWaitTime = options.asyncErrorWaitTime || 1000;
504
717
  await page.waitForTimeout(asyncWaitTime);
505
718
  const asyncErrors = await this.collectRuntimeErrors(page);
506
- // Only add new errors
719
+ // Only add new errors (excluding JSX element type errors)
507
720
  asyncErrors.forEach(err => {
508
- if (!errors.includes(err.message)) {
721
+ const isJSXError = err.type === 'invalid-element-type' ||
722
+ err.type === 'undefined-component';
723
+ if (!isJSXError && !errors.includes(err.message)) {
509
724
  errors.push(err.message);
510
725
  runtimeErrorsWithSource.push(err); // Keep the structured version too
511
726
  }
727
+ else if (isJSXError && !runtimeErrorsWithSource.some(e => e.message === err.message)) {
728
+ // Still track JSX errors for logging but don't add to errors array
729
+ runtimeErrorsWithSource.push(err);
730
+ }
512
731
  });
513
732
  // Also check for new warnings
514
733
  const asyncWarnings = await this.collectWarnings(page);
@@ -534,7 +753,20 @@ class ComponentRunner {
534
753
  // Combine runtime errors with data errors
535
754
  const allErrors = [...errors, ...dataErrors];
536
755
  // Map runtime errors with source info and specific rules
537
- const errorViolations = runtimeErrorsWithSource.map(e => ({
756
+ // Filter out JSX element type errors - they're too noisy and often false positives
757
+ const errorViolations = runtimeErrorsWithSource
758
+ .filter(e => {
759
+ // Skip JSX element type errors - still logged but not reported as violations
760
+ const isJSXError = e.rule === 'invalid-jsx-element' ||
761
+ e.rule === 'undefined-jsx-component' ||
762
+ e.type === 'invalid-element-type' ||
763
+ e.type === 'undefined-component';
764
+ if (isJSXError && debug) {
765
+ console.log('📝 JSX element error detected but not reported as violation:', e.message);
766
+ }
767
+ return !isJSXError;
768
+ })
769
+ .map(e => ({
538
770
  message: e.message,
539
771
  severity: 'critical',
540
772
  rule: e.rule || 'runtime-error', // Use specific rule from collectRuntimeErrors
@@ -852,8 +1084,9 @@ class ComponentRunner {
852
1084
  }
853
1085
  /**
854
1086
  * Set up error tracking in the page
1087
+ * @deprecated Moved inline to page.evaluate after library loading to avoid false positives
855
1088
  */
856
- async setupErrorTracking(page, componentSpec, allLibraries) {
1089
+ async setupErrorTracking_DEPRECATED(page, componentSpec, allLibraries) {
857
1090
  await page.evaluate(({ spec, availableLibraries }) => {
858
1091
  // Initialize error tracking
859
1092
  window.__testHarnessRuntimeErrors = [];