@memberjunction/react-test-harness 5.20.0 → 5.21.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.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Fixture Loader for Component Linter Tests
3
+ *
4
+ * Loads component spec fixtures from JSON files for testing.
5
+ * Fixtures are organized into categories: broken-components, fixed-components, valid-components.
6
+ *
7
+ * Supports reference-based fixtures using $ref to point to source component specs
8
+ * in metadata/components/spec/. No database or metadata-sync dependency required.
9
+ */
10
+ import { ComponentSpec } from '@memberjunction/interactive-component-types';
11
+ export interface FixtureMetadata {
12
+ name: string;
13
+ category: 'broken' | 'fixed' | 'valid';
14
+ description?: string;
15
+ expectedViolations?: string[];
16
+ isReference?: boolean;
17
+ sourcePath?: string;
18
+ }
19
+ export interface LoadedFixture {
20
+ metadata: FixtureMetadata;
21
+ spec: ComponentSpec;
22
+ filePath: string;
23
+ }
24
+ /**
25
+ * Load a single fixture by category and name.
26
+ * Name can include nested subdirectory path (e.g. "schema-validation/entity-field-invalid").
27
+ */
28
+ export declare function loadFixture(category: 'broken' | 'fixed' | 'valid', name: string): Promise<LoadedFixture>;
29
+ /** Load all fixtures from a given category */
30
+ export declare function loadFixturesByCategory(category: 'broken' | 'fixed' | 'valid'): Promise<LoadedFixture[]>;
31
+ //# sourceMappingURL=fixture-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture-loader.d.ts","sourceRoot":"","sources":["../../../src/__tests__/component-linter/fixture-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAc5E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAoDD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA2C9G;AAED,8CAA8C;AAC9C,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAsB7G"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Fixture Loader for Component Linter Tests
3
+ *
4
+ * Loads component spec fixtures from JSON files for testing.
5
+ * Fixtures are organized into categories: broken-components, fixed-components, valid-components.
6
+ *
7
+ * Supports reference-based fixtures using $ref to point to source component specs
8
+ * in metadata/components/spec/. No database or metadata-sync dependency required.
9
+ */
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ /** Root of the fixtures directory relative to this file */
13
+ const FIXTURES_ROOT = path.resolve(__dirname, '../../../fixtures/component-linter');
14
+ /** Root of the MJ repository (for resolving $ref paths in valid-component fixtures) */
15
+ const REPO_ROOT = path.resolve(__dirname, '../../../../../..');
16
+ function isReferenceFixture(data) {
17
+ return data !== null && typeof data === 'object' && '$ref' in data && typeof data.$ref === 'string';
18
+ }
19
+ /**
20
+ * Resolve @file: references in a JSON object.
21
+ * Replaces string values like "@file:./path/to/code.js" with the file contents.
22
+ */
23
+ function resolveFileReferences(obj, basePath) {
24
+ const result = {};
25
+ for (const [key, value] of Object.entries(obj)) {
26
+ if (typeof value === 'string' && value.startsWith('@file:')) {
27
+ const filePath = path.resolve(path.dirname(basePath), value.slice('@file:'.length));
28
+ try {
29
+ result[key] = fs.readFileSync(filePath, 'utf8');
30
+ }
31
+ catch {
32
+ result[key] = value; // Keep original if file not found
33
+ }
34
+ }
35
+ else if (Array.isArray(value)) {
36
+ result[key] = value.map((item) => item !== null && typeof item === 'object' && !Array.isArray(item) ? resolveFileReferences(item, basePath) : item);
37
+ }
38
+ else if (value !== null && typeof value === 'object') {
39
+ result[key] = resolveFileReferences(value, basePath);
40
+ }
41
+ else {
42
+ result[key] = value;
43
+ }
44
+ }
45
+ return result;
46
+ }
47
+ /** Recursively collect all .json file paths from a directory */
48
+ async function getJsonFilesRecursive(dirPath, baseDir = dirPath) {
49
+ const results = [];
50
+ try {
51
+ const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
52
+ for (const entry of entries) {
53
+ const fullPath = path.join(dirPath, entry.name);
54
+ if (entry.isDirectory()) {
55
+ results.push(...(await getJsonFilesRecursive(fullPath, baseDir)));
56
+ }
57
+ else if (entry.name.endsWith('.json')) {
58
+ results.push(path.relative(baseDir, fullPath));
59
+ }
60
+ }
61
+ }
62
+ catch {
63
+ // Directory doesn't exist
64
+ }
65
+ return results;
66
+ }
67
+ /**
68
+ * Load a single fixture by category and name.
69
+ * Name can include nested subdirectory path (e.g. "schema-validation/entity-field-invalid").
70
+ */
71
+ export async function loadFixture(category, name) {
72
+ const categoryDir = `${category}-components`;
73
+ const nameWithExt = name.endsWith('.json') ? name : `${name}.json`;
74
+ const filePath = path.join(FIXTURES_ROOT, categoryDir, nameWithExt);
75
+ if (!fs.existsSync(filePath)) {
76
+ throw new Error(`Fixture not found: ${filePath}`);
77
+ }
78
+ const content = await fs.promises.readFile(filePath, 'utf8');
79
+ const rawData = JSON.parse(content);
80
+ let spec;
81
+ let isReference = false;
82
+ let sourcePath;
83
+ let descriptionOverride;
84
+ if (isReferenceFixture(rawData)) {
85
+ isReference = true;
86
+ descriptionOverride = rawData.description;
87
+ sourcePath = path.resolve(REPO_ROOT, rawData.$ref);
88
+ if (!fs.existsSync(sourcePath)) {
89
+ throw new Error(`Referenced spec not found: ${sourcePath} (from $ref: ${rawData.$ref})`);
90
+ }
91
+ const specContent = await fs.promises.readFile(sourcePath, 'utf8');
92
+ const specData = JSON.parse(specContent);
93
+ spec = resolveFileReferences(specData, sourcePath);
94
+ }
95
+ else {
96
+ spec = resolveFileReferences(rawData, filePath);
97
+ }
98
+ const metadata = {
99
+ name,
100
+ category,
101
+ description: descriptionOverride || spec.description,
102
+ expectedViolations: isReferenceFixture(rawData) ? rawData.expectedViolations : undefined,
103
+ isReference,
104
+ sourcePath,
105
+ };
106
+ return { metadata, spec, filePath };
107
+ }
108
+ /** Load all fixtures from a given category */
109
+ export async function loadFixturesByCategory(category) {
110
+ const categoryDir = `${category}-components`;
111
+ const dirPath = path.join(FIXTURES_ROOT, categoryDir);
112
+ if (!fs.existsSync(dirPath)) {
113
+ return [];
114
+ }
115
+ const jsonFiles = await getJsonFilesRecursive(dirPath);
116
+ const fixtures = [];
117
+ for (const relativePath of jsonFiles) {
118
+ const name = relativePath.replace(/\.json$/, '');
119
+ try {
120
+ fixtures.push(await loadFixture(category, name));
121
+ }
122
+ catch (err) {
123
+ // Record load failure but don't block other fixtures
124
+ console.warn(`Warning: Failed to load fixture ${category}/${name}: ${err instanceof Error ? err.message : err}`);
125
+ }
126
+ }
127
+ return fixtures;
128
+ }
129
+ //# sourceMappingURL=fixture-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture-loader.js","sourceRoot":"","sources":["../../../src/__tests__/component-linter/fixture-loader.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"component-linter.d.ts","sourceRoot":"","sources":["../../src/lib/component-linter.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAwD,MAAM,6CAA6C,CAAC;AAIlI,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAU/D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,cAAc,CAAC;IACnF,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AA0OD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,cAAc,CAAqB;IAGlD,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAQhC,OAAO,CAAC,MAAM,CAAC,cAAc;IA8B7B,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAyC3C,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAy2PpC;WAEkB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;WAmC3G,aAAa,CAC/B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,aAAa,EAC7B,eAAe,CAAC,EAAE,OAAO,EACzB,WAAW,CAAC,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,OAAO,EACnB,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,UAAU,CAAC;IA4KtB,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA+avC,OAAO,CAAC,MAAM,CAAC,eAAe;IA2B9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAyBpC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4hCzC,OAAO,CAAC,MAAM,CAAC,8BAA8B;IA0B7C;;OAEG;mBACkB,qBAAqB;IA0H1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAqDzC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,6BAA6B;IAwB5C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA+BlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA+KpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2DlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;CAqGzC"}
1
+ {"version":3,"file":"component-linter.d.ts","sourceRoot":"","sources":["../../src/lib/component-linter.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAwD,MAAM,6CAA6C,CAAC;AAIlI,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAU/D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,cAAc,CAAC;IACnF,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AA0OD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,cAAc,CAAqB;IAGlD,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAQhC,OAAO,CAAC,MAAM,CAAC,cAAc;IA8B7B,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAyC3C,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAk4PpC;WAEkB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;WAmC3G,aAAa,CAC/B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,aAAa,EAC7B,eAAe,CAAC,EAAE,OAAO,EACzB,WAAW,CAAC,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,OAAO,EACnB,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,UAAU,CAAC;IA4KtB,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA+avC,OAAO,CAAC,MAAM,CAAC,eAAe;IA2B9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAyBpC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4hCzC,OAAO,CAAC,MAAM,CAAC,8BAA8B;IA0B7C;;OAEG;mBACkB,qBAAqB;IA0H1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAqDzC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,6BAA6B;IAwB5C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA+BlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA+KpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2DlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;CAqGzC"}
@@ -7216,9 +7216,30 @@ const extendedCallbacks = { ...callbacks, onCustomEvent: handler };
7216
7216
  // No queries defined, so no violation
7217
7217
  return violations;
7218
7218
  }
