@memberjunction/react-test-harness 2.70.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,177 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ComponentRunner = void 0;
27
+ const path = __importStar(require("path"));
28
+ const fs = __importStar(require("fs"));
29
+ class ComponentRunner {
30
+ constructor(browserManager) {
31
+ this.browserManager = browserManager;
32
+ }
33
+ async executeComponent(options) {
34
+ const startTime = Date.now();
35
+ const errors = [];
36
+ const consoleLogs = [];
37
+ try {
38
+ const page = await this.browserManager.getPage();
39
+ // Set up console logging
40
+ page.on('console', (msg) => {
41
+ consoleLogs.push({ type: msg.type(), text: msg.text() });
42
+ });
43
+ // Set up error handling
44
+ page.on('pageerror', (error) => {
45
+ errors.push(error.message);
46
+ });
47
+ // Create HTML template with React runtime
48
+ const htmlContent = this.createHTMLTemplate(options);
49
+ // Navigate to a data URL with the HTML content
50
+ await page.goto(`data:text/html;charset=utf-8,${encodeURIComponent(htmlContent)}`);
51
+ // Wait for React to render
52
+ if (options.waitForSelector) {
53
+ await this.browserManager.waitForSelector(options.waitForSelector, {
54
+ timeout: options.timeout || 30000
55
+ });
56
+ }
57
+ if (options.waitForLoadState) {
58
+ await this.browserManager.waitForLoadState(options.waitForLoadState);
59
+ }
60
+ else {
61
+ // Default wait for React to finish rendering
62
+ await page.waitForTimeout(100);
63
+ }
64
+ // Get the rendered HTML
65
+ const html = await this.browserManager.getContent();
66
+ // Take screenshot if needed
67
+ const screenshot = await this.browserManager.screenshot();
68
+ return {
69
+ success: errors.length === 0,
70
+ html,
71
+ errors,
72
+ console: consoleLogs,
73
+ screenshot,
74
+ executionTime: Date.now() - startTime
75
+ };
76
+ }
77
+ catch (error) {
78
+ errors.push(error instanceof Error ? error.message : String(error));
79
+ return {
80
+ success: false,
81
+ html: '',
82
+ errors,
83
+ console: consoleLogs,
84
+ executionTime: Date.now() - startTime
85
+ };
86
+ }
87
+ }
88
+ createHTMLTemplate(options) {
89
+ const propsJson = JSON.stringify(options.props || {});
90
+ // Generate child component registration code if needed
91
+ let childComponentCode = '';
92
+ if (options.registerChildren !== false && options.childComponents && options.childComponents.length > 0) {
93
+ childComponentCode = this.generateChildComponentRegistration(options.childComponents);
94
+ }
95
+ return `
96
+ <!DOCTYPE html>
97
+ <html>
98
+ <head>
99
+ <meta charset="utf-8">
100
+ <title>React Component Test</title>
101
+ <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
102
+ <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
103
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
104
+ <style>
105
+ body { margin: 0; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
106
+ #root { min-height: 100vh; }
107
+ </style>
108
+ </head>
109
+ <body>
110
+ <div id="root"></div>
111
+ <script type="text/babel">
112
+ ${options.setupCode || ''}
113
+
114
+ // Register child components
115
+ const registeredComponents = {};
116
+ ${childComponentCode}
117
+
118
+ const props = ${propsJson};
119
+
120
+ // Add registered components to props if main component expects them
121
+ if (Object.keys(registeredComponents).length > 0) {
122
+ props.components = registeredComponents;
123
+ }
124
+
125
+ ${options.componentCode}
126
+
127
+ // Render the component
128
+ const root = ReactDOM.createRoot(document.getElementById('root'));
129
+ root.render(React.createElement(Component, props));
130
+ </script>
131
+ </body>
132
+ </html>`;
133
+ }
134
+ generateChildComponentRegistration(specs) {
135
+ const registrationCode = [];
136
+ // Recursively process all components in dependency order
137
+ const processSpec = (spec, depth = 0) => {
138
+ // Process children first (leaf nodes)
139
+ const children = spec.childComponents || spec.components || [];
140
+ children.forEach(child => processSpec(child, depth + 1));
141
+ // Then register this component
142
+ if (spec.componentCode) {
143
+ registrationCode.push(`
144
+ // Register ${spec.componentName}
145
+ (function() {
146
+ ${spec.componentCode}
147
+ // Wrap the component to inject nested components
148
+ const WrappedComponent = (props) => {
149
+ return React.createElement(Component, {
150
+ ...props,
151
+ components: registeredComponents
152
+ });
153
+ };
154
+ registeredComponents['${spec.componentName}'] = WrappedComponent;
155
+ })();`);
156
+ }
157
+ };
158
+ // Process all specs
159
+ specs.forEach(spec => processSpec(spec));
160
+ // Return only the registration code (the object is declared in the HTML template)
161
+ return registrationCode.join('\n');
162
+ }
163
+ async executeComponentFromFile(filePath, props, options) {
164
+ const absolutePath = path.resolve(filePath);
165
+ if (!fs.existsSync(absolutePath)) {
166
+ throw new Error(`Component file not found: ${absolutePath}`);
167
+ }
168
+ const componentCode = fs.readFileSync(absolutePath, 'utf-8');
169
+ return this.executeComponent({
170
+ componentCode,
171
+ props,
172
+ ...options
173
+ });
174
+ }
175
+ }
176
+ exports.ComponentRunner = ComponentRunner;
177
+ //# sourceMappingURL=component-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-runner.js","sourceRoot":"","sources":["../../src/lib/component-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /// <reference types="node" />
2
+ import { BrowserContextOptions } from './browser-context';
3
+ import { ComponentExecutionOptions, ComponentExecutionResult, ComponentSpec } from './component-runner';
4
+ import { AssertionHelpers } from './assertion-helpers';
5
+ export interface TestHarnessOptions extends BrowserContextOptions {
6
+ debug?: boolean;
7
+ screenshotOnError?: boolean;
8
+ screenshotPath?: string;
9
+ }
10
+ export declare class ReactTestHarness {
11
+ private browserManager;
12
+ private componentRunner;
13
+ private options;
14
+ constructor(options?: TestHarnessOptions);
15
+ initialize(): Promise<void>;
16
+ testComponent(componentCode: string, props?: Record<string, any>, options?: Partial<ComponentExecutionOptions>): Promise<ComponentExecutionResult>;
17
+ testComponentFromFile(filePath: string, props?: Record<string, any>, options?: Partial<ComponentExecutionOptions>): Promise<ComponentExecutionResult>;
18
+ testComponentHierarchy(rootSpec: ComponentSpec, props?: Record<string, any>, options?: Partial<ComponentExecutionOptions>): Promise<ComponentExecutionResult>;
19
+ testComponentFromFileWithChildren(filePath: string, childComponents: ComponentSpec[], props?: Record<string, any>, options?: Partial<ComponentExecutionOptions>): Promise<ComponentExecutionResult>;
20
+ private collectChildComponents;
21
+ runTest(name: string, testFn: () => Promise<void>): Promise<{
22
+ name: string;
23
+ passed: boolean;
24
+ error?: string;
25
+ duration: number;
26
+ }>;
27
+ runTests(tests: Array<{
28
+ name: string;
29
+ fn: () => Promise<void>;
30
+ }>): Promise<{
31
+ total: number;
32
+ passed: number;
33
+ failed: number;
34
+ duration: number;
35
+ results: Array<{
36
+ name: string;
37
+ passed: boolean;
38
+ error?: string;
39
+ duration: number;
40
+ }>;
41
+ }>;
42
+ getAssertionHelpers(): typeof AssertionHelpers;
43
+ createMatcher(html: string): {
44
+ toContainText: (text: string) => void;
45
+ toHaveElement: (selector: string) => void;
46
+ toHaveElementCount: (tagName: string, count: number) => void;
47
+ toHaveAttribute: (selector: string, attribute: string, value?: string | undefined) => void;
48
+ };
49
+ close(): Promise<void>;
50
+ screenshot(path?: string): Promise<Buffer>;
51
+ reload(): Promise<void>;
52
+ navigateTo(url: string): Promise<void>;
53
+ evaluateInPage<T>(fn: (...args: any[]) => T, ...args: any[]): Promise<T>;
54
+ }
55
+ //# sourceMappingURL=test-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-harness.d.ts","sourceRoot":"","sources":["../../src/lib/test-harness.ts"],"names":[],"mappings":";AAAA,OAAO,EAAkB,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAmB,yBAAyB,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACzH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAKvD,MAAM,WAAW,kBAAmB,SAAQ,qBAAqB;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,GAAE,kBAAuB;IAYtC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,aAAa,CACjB,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAC3C,OAAO,CAAC,wBAAwB,CAAC;IA0B9B,qBAAqB,CACzB,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAC3C,OAAO,CAAC,wBAAwB,CAAC;IAI9B,sBAAsB,CAC1B,QAAQ,EAAE,aAAa,EACvB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAC3C,OAAO,CAAC,wBAAwB,CAAC;IA2B9B,iCAAiC,CACrC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,aAAa,EAAE,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAC3C,OAAO,CAAC,wBAAwB,CAAC;IAkBpC,OAAO,CAAC,sBAAsB;IAiBxB,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAC1B,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAyBzE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC;QAC/E,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,OAAO,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACrF,CAAC;IA0BF,mBAAmB;IAInB,aAAa,CAAC,IAAI,EAAE,MAAM;;;;;;IAIpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;CAG/E"}
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ReactTestHarness = void 0;
27
+ const browser_context_1 = require("./browser-context");
28
+ const component_runner_1 = require("./component-runner");
29
+ const assertion_helpers_1 = require("./assertion-helpers");
30
+ const path = __importStar(require("path"));
31
+ const fs = __importStar(require("fs"));
32
+ class ReactTestHarness {
33
+ constructor(options = {}) {
34
+ this.options = {
35
+ headless: true,
36
+ debug: false,
37
+ screenshotOnError: true,
38
+ ...options
39
+ };
40
+ this.browserManager = new browser_context_1.BrowserManager(this.options);
41
+ this.componentRunner = new component_runner_1.ComponentRunner(this.browserManager);
42
+ }
43
+ async initialize() {
44
+ await this.browserManager.initialize();
45
+ }
46
+ async testComponent(componentCode, props, options) {
47
+ const result = await this.componentRunner.executeComponent({
48
+ componentCode,
49
+ props,
50
+ ...options
51
+ });
52
+ if (this.options.debug) {
53
+ console.log('=== Test Execution Debug Info ===');
54
+ console.log('Success:', result.success);
55
+ console.log('Execution Time:', result.executionTime, 'ms');
56
+ console.log('Errors:', result.errors);
57
+ console.log('Console Output:', result.console);
58
+ console.log('================================');
59
+ }
60
+ if (!result.success && this.options.screenshotOnError && result.screenshot) {
61
+ const screenshotPath = this.options.screenshotPath || './error-screenshot.png';
62
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
63
+ fs.writeFileSync(screenshotPath, result.screenshot);
64
+ console.log(`Screenshot saved to: ${screenshotPath}`);
65
+ }
66
+ return result;
67
+ }
68
+ async testComponentFromFile(filePath, props, options) {
69
+ return await this.componentRunner.executeComponentFromFile(filePath, props, options);
70
+ }
71
+ async testComponentHierarchy(rootSpec, props, options) {
72
+ if (!rootSpec.componentCode) {
73
+ throw new Error(`Root component ${rootSpec.componentName} must have componentCode`);
74
+ }
75
+ // Collect all child components from the hierarchy
76
+ const childComponents = this.collectChildComponents(rootSpec);
77
+ // Execute the root component with all children registered
78
+ const result = await this.componentRunner.executeComponent({
79
+ componentCode: rootSpec.componentCode,
80
+ props,
81
+ childComponents,
82
+ registerChildren: true,
83
+ ...options
84
+ });
85
+ if (this.options.debug) {
86
+ console.log('=== Component Hierarchy Test Debug Info ===');
87
+ console.log('Root Component:', rootSpec.componentName);
88
+ console.log('Child Components:', childComponents.map(c => c.componentName));
89
+ console.log('==========================================');
90
+ }
91
+ return result;
92
+ }
93
+ async testComponentFromFileWithChildren(filePath, childComponents, props, options) {
94
+ const absolutePath = path.resolve(filePath);
95
+ if (!fs.existsSync(absolutePath)) {
96
+ throw new Error(`Component file not found: ${absolutePath}`);
97
+ }
98
+ const componentCode = fs.readFileSync(absolutePath, 'utf-8');
99
+ return await this.componentRunner.executeComponent({
100
+ componentCode,
101
+ props,
102
+ childComponents,
103
+ registerChildren: true,
104
+ ...options
105
+ });
106
+ }
107
+ collectChildComponents(spec) {
108
+ const collected = [];
109
+ const processSpec = (s) => {
110
+ const children = s.childComponents || s.components || [];
111
+ children.forEach(child => {
112
+ if (child.componentCode) {
113
+ collected.push(child);
114
+ }
115
+ processSpec(child);
116
+ });
117
+ };
118
+ processSpec(spec);
119
+ return collected;
120
+ }
121
+ async runTest(name, testFn) {
122
+ const startTime = Date.now();
123
+ try {
124
+ await testFn();
125
+ const duration = Date.now() - startTime;
126
+ if (this.options.debug) {
127
+ console.log(`✓ ${name} (${duration}ms)`);
128
+ }
129
+ return { name, passed: true, duration };
130
+ }
131
+ catch (error) {
132
+ const duration = Date.now() - startTime;
133
+ const errorMessage = error instanceof Error ? error.message : String(error);
134
+ if (this.options.debug) {
135
+ console.log(`✗ ${name} (${duration}ms)`);
136
+ console.error(` Error: ${errorMessage}`);
137
+ }
138
+ return { name, passed: false, error: errorMessage, duration };
139
+ }
140
+ }
141
+ async runTests(tests) {
142
+ const startTime = Date.now();
143
+ const results = [];
144
+ for (const test of tests) {
145
+ const result = await this.runTest(test.name, test.fn);
146
+ results.push(result);
147
+ }
148
+ const total = results.length;
149
+ const passed = results.filter(r => r.passed).length;
150
+ const failed = total - passed;
151
+ const duration = Date.now() - startTime;
152
+ if (this.options.debug) {
153
+ console.log('\n=== Test Summary ===');
154
+ console.log(`Total: ${total}`);
155
+ console.log(`Passed: ${passed}`);
156
+ console.log(`Failed: ${failed}`);
157
+ console.log(`Duration: ${duration}ms`);
158
+ console.log('==================');
159
+ }
160
+ return { total, passed, failed, duration, results };
161
+ }
162
+ getAssertionHelpers() {
163
+ return assertion_helpers_1.AssertionHelpers;
164
+ }
165
+ createMatcher(html) {
166
+ return assertion_helpers_1.AssertionHelpers.createMatcher(html);
167
+ }
168
+ async close() {
169
+ await this.browserManager.close();
170
+ }
171
+ async screenshot(path) {
172
+ return await this.browserManager.screenshot(path);
173
+ }
174
+ async reload() {
175
+ await this.browserManager.reload();
176
+ }
177
+ async navigateTo(url) {
178
+ await this.browserManager.navigateTo(url);
179
+ }
180
+ async evaluateInPage(fn, ...args) {
181
+ return await this.browserManager.evaluateInPage(fn, ...args);
182
+ }
183
+ }
184
+ exports.ReactTestHarness = ReactTestHarness;
185
+ //# sourceMappingURL=test-harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-harness.js","sourceRoot":"","sources":["../../src/lib/test-harness.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@memberjunction/react-test-harness",
3
+ "version": "2.70.0",
4
+ "description": "React component test harness for MemberJunction using Playwright",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "mj-react-test": "./dist/cli/index.js"
9
+ },
10
+ "files": [
11
+ "/dist"
12
+ ],
13
+ "scripts": {
14
+ "start": "ts-node-dev src/index.ts",
15
+ "build": "tsc",
16
+ "test": "echo \"Error: no test specified\" && exit 1"
17
+ },
18
+ "author": "MemberJunction.com",
19
+ "license": "ISC",
20
+ "devDependencies": {
21
+ "ts-node-dev": "^2.0.0",
22
+ "typescript": "^5.4.5"
23
+ },
24
+ "dependencies": {
25
+ "@memberjunction/react-runtime": "^2.70.0",
26
+ "@playwright/test": "^1.40.0",
27
+ "playwright": "^1.40.0",
28
+ "commander": "^11.1.0",
29
+ "chalk": "^4.1.2",
30
+ "ora": "^5.4.1"
31
+ }
32
+ }