@memberjunction/react-test-harness 2.97.0 → 2.98.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.
@@ -22,7 +22,6 @@ export interface ComponentExecutionResult {
22
22
  html: string;
23
23
  errors: Violation[];
24
24
  warnings: Violation[];
25
- criticalWarnings: string[];
26
25
  console: {
27
26
  type: string;
28
27
  text: string;
@@ -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,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,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;IA6sB7F;;;OAGG;YACW,oBAAoB;IA0ElC;;OAEG;YACW,sBAAsB;IAqHpC;;OAEG;YACW,kBAAkB;IAiFhC;;OAEG;YACW,oBAAoB;IA8ClC;;OAEG;YACW,eAAe;IAkB7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;YA+Bb,qBAAqB;cAqBnB,uBAAuB,CAAC,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC;IA2JtF;;OAEG;YACW,iBAAiB;IAsT/B;;OAEG;IACH,OAAO,CAAC,aAAa;CA6BtB"}
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"}
@@ -52,7 +52,6 @@ class ComponentRunner {
52
52
  const startTime = Date.now();
53
53
  const errors = [];
54
54
  const warnings = [];
55
- const criticalWarnings = [];
56
55
  const consoleLogs = [];
57
56
  const dataErrors = []; // Track data access errors from RunView/RunQuery
58
57
  let renderCount = 0;
@@ -120,9 +119,9 @@ class ComponentRunner {
120
119
  throw new Error('Failed to inject MJReactRuntime into page context');
121
120
  }
122
121
  // Set up error tracking
123
- await this.setupErrorTracking(page);
122
+ await this.setupErrorTracking(page, options.componentSpec, allLibraries);
124
123
  // Set up console logging
125
- this.setupConsoleLogging(page, consoleLogs, warnings, criticalWarnings);
124
+ this.setupConsoleLogging(page, consoleLogs, warnings);
126
125
  // Expose MJ utilities to the page
127
126
  await this.exposeMJUtilities(page, options, dataErrors, debug);
128
127
  if (debug) {
@@ -529,17 +528,16 @@ class ComponentRunner {
529
528
  }
530
529
  // Determine success
531
530
  const success = errors.length === 0 &&
532
- criticalWarnings.length === 0 &&
533
531
  !hasRenderLoop &&
534
532
  !hasTimeout &&
535
533
  executionResult.success;
536
534
  // Combine runtime errors with data errors
537
535
  const allErrors = [...errors, ...dataErrors];
538
- // Map runtime errors with source info, data errors don't have source
536
+ // Map runtime errors with source info and specific rules
539
537
  const errorViolations = runtimeErrorsWithSource.map(e => ({
540
538
  message: e.message,
541
539
  severity: 'critical',
542
- rule: 'runtime-error',
540
+ rule: e.rule || 'runtime-error', // Use specific rule from collectRuntimeErrors
543
541
  line: 0,
544
542
  column: 0,
545
543
  source: e.source
@@ -577,18 +575,39 @@ class ComponentRunner {
577
575
  source: 'user-component' // Data errors are from user's data access code
578
576
  });
579
577
  });
578
+ // Check warnings for critical patterns and move them to errors
579
+ const criticalWarningViolations = [];
580
+ const regularWarnings = [];
581
+ warnings.forEach(w => {
582
+ if (ComponentRunner.CRITICAL_WARNING_PATTERNS.some(pattern => pattern.test(w))) {
583
+ // This is a critical warning - add to errors
584
+ criticalWarningViolations.push({
585
+ message: w,
586
+ severity: 'critical',
587
+ rule: 'critical-react-warning',
588
+ line: 0,
589
+ column: 0,
590
+ source: 'react-framework'
591
+ });
592
+ }
593
+ else {
594
+ // Regular warning
595
+ regularWarnings.push(w);
596
+ }
597
+ });
598
+ // Combine all error violations
599
+ const allErrorViolations = [...errorViolations, ...criticalWarningViolations];
580
600
  const result = {
581
- success: success && dataErrors.length === 0, // Fail if we have data errors
601
+ success: success && dataErrors.length === 0 && criticalWarningViolations.length === 0, // Fail on critical warnings too
582
602
  html,
583
- errors: errorViolations,
584
- warnings: warnings.map(w => ({
603
+ errors: allErrorViolations,
604
+ warnings: regularWarnings.map(w => ({
585
605
  message: w,
586
606
  severity: 'low',
587
607
  rule: 'warning',
588
608
  line: 0,
589
609
  column: 0
590
610
  })),
591
- criticalWarnings,
592
611
  console: consoleLogs,
593
612
  screenshot,
594
613
  executionTime: Date.now() - startTime,
@@ -636,7 +655,6 @@ class ComponentRunner {
636
655
  line: 0,
637
656
  column: 0
638
657
  })),
639
- criticalWarnings,
640
658
  console: consoleLogs,
641
659
  executionTime: Date.now() - startTime,
642
660
  renderCount
@@ -835,20 +853,91 @@ class ComponentRunner {
835
853
  /**
836
854
  * Set up error tracking in the page
837
855
  */
838
- async setupErrorTracking(page) {
839
- await page.evaluate(() => {
856
+ async setupErrorTracking(page, componentSpec, allLibraries) {
857
+ await page.evaluate(({ spec, availableLibraries }) => {
840
858
  // Initialize error tracking
841
859
  window.__testHarnessRuntimeErrors = [];
842
860
  window.__testHarnessConsoleErrors = [];
843
861
  window.__testHarnessConsoleWarnings = [];
844
862
  window.__testHarnessTestFailed = false;
845
863
  window.__testHarnessRenderCount = 0;
846
- // Track renders
864
+ // Track renders and detect invalid element types
847
865
  const originalCreateElement = window.React?.createElement;
848
866
  if (originalCreateElement) {
849
- window.React.createElement = function (...args) {
867
+ window.React.createElement = function (type, props, ...children) {
850
868
  window.__testHarnessRenderCount++;
851
- return originalCreateElement.apply(this, args);
869
+ // Enhanced error detection for invalid element types
870
+ if (type !== null && type !== undefined) {
871
+ const typeOf = typeof type;
872
+ // Check for the common "object instead of component" error
873
+ if (typeOf === 'object' && !window.React.isValidElement(type)) {
874
+ // Try to get a meaningful name for the object
875
+ let objectInfo = 'unknown object';
876
+ try {
877
+ if (type.constructor && type.constructor.name) {
878
+ objectInfo = type.constructor.name;
879
+ }
880
+ else if (type.name) {
881
+ objectInfo = type.name;
882
+ }
883
+ else {
884
+ // Try to show what properties it has
885
+ const keys = Object.keys(type).slice(0, 5);
886
+ if (keys.length > 0) {
887
+ objectInfo = `object with properties: ${keys.join(', ')}`;
888
+ }
889
+ }
890
+ }
891
+ catch (e) {
892
+ // Ignore errors in trying to get object info
893
+ }
894
+ // Generate helpful error message
895
+ const errorMsg = [
896
+ `Invalid JSX element type: React received an object (${objectInfo}) instead of a React component function.`,
897
+ '',
898
+ 'This often occurs when JSX elements or React.createElement receive an object instead of a valid component function.',
899
+ '',
900
+ 'Inspect all instances where you are using JSX elements that come from libraries or components to ensure they are properly referenced.',
901
+ '',
902
+ 'The exact fix depends on the specific library or component structure.'
903
+ ].join('\\n');
904
+ // Log to both console and error tracking
905
+ console.error('šŸ”“ Invalid JSX Element Type Detected:', errorMsg);
906
+ // Store the error for later collection
907
+ window.__testHarnessRuntimeErrors = window.__testHarnessRuntimeErrors || [];
908
+ window.__testHarnessRuntimeErrors.push({
909
+ message: errorMsg,
910
+ type: 'invalid-element-type',
911
+ phase: 'createElement',
912
+ source: 'enhanced-detection',
913
+ elementInfo: objectInfo
914
+ });
915
+ // Still try to call the original to get React's error too
916
+ // This will provide the component stack trace
917
+ }
918
+ }
919
+ else if (type === undefined) {
920
+ // Undefined component - likely a failed destructure or missing import
921
+ const errorMsg = [
922
+ 'Invalid JSX element type: component is undefined.',
923
+ '',
924
+ 'This occurs when a JSX element references a component that is undefined at runtime.',
925
+ '',
926
+ 'Inspect how this component is being accessed - it may not exist in the expected location or may have a different name.',
927
+ '',
928
+ 'Check that the component exists in your dependencies or libraries and is properly referenced.'
929
+ ].join('\\n');
930
+ console.error('šŸ”“ Undefined JSX Component:', errorMsg);
931
+ window.__testHarnessRuntimeErrors = window.__testHarnessRuntimeErrors || [];
932
+ window.__testHarnessRuntimeErrors.push({
933
+ message: errorMsg,
934
+ type: 'undefined-component',
935
+ phase: 'createElement',
936
+ source: 'enhanced-detection'
937
+ });
938
+ }
939
+ // Call original createElement
940
+ return originalCreateElement.call(this, type, props, ...children);
852
941
  };
853
942
  }
854
943
  // Override console.error
@@ -877,9 +966,82 @@ class ComponentRunner {
877
966
  }
878
967
  originalConsoleError.apply(console, args);
879
968
  };
969
+ // Helper function to analyze undefined identifiers
970
+ const analyzeUndefinedIdentifier = (identifier, spec, availableLibraries) => {
971
+ const result = {
972
+ isInSpecLibraries: false,
973
+ isInSpecDependencies: false,
974
+ isAvailableLibrary: false,
975
+ matchedLibrary: null,
976
+ specLibraries: spec?.libraries || [],
977
+ specDependencies: spec?.dependencies || []
978
+ };
979
+ // Check if it's in spec libraries
980
+ result.isInSpecLibraries = result.specLibraries.some((lib) => lib.globalVariable === identifier);
981
+ // Check if it's in spec dependencies
982
+ result.isInSpecDependencies = result.specDependencies.some((dep) => dep.name === identifier);
983
+ // Check against ALL available libraries (case-insensitive)
984
+ if (availableLibraries) {
985
+ const availableLib = availableLibraries.find((lib) => lib.GlobalVariable &&
986
+ lib.GlobalVariable.toLowerCase() === identifier.toLowerCase());
987
+ if (availableLib) {
988
+ result.isAvailableLibrary = true;
989
+ result.matchedLibrary = availableLib;
990
+ }
991
+ }
992
+ return result;
993
+ };
994
+ // Helper function to generate guidance message
995
+ const generateGuidance = (identifier, analysis) => {
996
+ // Case 1: Trying to use a library not in their spec
997
+ if (analysis.isAvailableLibrary && !analysis.isInSpecLibraries) {
998
+ const libList = analysis.specLibraries.length > 0
999
+ ? analysis.specLibraries.map((l) => l.globalVariable || l.name).filter(Boolean).join(', ')
1000
+ : 'no third-party libraries';
1001
+ return `${identifier} is not defined. It appears you're trying to use the ${analysis.matchedLibrary.Name} library. ` +
1002
+ `You do NOT have access to this library. ` +
1003
+ `Your architect gave you access to: ${libList}. ` +
1004
+ `You must work within these constraints and cannot load additional libraries.`;
1005
+ }
1006
+ // Case 2: Should be a component but not properly accessed
1007
+ if (analysis.isInSpecDependencies) {
1008
+ return `${identifier} is not defined. This component exists in your dependencies. ` +
1009
+ `Ensure you've destructured it: const { ${identifier} } = components; ` +
1010
+ `or accessed it as: components.${identifier}`;
1011
+ }
1012
+ // Case 3: Not a valid library or component
1013
+ const libList = analysis.specLibraries.length > 0
1014
+ ? `Available libraries: ${analysis.specLibraries.map((l) => l.globalVariable || l.name).filter(Boolean).join(', ')}`
1015
+ : 'No third-party libraries are available';
1016
+ const depList = analysis.specDependencies.length > 0
1017
+ ? `Available components: ${analysis.specDependencies.map((d) => d.name).join(', ')}`
1018
+ : 'No component dependencies are available';
1019
+ return `${identifier} is not defined. This is not a valid library or component in your specification. ` +
1020
+ `${libList}. ${depList}. ` +
1021
+ `You must only use the libraries and components specified in your component specification.`;
1022
+ };
880
1023
  // Global error handler
881
1024
  window.addEventListener('error', (event) => {
882
- // Determine source based on error content
1025
+ // Check for "X is not defined" errors
1026
+ const notDefinedMatch = event.message?.match(/^(\w+) is not defined$/);
1027
+ if (notDefinedMatch) {
1028
+ const identifier = notDefinedMatch[1];
1029
+ // Analyze what this identifier might be
1030
+ const analysis = analyzeUndefinedIdentifier(identifier, spec, availableLibraries);
1031
+ // Generate specific guidance
1032
+ const guidance = generateGuidance(identifier, analysis);
1033
+ // Store enhanced error with specific guidance
1034
+ window.__testHarnessRuntimeErrors.push({
1035
+ message: guidance,
1036
+ stack: event.error?.stack,
1037
+ type: 'undefined-identifier',
1038
+ source: 'user-component',
1039
+ identifier: identifier
1040
+ });
1041
+ window.__testHarnessTestFailed = true;
1042
+ return;
1043
+ }
1044
+ // Handle other errors as before
883
1045
  let source = 'user-component'; // Default to user component
884
1046
  if (event.message && event.message.includes('Script error')) {
885
1047
  source = 'runtime-wrapper';
@@ -903,7 +1065,7 @@ class ComponentRunner {
903
1065
  window.__testHarnessTestFailed = true;
904
1066
  event.preventDefault();
905
1067
  });
906
- });
1068
+ }, { spec: componentSpec, availableLibraries: allLibraries || [] });
907
1069
  }
908
1070
  /**
909
1071
  * Collect runtime errors from the page
@@ -916,7 +1078,8 @@ class ComponentRunner {
916
1078
  testFailed: window.__testHarnessTestFailed || false
917
1079
  };
918
1080
  });
919
- const errors = [];
1081
+ // Track unique errors and their counts
1082
+ const errorMap = new Map();
920
1083
  // Check if we have any specific React render errors
921
1084
  const hasSpecificReactError = errorData.runtimeErrors.some((error) => error.type === 'react-render-error' &&
922
1085
  !error.message.includes('Script error'));
@@ -928,19 +1091,84 @@ class ComponentRunner {
928
1091
  error.message === 'Script error.') {
929
1092
  return; // Skip this generic error
930
1093
  }
931
- const phase = error.phase ? ` (during ${error.phase})` : '';
932
- const errorMsg = `${error.type} error: ${error.message}${phase}`;
933
- errors.push({
934
- message: errorMsg,
935
- source: error.source
936
- });
1094
+ // Map error types to specific rule names
1095
+ let rule = 'runtime-error';
1096
+ switch (error.type) {
1097
+ case 'invalid-element-type':
1098
+ rule = 'invalid-jsx-element';
1099
+ break;
1100
+ case 'undefined-component':
1101
+ rule = 'undefined-jsx-component';
1102
+ break;
1103
+ case 'undefined-identifier':
1104
+ rule = 'undefined-identifier';
1105
+ break;
1106
+ case 'react-render-error':
1107
+ rule = 'react-render-error';
1108
+ break;
1109
+ case 'render-loop':
1110
+ rule = 'infinite-render-loop';
1111
+ break;
1112
+ case 'registration-error':
1113
+ rule = 'component-registration-error';
1114
+ break;
1115
+ case 'execution-error':
1116
+ rule = 'execution-error';
1117
+ break;
1118
+ case 'runtime':
1119
+ rule = 'runtime-error';
1120
+ break;
1121
+ case 'promise-rejection':
1122
+ rule = 'unhandled-promise-rejection';
1123
+ break;
1124
+ }
1125
+ // Create a key for deduplication based on message and type
1126
+ const key = `${error.type}:${error.message}`;
1127
+ if (errorMap.has(key)) {
1128
+ // Increment count for duplicate
1129
+ errorMap.get(key).count++;
1130
+ }
1131
+ else {
1132
+ // Add new error
1133
+ errorMap.set(key, {
1134
+ error: {
1135
+ message: error.message,
1136
+ source: error.source,
1137
+ type: error.type,
1138
+ rule: rule
1139
+ },
1140
+ count: 1
1141
+ });
1142
+ }
937
1143
  });
938
- // Console errors don't have source info
1144
+ // Process console errors
939
1145
  errorData.consoleErrors.forEach((error) => {
940
- const errorMsg = `Console error: ${error}`;
1146
+ const key = `console-error:${error}`;
1147
+ if (errorMap.has(key)) {
1148
+ errorMap.get(key).count++;
1149
+ }
1150
+ else {
1151
+ errorMap.set(key, {
1152
+ error: {
1153
+ message: error,
1154
+ source: 'react-framework',
1155
+ type: 'console-error',
1156
+ rule: 'console-error'
1157
+ },
1158
+ count: 1
1159
+ });
1160
+ }
1161
+ });
1162
+ // Convert map to array with occurrence counts
1163
+ const errors = [];
1164
+ errorMap.forEach(({ error, count }) => {
1165
+ // Append count if > 1
1166
+ const message = count > 1
1167
+ ? `${error.message} (occurred ${count} times)`
1168
+ : error.message;
941
1169
  errors.push({
942
- message: errorMsg,
943
- source: 'react-framework' // Console errors from React are framework level
1170
+ ...error,
1171
+ message
944
1172
  });
945
1173
  });
946
1174
  return errors;
@@ -965,7 +1193,7 @@ class ComponentRunner {
965
1193
  /**
966
1194
  * Set up console logging
967
1195
  */
968
- setupConsoleLogging(page, consoleLogs, warnings, criticalWarnings) {
1196
+ setupConsoleLogging(page, consoleLogs, warnings) {
969
1197
  page.on('console', (msg) => {
970
1198
  const type = msg.type();
971
1199
  const text = msg.text();
@@ -976,10 +1204,6 @@ class ComponentRunner {
976
1204
  if (!warnings.includes(text)) {
977
1205
  warnings.push(text);
978
1206
  }
979
- // Check if it's a critical warning that should fail the test
980
- if (ComponentRunner.CRITICAL_WARNING_PATTERNS.some(pattern => pattern.test(text))) {
981
- criticalWarnings.push(text);
982
- }
983
1207
  }
984
1208
  });
985
1209
  page.on('pageerror', (error) => {
@@ -1440,12 +1664,6 @@ class ComponentRunner {
1440
1664
  console.log(` ${i + 1}. ${warn.message}`);
1441
1665
  });
1442
1666
  }
1443
- if (result.criticalWarnings && result.criticalWarnings.length > 0) {
1444
- console.log('\nšŸ”“ Critical Warnings:', result.criticalWarnings.length);
1445
- result.criticalWarnings.forEach((warn, i) => {
1446
- console.log(` ${i + 1}. ${warn}`);
1447
- });
1448
- }
1449
1667
  console.log('\n========================================\n');
1450
1668
  }
1451
1669
  }