testchimp-runner-core 0.0.1

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.
Files changed (74) hide show
  1. package/dist/auth-config.d.ts +33 -0
  2. package/dist/auth-config.d.ts.map +1 -0
  3. package/dist/auth-config.js +69 -0
  4. package/dist/auth-config.js.map +1 -0
  5. package/dist/env-loader.d.ts +20 -0
  6. package/dist/env-loader.d.ts.map +1 -0
  7. package/dist/env-loader.js +83 -0
  8. package/dist/env-loader.js.map +1 -0
  9. package/dist/execution-service.d.ts +61 -0
  10. package/dist/execution-service.d.ts.map +1 -0
  11. package/dist/execution-service.js +822 -0
  12. package/dist/execution-service.js.map +1 -0
  13. package/dist/file-handler.d.ts +59 -0
  14. package/dist/file-handler.d.ts.map +1 -0
  15. package/dist/file-handler.js +75 -0
  16. package/dist/file-handler.js.map +1 -0
  17. package/dist/index.d.ts +46 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +196 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/llm-facade.d.ts +101 -0
  22. package/dist/llm-facade.d.ts.map +1 -0
  23. package/dist/llm-facade.js +289 -0
  24. package/dist/llm-facade.js.map +1 -0
  25. package/dist/playwright-mcp-service.d.ts +42 -0
  26. package/dist/playwright-mcp-service.d.ts.map +1 -0
  27. package/dist/playwright-mcp-service.js +167 -0
  28. package/dist/playwright-mcp-service.js.map +1 -0
  29. package/dist/prompts.d.ts +34 -0
  30. package/dist/prompts.d.ts.map +1 -0
  31. package/dist/prompts.js +237 -0
  32. package/dist/prompts.js.map +1 -0
  33. package/dist/scenario-service.d.ts +25 -0
  34. package/dist/scenario-service.d.ts.map +1 -0
  35. package/dist/scenario-service.js +119 -0
  36. package/dist/scenario-service.js.map +1 -0
  37. package/dist/scenario-worker-class.d.ts +30 -0
  38. package/dist/scenario-worker-class.d.ts.map +1 -0
  39. package/dist/scenario-worker-class.js +263 -0
  40. package/dist/scenario-worker-class.js.map +1 -0
  41. package/dist/script-utils.d.ts +44 -0
  42. package/dist/script-utils.d.ts.map +1 -0
  43. package/dist/script-utils.js +100 -0
  44. package/dist/script-utils.js.map +1 -0
  45. package/dist/types.d.ts +171 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +28 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/utils/browser-utils.d.ts +13 -0
  50. package/dist/utils/browser-utils.d.ts.map +1 -0
  51. package/dist/utils/browser-utils.js +269 -0
  52. package/dist/utils/browser-utils.js.map +1 -0
  53. package/dist/utils/page-info-utils.d.ts +16 -0
  54. package/dist/utils/page-info-utils.d.ts.map +1 -0
  55. package/dist/utils/page-info-utils.js +77 -0
  56. package/dist/utils/page-info-utils.js.map +1 -0
  57. package/env.prod +1 -0
  58. package/env.staging +1 -0
  59. package/package.json +38 -0
  60. package/src/auth-config.ts +84 -0
  61. package/src/env-loader.ts +91 -0
  62. package/src/execution-service.ts +999 -0
  63. package/src/file-handler.ts +104 -0
  64. package/src/index.ts +205 -0
  65. package/src/llm-facade.ts +413 -0
  66. package/src/playwright-mcp-service.ts +203 -0
  67. package/src/prompts.ts +247 -0
  68. package/src/scenario-service.ts +138 -0
  69. package/src/scenario-worker-class.ts +330 -0
  70. package/src/script-utils.ts +109 -0
  71. package/src/types.ts +202 -0
  72. package/src/utils/browser-utils.ts +272 -0
  73. package/src/utils/page-info-utils.ts +93 -0
  74. package/tsconfig.json +19 -0