7219
- // Track whether RunQuery is called anywhere
7219
+ const allQueryNames = componentSpec.dataRequirements.queries.map((q) => q.name).filter(Boolean);
7220
+ // In hierarchical components, the root's dataRequirements contains the complete
7221
+ // set of queries for the entire tree, but child components can own subsets and
7222
+ // call RunQuery themselves. Collect query names claimed by child dependencies
7223
+ // so we only require the root to call RunQuery for unclaimed queries.
7224
+ const childClaimedQueries = new Set();
7225
+ if (componentSpec.dependencies) {
7226
+ for (const dep of componentSpec.dependencies) {
7227
+ if (dep.dataRequirements?.queries) {
7228
+ for (const q of dep.dataRequirements.queries) {
7229
+ if (q.name) {
7230
+ childClaimedQueries.add(q.name);
7231
+ }
7232
+ }
7233
+ }
7234
+ }
7235
+ }
7236
+ const unclaimedQueryNames = allQueryNames.filter((name) => !childClaimedQueries.has(name));
7237
+ // If all queries are delegated to child components, no violation for the root
7238
+ if (unclaimedQueryNames.length === 0) {
7239
+ return violations;
7240
+ }
7241
+ // Track whether RunQuery is called anywhere in the root component's code
7220
7242
  let hasRunQueryCall = false;
