intellitester 0.2.20 → 0.2.22

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.
@@ -129,7 +129,17 @@ var appwriteVerifyEmailActionSchema = z.object({
129
129
  var debugActionSchema = z.object({
130
130
  type: z.literal("debug")
131
131
  }).describe("Pause execution and open Playwright Inspector for debugging");
132
- var ActionSchema = z.discriminatedUnion("type", [
132
+ var waitForSelectorActionSchema = z.object({
133
+ type: z.literal("waitForSelector"),
134
+ target: LocatorSchema,
135
+ state: z.enum(["enabled", "disabled", "visible", "hidden", "attached", "detached"]).describe("Element state to wait for"),
136
+ timeout: z.number().int().positive().optional().describe("Time to wait in milliseconds")
137
+ }).describe("Wait for an element to reach a specific state");
138
+ var failActionSchema = z.object({
139
+ type: z.literal("fail"),
140
+ message: nonEmptyString.describe("Error message to display when test fails")
141
+ }).describe("Explicitly fail the test with a custom message");
142
+ var BaseActionSchema = z.discriminatedUnion("type", [
133
143
  navigateActionSchema,
134
144
  tapActionSchema,
135
145
  inputActionSchema,
@@ -150,8 +160,20 @@ var ActionSchema = z.discriminatedUnion("type", [
150
160
  emailExtractLinkActionSchema,
151
161
  emailClearActionSchema,
152
162
  appwriteVerifyEmailActionSchema,
153
- debugActionSchema
163
+ debugActionSchema,
164
+ waitForSelectorActionSchema,
165
+ failActionSchema
154
166
  ]);
167
+ var conditionalActionSchema = z.object({
168
+ type: z.literal("conditional"),
169
+ condition: z.object({
170
+ type: z.enum(["exists", "notExists", "visible", "hidden"]),
171
+ target: LocatorSchema
172
+ }).describe("Condition to check"),
173
+ then: z.array(BaseActionSchema).describe("Steps to execute if condition is true"),
174
+ else: z.array(BaseActionSchema).optional().describe("Steps to execute if condition is false")
175
+ }).describe("Execute steps conditionally based on element state");
176
+ var ActionSchema = z.union([BaseActionSchema, conditionalActionSchema]);
155
177
  var defaultsSchema = z.object({
156
178
  timeout: z.number().int().positive().optional().describe("Default timeout in milliseconds for all actions"),
157
179
  screenshots: z.enum(["on-failure", "always", "never"]).optional().describe("When to capture screenshots during test execution")
@@ -989,6 +1011,30 @@ var APPWRITE_DELETE_PATTERNS = {
989
1011
  teamDelete: /\/v1\/teams\/([\w-]+)$/,
990
1012
  membershipDelete: /\/v1\/teams\/([\w-]+)\/memberships\/([\w-]+)$/
991
1013
  };
1014
+
1015
+ // src/executors/web/browserOptions.ts
1016
+ function getBrowserLaunchOptions(options) {
1017
+ return {
1018
+ headless: options.headless,
1019
+ args: [
1020
+ // Shared memory - critical for Docker/CI, harmless locally
1021
+ "--disable-dev-shm-usage",
1022
+ // GPU acceleration - not needed in headless mode
1023
+ "--disable-gpu",
1024
+ // Reduce overhead
1025
+ "--disable-extensions",
1026
+ // Prevent JavaScript throttling (helps with slow page loads)
1027
+ "--disable-background-timer-throttling",
1028
+ "--disable-backgrounding-occluded-windows",
1029
+ "--disable-renderer-backgrounding",
1030
+ // Process isolation - reduces overhead for testing
1031
+ "--disable-features=IsolateOrigins,site-per-process",
1032
+ // Networking tweaks
1033
+ "--disable-features=VizDisplayCompositor",
1034
+ "--disable-blink-features=AutomationControlled"
1035
+ ]
1036
+ };
1037
+ }
992
1038
  function resolveEnvVars(value) {
993
1039
  return value.replace(/\$\{(\w+)\}/g, (_, name) => process.env[name] || "");
994
1040
  }
@@ -1352,6 +1398,14 @@ var runWait = async (page, action) => {
1352
1398
  }
1353
1399
  await page.waitForTimeout(action.timeout ?? 1e3);
1354
1400
  };
1401
+ var waitForCondition = async (checkFn, timeout, errorMessage) => {
1402
+ const start = Date.now();
1403
+ while (Date.now() - start < timeout) {
1404
+ if (await checkFn()) return;
1405
+ await new Promise((r) => setTimeout(r, 100));
1406
+ }
1407
+ throw new Error(errorMessage);
1408
+ };
1355
1409
  var runScroll = async (page, action) => {
1356
1410
  if (action.target) {
1357
1411
  const handle = resolveLocator(page, action.target);
@@ -1787,6 +1841,91 @@ async function executeActionWithRetry(page, action, index, options) {
1787
1841
  await page.pause();
1788
1842
  break;
1789
1843
  }
1844
+ case "waitForSelector": {
1845
+ const wsAction = action;
1846
+ const handle = resolveLocator(page, wsAction.target);
1847
+ const timeout = wsAction.timeout ?? 3e4;
1848
+ if (debugMode) {
1849
+ console.log(`[DEBUG] Waiting for element to be ${wsAction.state}:`, wsAction.target);
1850
+ }
1851
+ switch (wsAction.state) {
1852
+ case "visible":
1853
+ case "hidden":
1854
+ case "attached":
1855
+ case "detached":
1856
+ await handle.waitFor({ state: wsAction.state, timeout });
1857
+ break;
1858
+ case "enabled":
1859
+ await waitForCondition(
1860
+ () => handle.isEnabled(),
1861
+ timeout,
1862
+ `Element did not become enabled within ${timeout}ms`
1863
+ );
1864
+ break;
1865
+ case "disabled":
1866
+ await waitForCondition(
1867
+ () => handle.isDisabled(),
1868
+ timeout,
1869
+ `Element did not become disabled within ${timeout}ms`
1870
+ );
1871
+ break;
1872
+ }
1873
+ break;
1874
+ }
1875
+ case "conditional": {
1876
+ const condAction = action;
1877
+ const handle = resolveLocator(page, condAction.condition.target);
1878
+ let conditionMet = false;
1879
+ if (debugMode) {
1880
+ console.log(`[DEBUG] Checking condition ${condAction.condition.type}:`, condAction.condition.target);
1881
+ }
1882
+ try {
1883
+ switch (condAction.condition.type) {
1884
+ case "exists":
1885
+ await handle.waitFor({ state: "attached", timeout: 500 });
1886
+ conditionMet = true;
1887
+ break;
1888
+ case "notExists":
1889
+ try {
1890
+ await handle.waitFor({ state: "detached", timeout: 500 });
1891
+ conditionMet = true;
1892
+ } catch {
1893
+ conditionMet = false;
1894
+ }
1895
+ break;
1896
+ case "visible":
1897
+ conditionMet = await handle.isVisible();
1898
+ break;
1899
+ case "hidden":
1900
+ conditionMet = !await handle.isVisible();
1901
+ break;
1902
+ }
1903
+ } catch {
1904
+ conditionMet = condAction.condition.type === "notExists";
1905
+ }
1906
+ if (debugMode) {
1907
+ console.log(`[DEBUG] Condition result: ${conditionMet}`);
1908
+ }
1909
+ const stepsToRun = conditionMet ? condAction.then : condAction.else ?? [];
1910
+ for (const [nestedIdx, nestedAction] of stepsToRun.entries()) {
1911
+ if (debugMode) {
1912
+ console.log(`[DEBUG] Executing nested step ${nestedIdx + 1}: ${nestedAction.type}`);
1913
+ }
1914
+ await executeActionWithRetry(page, nestedAction, index, {
1915
+ baseUrl,
1916
+ context,
1917
+ screenshotDir,
1918
+ debugMode,
1919
+ interactive,
1920
+ aiConfig
1921
+ });
1922
+ }
1923
+ break;
1924
+ }
1925
+ case "fail": {
1926
+ const failAction = action;
1927
+ throw new Error(failAction.message);
1928
+ }
1790
1929
  default:
1791
1930
  throw new Error(`Unsupported action type: ${action.type}`);
1792
1931
  }
@@ -1848,7 +1987,7 @@ var runWebTest = async (test, options = {}) => {
1848
1987
  process.on("SIGINT", cleanup);
1849
1988
  process.on("SIGTERM", cleanup);
1850
1989
  console.log(`Launching ${browserName}${headless ? " (headless)" : " (visible)"}...`);
1851
- const browser = await getBrowser(browserName).launch({ headless });
1990
+ const browser = await getBrowser(browserName).launch(getBrowserLaunchOptions({ headless }));
1852
1991
  console.log(`Browser launched successfully`);
1853
1992
  const browserContext = await browser.newContext();
1854
1993
  const page = await browserContext.newPage();
@@ -2383,6 +2522,99 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
2383
2522
  await page.pause();
2384
2523
  break;
2385
2524
  }
2525
+ case "waitForSelector": {
2526
+ const handle = resolveLocator2(action.target);
2527
+ const timeout = action.timeout ?? 3e4;
2528
+ if (debugMode) {
2529
+ console.log(` [DEBUG] Waiting for element to be ${action.state}:`, action.target);
2530
+ }
2531
+ const waitForCondition2 = async (checkFn, timeoutMs, errorMessage) => {
2532
+ const start = Date.now();
2533
+ while (Date.now() - start < timeoutMs) {
2534
+ if (await checkFn()) return;
2535
+ await new Promise((r) => setTimeout(r, 100));
2536
+ }
2537
+ throw new Error(errorMessage);
2538
+ };
2539
+ switch (action.state) {
2540
+ case "visible":
2541
+ case "hidden":
2542
+ case "attached":
2543
+ case "detached":
2544
+ await handle.waitFor({ state: action.state, timeout });
2545
+ break;
2546
+ case "enabled":
2547
+ await waitForCondition2(
2548
+ () => handle.isEnabled(),
2549
+ timeout,
2550
+ `Element did not become enabled within ${timeout}ms`
2551
+ );
2552
+ break;
2553
+ case "disabled":
2554
+ await waitForCondition2(
2555
+ () => handle.isDisabled(),
2556
+ timeout,
2557
+ `Element did not become disabled within ${timeout}ms`
2558
+ );
2559
+ break;
2560
+ }
2561
+ break;
2562
+ }
2563
+ case "conditional": {
2564
+ const handle = resolveLocator2(action.condition.target);
2565
+ let conditionMet = false;
2566
+ if (debugMode) {
2567
+ console.log(` [DEBUG] Checking condition ${action.condition.type}:`, action.condition.target);
2568
+ }
2569
+ try {
2570
+ switch (action.condition.type) {
2571
+ case "exists":
2572
+ await handle.waitFor({ state: "attached", timeout: 500 });
2573
+ conditionMet = true;
2574
+ break;
2575
+ case "notExists":
2576
+ try {
2577
+ await handle.waitFor({ state: "detached", timeout: 500 });
2578
+ conditionMet = true;
2579
+ } catch {
2580
+ conditionMet = false;
2581
+ }
2582
+ break;
2583
+ case "visible":
2584
+ conditionMet = await handle.isVisible();
2585
+ break;
2586
+ case "hidden":
2587
+ conditionMet = !await handle.isVisible();
2588
+ break;
2589
+ }
2590
+ } catch {
2591
+ conditionMet = action.condition.type === "notExists";
2592
+ }
2593
+ if (debugMode) {
2594
+ console.log(` [DEBUG] Condition result: ${conditionMet}`);
2595
+ }
2596
+ const stepsToRun = conditionMet ? action.then : action.else ?? [];
2597
+ for (const nestedAction of stepsToRun) {
2598
+ switch (nestedAction.type) {
2599
+ case "screenshot": {
2600
+ const filename = nestedAction.name ?? `conditional-step.png`;
2601
+ const filePath = path.join(screenshotDir, filename);
2602
+ await page.screenshot({ path: filePath, fullPage: true });
2603
+ results.push({ action: nestedAction, status: "passed", screenshotPath: filePath });
2604
+ break;
2605
+ }
2606
+ case "fail": {
2607
+ throw new Error(nestedAction.message);
2608
+ }
2609
+ default:
2610
+ throw new Error(`Nested action type ${nestedAction.type} in conditional not yet supported`);
2611
+ }
2612
+ }
2613
+ break;
2614
+ }
2615
+ case "fail": {
2616
+ throw new Error(action.message);
2617
+ }
2386
2618
  default:
2387
2619
  throw new Error(`Unsupported action type: ${action.type}`);
2388
2620
  }
@@ -2807,7 +3039,7 @@ async function runWorkflow(workflow, workflowFilePath, options = {}) {
2807
3039
  const browserName = options.browser ?? workflow.config?.web?.browser ?? "chromium";
2808
3040
  const headless = options.headed === true ? false : workflow.config?.web?.headless ?? true;
2809
3041
  console.log(`Launching ${browserName}${headless ? " (headless)" : " (visible)"}...`);
2810
- const browser = await getBrowser2(browserName).launch({ headless });
3042
+ const browser = await getBrowser2(browserName).launch(getBrowserLaunchOptions({ headless }));
2811
3043
  console.log(`Browser launched successfully`);
2812
3044
  const browserContext = await browser.newContext();
2813
3045
  const page = await browserContext.newPage();
@@ -2944,6 +3176,6 @@ Collected ${serverResources.length} server-tracked resources`);
2944
3176
  }
2945
3177
  }
2946
3178
 
2947
- export { ActionSchema, IntellitesterConfigSchema, LocatorSchema, TestConfigSchema, TestDefinitionSchema, cleanupConfigSchema, cleanupDiscoverSchema, collectMissingEnvVars, createAIProvider, createTestContext, generateFillerText, generateRandomEmail, generateRandomPhone, generateRandomPhoto, generateRandomUsername, interpolateVariables, isPipelineContent, isPipelineFile, isWorkflowContent, isWorkflowFile, killServer, loadIntellitesterConfig, loadPipelineDefinition, loadTestDefinition, loadWorkflowDefinition, parseIntellitesterConfig, parsePipelineDefinition, parseTestDefinition, parseWorkflowDefinition, previewConfigSchema, runWebTest, runWorkflow, runWorkflowWithContext, setupAppwriteTracking, startTrackingServer, startWebServer };
2948
- //# sourceMappingURL=chunk-ICJK4WBA.js.map
2949
- //# sourceMappingURL=chunk-ICJK4WBA.js.map
3179
+ export { ActionSchema, IntellitesterConfigSchema, LocatorSchema, TestConfigSchema, TestDefinitionSchema, cleanupConfigSchema, cleanupDiscoverSchema, collectMissingEnvVars, createAIProvider, createTestContext, generateFillerText, generateRandomEmail, generateRandomPhone, generateRandomPhoto, generateRandomUsername, getBrowserLaunchOptions, interpolateVariables, isPipelineContent, isPipelineFile, isWorkflowContent, isWorkflowFile, killServer, loadIntellitesterConfig, loadPipelineDefinition, loadTestDefinition, loadWorkflowDefinition, parseIntellitesterConfig, parsePipelineDefinition, parseTestDefinition, parseWorkflowDefinition, previewConfigSchema, runWebTest, runWorkflow, runWorkflowWithContext, setupAppwriteTracking, startTrackingServer, startWebServer };
3180
+ //# sourceMappingURL=chunk-EQJZ2E5H.js.map
3181
+ //# sourceMappingURL=chunk-EQJZ2E5H.js.map