@@ -0,0 +1,272 @@
1
+ import { chromium, firefox, webkit, Browser, BrowserContext, Page } from 'playwright';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import * as os from 'os';
5
+ import { build } from 'esbuild';
6
+
7
+ /**
8
+ * Initialize browser with Playwright configuration
9
+ * @param playwrightConfig - JavaScript config file content (playwright.config.js)
10
+ * @param headless - Override headless mode (optional)
11
+ * @returns Browser, context, and page instances
12
+ */
13
+ export async function initializeBrowser(
14
+ playwrightConfigContent?: string,
15
+ headless?: boolean,
16
+ playwrightConfigFilePath?: string
17
+ ): Promise<{ browser: Browser; context: BrowserContext; page: Page }> {
18
+ console.log('Initializing browser with Playwright');
19
+
20
+ let contextOptions: any = {};
21
+
22
+ // Use Playwright config content if provided
23
+ if (playwrightConfigContent) {
24
+ console.log('Using provided Playwright config content');
25
+
26
+ try {
27
+ // Transpile the config content in-memory and evaluate it
28
+ console.log(`Transpiling config content (${playwrightConfigContent.length} characters)`);
29
+
30
+ const result = await build({
31
+ stdin: {
32
+ contents: playwrightConfigContent,
33
+ resolveDir: process.cwd(),
34
+ },
35
+ bundle: true,
36
+ platform: 'node',
37
+ format: 'cjs',
38
+ sourcemap: false,
39
+ target: 'node18',
40
+ logLevel: 'silent',
41
+ write: false, // Don't write to file, get the result in memory
42
+ external: [
43
+ '@playwright/test',
44
+ 'playwright',
45
+ 'playwright-core'
46
+ ]
47
+ });
48
+
49
+ if (!result.outputFiles || result.outputFiles.length === 0) {
50
+ throw new Error('esbuild failed to generate output');
51
+ }
52
+
53
+ const transpiledCode = result.outputFiles[0].text;
54
+ console.log(`Transpilation complete. Generated ${transpiledCode.length} characters of code`);
55
+
56
+ // Evaluate the transpiled code in a safe context
57
+ const loadedConfig = eval(transpiledCode);
58
+ console.log('Loaded config object:', loadedConfig);
59
+ console.log('Config type:', typeof loadedConfig);
60
+ console.log('Config keys:', loadedConfig ? Object.keys(loadedConfig) : 'null/undefined');
61
+
62
+ // Get the actual config from the default export (ES module transpiled to CommonJS)
63
+ const actualConfig = loadedConfig.default || loadedConfig;
64
+
65
+ if (actualConfig && typeof actualConfig === 'object') {
66
+ console.log('Successfully loaded Playwright config from content');
67
+ console.log(`Config keys: ${Object.keys(actualConfig).join(', ')}`);
68
+
69
+ // Extract context options from the config
70
+ if (actualConfig.use && actualConfig.use.contextOptions) {
71
+ contextOptions = { ...contextOptions, ...actualConfig.use.contextOptions };
72
+ console.log('Applied context options from config');
73
+ }
74
+
75
+ // Apply other config settings
76
+ if (actualConfig.use && actualConfig.use.headless !== undefined) {
77
+ // Override headless mode if specified in config and not explicitly overridden
78
+ if (headless === undefined) {
79
+ headless = actualConfig.use.headless;
80
+ console.log(`Using headless mode from config: ${headless}`);
81
+ }
82
+ }
83
+
84
+ // Apply timeout settings
85
+ if (actualConfig.use && actualConfig.use.actionTimeout) {
86
+ console.log(`Using action timeout from config: ${actualConfig.use.actionTimeout}ms`);
87
+ }
88
+
89
+ // Apply viewport settings
90
+ if (actualConfig.use && actualConfig.use.viewport) {
91
+ contextOptions.viewport = actualConfig.use.viewport;
92
+ console.log(`Using viewport from config: ${JSON.stringify(actualConfig.use.viewport)}`);
93
+ }
94
+
95
+ // Apply user agent
96
+ if (actualConfig.use && actualConfig.use.userAgent) {
97
+ contextOptions.userAgent = actualConfig.use.userAgent;
98
+ console.log(`Using user agent from config: ${actualConfig.use.userAgent}`);
99
+ }
100
+
101
+ // Apply other context options
102
+ if (actualConfig.use && actualConfig.use.extraHTTPHeaders) {
103
+ contextOptions.extraHTTPHeaders = actualConfig.use.extraHTTPHeaders;
104
+ console.log(`Using extra HTTP headers from config`);
105
+ }
106
+
107
+ if (actualConfig.use && actualConfig.use.locale) {
108
+ contextOptions.locale = actualConfig.use.locale;
109
+ console.log(`Using locale from config: ${actualConfig.use.locale}`);
110
+ }
111
+
112
+ if (actualConfig.use && actualConfig.use.timezoneId) {
113
+ contextOptions.timezoneId = actualConfig.use.timezoneId;
114
+ console.log(`Using timezone from config: ${actualConfig.use.timezoneId}`);
115
+ }
116
+
117
+ if (actualConfig.use && actualConfig.use.geolocation) {
118
+ contextOptions.geolocation = actualConfig.use.geolocation;
119
+ console.log(`Using geolocation from config: ${JSON.stringify(actualConfig.use.geolocation)}`);
120
+ }
121
+
122
+ if (actualConfig.use && actualConfig.use.permissions) {
123
+ contextOptions.permissions = actualConfig.use.permissions;
124
+ console.log(`Using permissions from config: ${JSON.stringify(actualConfig.use.permissions)}`);
125
+ }
126
+
127
+ if (actualConfig.use && actualConfig.use.colorScheme) {
128
+ contextOptions.colorScheme = actualConfig.use.colorScheme;
129
+ console.log(`Using color scheme from config: ${actualConfig.use.colorScheme}`);
130
+ }
131
+
132
+ if (actualConfig.use && actualConfig.use.reducedMotion) {
133
+ contextOptions.reducedMotion = actualConfig.use.reducedMotion;
134
+ console.log(`Using reduced motion from config: ${actualConfig.use.reducedMotion}`);
135
+ }
136
+
137
+ if (actualConfig.use && actualConfig.use.forcedColors) {
138
+ contextOptions.forcedColors = actualConfig.use.forcedColors;
139
+ console.log(`Using forced colors from config: ${actualConfig.use.forcedColors}`);
140
+ }
141
+
142
+ if (actualConfig.use && actualConfig.use.acceptDownloads) {
143
+ contextOptions.acceptDownloads = actualConfig.use.acceptDownloads;
144
+ console.log(`Using accept downloads from config: ${actualConfig.use.acceptDownloads}`);
145
+ }
146
+
147
+ if (actualConfig.use && actualConfig.use.bypassCSP) {
148
+ contextOptions.bypassCSP = actualConfig.use.bypassCSP;
149
+ console.log(`Using bypass CSP from config: ${actualConfig.use.bypassCSP}`);
150
+ }
151
+
152
+ if (actualConfig.use && actualConfig.use.javaScriptEnabled) {
153
+ contextOptions.javaScriptEnabled = actualConfig.use.javaScriptEnabled;
154
+ console.log(`Using JavaScript enabled from config: ${actualConfig.use.javaScriptEnabled}`);
155
+ }
156
+
157
+ if (actualConfig.use && actualConfig.use.ignoreHTTPSErrors) {
158
+ contextOptions.ignoreHTTPSErrors = actualConfig.use.ignoreHTTPSErrors;
159
+ console.log(`Using ignore HTTPS errors from config: ${actualConfig.use.ignoreHTTPSErrors}`);
160
+ }
161
+
162
+ console.log(`Final context options: ${JSON.stringify(contextOptions, null, 2)}`);
163
+ } else {
164
+ console.log('Config loaded but no valid configuration found');
165
+ }
166
+ } catch (error) {
167
+ console.error(`Error transpiling config content: ${error}`);
168
+ console.log('Falling back to default configuration');
169
+ }
170
+ } else if (playwrightConfigFilePath) {
171
+ // Fallback to file path if no content provided (for backward compatibility)
172
+ console.log('No config content provided, falling back to file path');
173
+ // Resolve the path - it might be relative or absolute
174
+ const resolvedPath = path.isAbsolute(playwrightConfigFilePath)
175
+ ? playwrightConfigFilePath
176
+ : path.resolve(process.cwd(), playwrightConfigFilePath);
177
+
178
+ console.log(`Looking for Playwright config at: ${resolvedPath}`);
179
+ console.log(`File exists: ${fs.existsSync(resolvedPath)}`);
180
+
181
+ if (fs.existsSync(resolvedPath)) {
182
+ console.log(`Loading Playwright config from: ${resolvedPath}`);
183
+
184
+ try {
185
+ // Transpile the config in-memory and evaluate it
186
+ console.log(`Transpiling config in-memory from: ${resolvedPath}`);
187
+
188
+ const result = await build({
189
+ entryPoints: [resolvedPath],
190
+ bundle: true,
191
+ platform: 'node',
192
+ format: 'cjs',
193
+ sourcemap: false,
194
+ target: 'node18',
195
+ logLevel: 'silent',
196
+ write: false, // Don't write to file, get the result in memory
197
+ external: [
198
+ '@playwright/test',
199
+ 'playwright',
200
+ 'playwright-core'
201
+ ]
202
+ });
203
+
204
+ if (!result.outputFiles || result.outputFiles.length === 0) {
205
+ throw new Error('esbuild failed to generate output');
206
+ }
207
+
208
+ const transpiledCode = result.outputFiles[0].text;
209
+ console.log(`Transpilation complete. Generated ${transpiledCode.length} characters of code`);
210
+
211
+ // Evaluate the transpiled code in a safe context
212
+ const loadedConfig = eval(transpiledCode);
213
+ console.log('Loaded config object:', loadedConfig);
214
+ console.log('Config type:', typeof loadedConfig);
215
+ console.log('Config keys:', loadedConfig ? Object.keys(loadedConfig) : 'null/undefined');
216
+
217
+ // Get the actual config from the default export (ES module transpiled to CommonJS)
218
+ const actualConfig = loadedConfig.default || loadedConfig;
219
+ console.log('Actual config:', actualConfig);
220
+ console.log('Actual config keys:', actualConfig ? Object.keys(actualConfig) : 'null/undefined');
221
+
222
+ if (!actualConfig) {
223
+ console.log('Config import did not return a valid config; using defaults');
224
+ } else {
225
+ // Apply global use options
226
+ if (actualConfig.use) {
227
+ contextOptions = { ...actualConfig.use };
228
+ console.log('Applied context options from Playwright config:', contextOptions);
229
+ } else {
230
+ console.log('No use property found in config');
231
+ }
232
+ // Apply first project overrides if present
233
+ if (Array.isArray(actualConfig.projects) && actualConfig.projects.length > 0) {
234
+ const firstProject = actualConfig.projects[0];
235
+ if (firstProject && firstProject.use) {
236
+ contextOptions = { ...contextOptions, ...firstProject.use };
237
+ console.log('Applied project-specific options:', firstProject.use);
238
+ }
239
+ } else {
240
+ console.log('No projects found in config');
241
+ }
242
+ }
243
+
244
+ // No cleanup needed - we used in-memory transpilation
245
+
246
+ } catch (error) {
247
+ console.log(`Failed to load Playwright config via esbuild/import: ${error}`);
248
+ console.log('Using default browser settings');
249
+ }
250
+ } else {
251
+ console.log(`Playwright config file not found at: ${resolvedPath}`);
252
+ console.log('Using default browser settings');
253
+ }
254
+ }
255
+
256
+ // Use chromium as default browser
257
+ const browser = await chromium.launch({
258
+ headless: headless !== undefined ? headless : false
259
+ });
260
+
261
+ // Create context with config options or defaults
262
+ const context = await browser.newContext(contextOptions);
263
+ const page = await context.newPage();
264
+
265
+ // Set default timeout to 5 seconds (unless overridden by playwright config)
266
+ if (!contextOptions.timeout) {
267
+ context.setDefaultTimeout(5000);
268
+ page.setDefaultTimeout(5000);
269
+ }
270
+
271
+ return { browser, context, page };
272
+ }
@@ -0,0 +1,93 @@
1
+ import { Page } from 'playwright';
2
+
3
+ export interface PageInfo {
4
+ url: string;
5
+ title: string;
6
+ elements: string;
7
+ formFields: string;
8
+ interactiveElements: string;
9
+ pageStructure: string;
10
+ }
11
+
12
+ export async function getEnhancedPageInfo(page: Page): Promise<PageInfo>;
13
+ export async function getEnhancedPageInfo(domSnapshot: { url: string; title: string; accessibilityTree: any }): Promise<PageInfo>;
14
+ export async function getEnhancedPageInfo(input: Page | { url: string; title: string; accessibilityTree: any }): Promise<PageInfo> {
15
+ let domSnapshot: { url: string; title: string; accessibilityTree: any } = { url: 'Unknown', title: 'Unknown', accessibilityTree: null };
16
+
17
+ try {
18
+ if ('accessibility' in input) {
19
+ // Input is a Page object
20
+ const snapshot = await input.accessibility.snapshot();
21
+ const url = input.url();
22
+ const title = await input.title();
23
+ domSnapshot = { url, title, accessibilityTree: snapshot };
24
+ } else {
25
+ // Input is already a domSnapshot
26
+ domSnapshot = input;
27
+ }
28
+
29
+ // Extract key information from accessibility tree
30
+ const elements: string[] = [];
31
+ const formFields: string[] = [];
32
+ const interactiveElements: string[] = [];
33
+ const pageStructure: string[] = [];
34
+
35
+ const extractElements = (node: any, depth = 0) => {
36
+ if (depth > 4) return; // Limit depth to avoid overwhelming output
37
+
38
+ if (node && typeof node === 'object') {
39
+ if (node.role) {
40
+ const elementInfo = `${node.role}${node.name ? `: ${node.name}` : ''}`;
41
+ elements.push(elementInfo);
42
+
43
+ // Categorize elements
44
+ if (['textbox', 'button', 'link', 'checkbox', 'radio', 'combobox', 'slider'].includes(node.role)) {
45
+ interactiveElements.push(elementInfo);
46
+ }
47
+
48
+ if (['textbox', 'checkbox', 'radio', 'combobox', 'slider'].includes(node.role)) {
49
+ formFields.push(elementInfo);
50
+ }
51
+
52
+ if (['main', 'navigation', 'banner', 'contentinfo', 'complementary', 'search'].includes(node.role)) {
53
+ pageStructure.push(elementInfo);
54
+ }
55
+ }
56
+
57
+ if (node.children) {
58
+ node.children.forEach((child: any) => extractElements(child, depth + 1));
59
+ }
60
+ }
61
+ };
62
+
63
+ extractElements(domSnapshot.accessibilityTree);
64
+
65
+ // Create a more focused summary
66
+ const getElementSummary = (elementList: string[], maxItems: number, category: string) => {
67
+ if (elementList.length === 0) return `No ${category} found`;
68
+ const limited = elementList.slice(0, maxItems);
69
+ const remaining = elementList.length - maxItems;
70
+ const summary = limited.join(', ');
71
+ return remaining > 0 ? `${summary} (+${remaining} more)` : summary;
72
+ };
73
+
74
+ return {
75
+ url: domSnapshot.url,
76
+ title: domSnapshot.title,
77
+ elements: getElementSummary(elements, 15, 'elements'),
78
+ formFields: getElementSummary(formFields, 8, 'form fields'),
79
+ interactiveElements: getElementSummary(interactiveElements, 12, 'interactive elements'),
80
+ pageStructure: getElementSummary(pageStructure, 6, 'page sections')
81
+ };
82
+ } catch (error) {
83
+ console.error('Error extracting page info:', error);
84
+ return {
85
+ url: domSnapshot?.url || 'Unknown',
86
+ title: 'Unknown',
87
+ elements: 'Unable to extract',
88
+ formFields: 'Unable to extract',
89
+ interactiveElements: 'Unable to extract',
90
+ pageStructure: 'Unable to extract'
91
+ };
92
+ }
93
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true,
15
+ "resolveJsonModule": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
19
+ }