7221
- const queryNames = componentSpec.dataRequirements.queries.map((q) => q.name).filter(Boolean);
7222
7243
  traverse(ast, {
7223
7244
  CallExpression(path) {
7224
7245
  // Check for utilities.rq.RunQuery pattern
@@ -7242,27 +7263,27 @@ const extendedCallbacks = { ...callbacks, onCustomEvent: handler };
7242
7263
  }
7243
7264
  },
7244
7265
  });
7245
- // If queries are defined but RunQuery is never called, that's a critical violation
7266
+ // If unclaimed queries exist but RunQuery is never called, that's a critical violation
7246
7267
  if (!hasRunQueryCall) {
7247
7268
  violations.push({
7248
7269
  rule: 'required-queries-not-called',
7249
7270
  severity: 'critical',
7250
7271
  line: 1,
7251
7272
  column: 0,
7252
- message: `Component has ${queryNames.length} defined ${queryNames.length === 1 ? 'query' : 'queries'} in dataRequirements (mode: '${mode}') but never calls RunQuery. Queries defined: ${queryNames.join(', ')}`,
7273
+ message: `Component has ${unclaimedQueryNames.length} defined ${unclaimedQueryNames.length === 1 ? 'query' : 'queries'} in dataRequirements (mode: '${mode}') but never calls RunQuery. Queries defined: ${unclaimedQueryNames.join(', ')}`,
7253
7274
  suggestion: {
7254
7275
  text: `When dataRequirements.mode is '${mode}' and includes queries, you must use utilities.rq.RunQuery to execute them, not RunView.`,
7255
- example: `// Your dataRequirements defines these queries: ${queryNames.join(', ')}
7276
+ example: `// Your dataRequirements defines these queries: ${unclaimedQueryNames.join(', ')}
7256
7277
  // Mode is set to: '${mode}'
7257
7278
 
7258
7279
  // ❌ WRONG - Using RunView for a query:
7259
7280
  const result = await utilities.rv.RunView({
7260
- EntityName: '${queryNames[0] || 'QueryName'}'
7281
+ EntityName: '${unclaimedQueryNames[0] || 'QueryName'}'
7261
7282
  });
7262
7283
 
7263
7284
  // ✅ CORRECT - Using RunQuery for queries:
7264
7285
  const result = await utilities.rq.RunQuery({
7265
- QueryName: '${queryNames[0] || 'QueryName'}'
7286
+ QueryName: '${unclaimedQueryNames[0] || 'QueryName'}'
7266
7287
  });
7267
7288
 
7268
7289
  // Key differences: