@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.
- package/dist/lib/component-linter.d.ts.map +1 -1
- package/dist/lib/component-linter.js +55 -12
- package/dist/lib/component-linter.js.map +1 -1
- package/dist/lib/component-runner.d.ts +0 -1
- package/dist/lib/component-runner.d.ts.map +1 -1
- package/dist/lib/component-runner.js +258 -40
- package/dist/lib/component-runner.js.map +1 -1
- package/dist/lib/library-lint-cache.d.ts +4 -0
- package/dist/lib/library-lint-cache.d.ts.map +1 -1
- package/dist/lib/library-lint-cache.js +61 -3
- package/dist/lib/library-lint-cache.js.map +1 -1
- package/dist/lib/test-harness.d.ts.map +1 -1
- package/dist/lib/test-harness.js +5 -2
- package/dist/lib/test-harness.js.map +1 -1
- package/package.json +3 -3
|
@@ -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,
|
|
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
|
|
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
|
|
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
|
|
601
|
+
success: success && dataErrors.length === 0 && criticalWarningViolations.length === 0, // Fail on critical warnings too
|
|
582
602
|
html,
|
|
583
|
-
errors:
|
|
584
|
-
warnings:
|
|
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 (...
|
|
867
|
+
window.React.createElement = function (type, props, ...children) {
|
|
850
868
|
window.__testHarnessRenderCount++;
|
|
851
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|
-
//
|
|
1144
|
+
// Process console errors
|
|
939
1145
|
errorData.consoleErrors.forEach((error) => {
|
|
940
|
-
const
|
|
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
|
-
|
|
943
|
-
|
|
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
|
|
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
|
}
|