intellitester 0.2.19 → 0.2.21

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.
@@ -2,12 +2,13 @@ import { loadCleanupHandlers, executeCleanup, saveFailedCleanup } from './chunk-
2
2
  import { z } from 'zod';
3
3
  import fs2 from 'fs/promises';
4
4
  import { parse } from 'yaml';
5
- import crypto2 from 'crypto';
5
+ import { NumberDictionary, uniqueNamesGenerator, adjectives, animals } from 'unique-names-generator';
6
+ import crypto4 from 'crypto';
7
+ import { parsePhoneNumber, isValidPhoneNumber } from 'libphonenumber-js';
6
8
  import path from 'path';
7
9
  import { spawn } from 'child_process';
8
10
  import { chromium, webkit, firefox } from 'playwright';
9
11
  import prompts from 'prompts';
10
- import { NumberDictionary, uniqueNamesGenerator, adjectives, animals } from 'unique-names-generator';
11
12
  import { Client, Users, TablesDB, Storage, Teams } from 'node-appwrite';
12
13
  import { Anthropic } from '@llamaindex/anthropic';
13
14
  import { OpenAI } from '@llamaindex/openai';
@@ -128,7 +129,17 @@ var appwriteVerifyEmailActionSchema = z.object({
128
129
  var debugActionSchema = z.object({
129
130
  type: z.literal("debug")
130
131
  }).describe("Pause execution and open Playwright Inspector for debugging");
131
- 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", [
132
143
  navigateActionSchema,
133
144
  tapActionSchema,
134
145
  inputActionSchema,
@@ -149,8 +160,20 @@ var ActionSchema = z.discriminatedUnion("type", [
149
160
  emailExtractLinkActionSchema,
150
161
  emailClearActionSchema,
151
162
  appwriteVerifyEmailActionSchema,
152
- debugActionSchema
163
+ debugActionSchema,
164
+ waitForSelectorActionSchema,
165
+ failActionSchema
153
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]);
154
177
  var defaultsSchema = z.object({
155
178
  timeout: z.number().int().positive().optional().describe("Default timeout in milliseconds for all actions"),
156
179
  screenshots: z.enum(["on-failure", "always", "never"]).optional().describe("When to capture screenshots during test execution")
@@ -491,6 +514,272 @@ function generateRandomUsername() {
491
514
  return username;
492
515
  }
493
516
 
517
+ // src/core/randomPhoto.ts
518
+ function generateRandomPhoto(dimensions) {
519
+ let width = 500;
520
+ let height = 500;
521
+ if (dimensions) {
522
+ if (dimensions.includes("x")) {
523
+ const [w, h] = dimensions.split("x").map((d) => parseInt(d.trim(), 10));
524
+ if (!isNaN(w) && w > 0) width = w;
525
+ if (!isNaN(h) && h > 0) height = h;
526
+ } else {
527
+ const size = parseInt(dimensions.trim(), 10);
528
+ if (!isNaN(size) && size > 0) {
529
+ width = size;
530
+ height = size;
531
+ }
532
+ }
533
+ }
534
+ return `https://picsum.photos/${width}/${height}`;
535
+ }
536
+
537
+ // src/core/fillerText.ts
538
+ var LOREM_WORDS = [
539
+ "lorem",
540
+ "ipsum",
541
+ "dolor",
542
+ "sit",
543
+ "amet",
544
+ "consectetur",
545
+ "adipiscing",
546
+ "elit",
547
+ "sed",
548
+ "do",
549
+ "eiusmod",
550
+ "tempor",
551
+ "incididunt",
552
+ "ut",
553
+ "labore",
554
+ "et",
555
+ "dolore",
556
+ "magna",
557
+ "aliqua",
558
+ "enim",
559
+ "ad",
560
+ "minim",
561
+ "veniam",
562
+ "quis",
563
+ "nostrud",
564
+ "exercitation",
565
+ "ullamco",
566
+ "laboris",
567
+ "nisi",
568
+ "aliquip",
569
+ "ex",
570
+ "ea",
571
+ "commodo",
572
+ "consequat",
573
+ "duis",
574
+ "aute",
575
+ "irure",
576
+ "in",
577
+ "reprehenderit",
578
+ "voluptate",
579
+ "velit",
580
+ "esse",
581
+ "cillum",
582
+ "fugiat",
583
+ "nulla",
584
+ "pariatur",
585
+ "excepteur",
586
+ "sint",
587
+ "occaecat",
588
+ "cupidatat",
589
+ "non",
590
+ "proident",
591
+ "sunt",
592
+ "culpa",
593
+ "qui",
594
+ "officia",
595
+ "deserunt",
596
+ "mollit",
597
+ "anim",
598
+ "id",
599
+ "est",
600
+ "laborum",
601
+ "perspiciatis",
602
+ "unde",
603
+ "omnis",
604
+ "iste",
605
+ "natus",
606
+ "error",
607
+ "voluptatem",
608
+ "accusantium",
609
+ "doloremque",
610
+ "laudantium",
611
+ "totam",
612
+ "rem",
613
+ "aperiam",
614
+ "eaque",
615
+ "ipsa",
616
+ "quae",
617
+ "ab",
618
+ "illo",
619
+ "inventore",
620
+ "veritatis",
621
+ "quasi",
622
+ "architecto",
623
+ "beatae",
624
+ "vitae",
625
+ "dicta",
626
+ "explicabo",
627
+ "nemo",
628
+ "ipsam",
629
+ "quia",
630
+ "voluptas",
631
+ "aspernatur",
632
+ "aut",
633
+ "odit",
634
+ "fugit",
635
+ "consequuntur",
636
+ "magni",
637
+ "dolores",
638
+ "eos",
639
+ "ratione",
640
+ "sequi",
641
+ "nesciunt",
642
+ "neque",
643
+ "porro",
644
+ "quisquam",
645
+ "nihil",
646
+ "impedit",
647
+ "quo",
648
+ "minus"
649
+ ];
650
+ function generateFillerText(wordCount) {
651
+ let count = 50;
652
+ if (wordCount !== void 0) {
653
+ const parsed = typeof wordCount === "string" ? parseInt(wordCount.trim(), 10) : wordCount;
654
+ if (!isNaN(parsed) && parsed > 0) {
655
+ count = parsed;
656
+ }
657
+ }
658
+ const words = [];
659
+ if (count >= 2) {
660
+ words.push("Lorem", "ipsum");
661
+ count -= 2;
662
+ }
663
+ for (let i = 0; i < count; i++) {
664
+ const randomIndex = Math.floor(Math.random() * LOREM_WORDS.length);
665
+ words.push(LOREM_WORDS[randomIndex]);
666
+ }
667
+ let result = words.join(" ");
668
+ const resultWords = result.split(" ");
669
+ const sentenceWords = [];
670
+ let sentenceLength = 0;
671
+ const nextSentenceLength = () => 8 + Math.floor(Math.random() * 5);
672
+ let targetLength = nextSentenceLength();
673
+ for (let i = 0; i < resultWords.length; i++) {
674
+ let word = resultWords[i];
675
+ if (sentenceLength === 0) {
676
+ word = word.charAt(0).toUpperCase() + word.slice(1);
677
+ }
678
+ sentenceWords.push(word);
679
+ sentenceLength++;
680
+ if (sentenceLength >= targetLength && i < resultWords.length - 1) {
681
+ sentenceWords[sentenceWords.length - 1] += ".";
682
+ sentenceLength = 0;
683
+ targetLength = nextSentenceLength();
684
+ }
685
+ }
686
+ result = sentenceWords.join(" ");
687
+ if (!result.endsWith(".")) {
688
+ result += ".";
689
+ }
690
+ return result;
691
+ }
692
+ function generateRandomEmail(domain) {
693
+ const randomPart = crypto4.randomBytes(3).toString("hex");
694
+ const emailDomain = domain?.trim() || "test.local";
695
+ return `test-${randomPart}@${emailDomain}`;
696
+ }
697
+ var COUNTRY_FORMATS = {
698
+ US: {
699
+ areaCode: () => {
700
+ const areaCodes = ["201", "212", "213", "310", "312", "404", "415", "512", "617", "702", "713", "718", "805", "818", "917"];
701
+ return areaCodes[Math.floor(Math.random() * areaCodes.length)];
702
+ },
703
+ subscriber: () => String(Math.floor(Math.random() * 9e6) + 1e6).slice(0, 7)
704
+ },
705
+ GB: {
706
+ areaCode: () => {
707
+ const areaCodes = ["20", "121", "131", "141", "151", "161", "171", "181"];
708
+ return areaCodes[Math.floor(Math.random() * areaCodes.length)];
709
+ },
710
+ subscriber: () => String(Math.floor(Math.random() * 9e7) + 1e7).slice(0, 8)
711
+ },
712
+ DE: {
713
+ areaCode: () => {
714
+ const areaCodes = ["30", "40", "69", "89", "211", "221", "341", "351"];
715
+ return areaCodes[Math.floor(Math.random() * areaCodes.length)];
716
+ },
717
+ subscriber: () => String(Math.floor(Math.random() * 9e6) + 1e6).slice(0, 7)
718
+ },
719
+ FR: {
720
+ areaCode: () => {
721
+ const areaCodes = ["1", "2", "3", "4", "5"];
722
+ return areaCodes[Math.floor(Math.random() * areaCodes.length)];
723
+ },
724
+ subscriber: () => String(Math.floor(Math.random() * 9e7) + 1e7).slice(0, 8)
725
+ },
726
+ AU: {
727
+ areaCode: () => {
728
+ const areaCodes = ["2", "3", "7", "8"];
729
+ return areaCodes[Math.floor(Math.random() * areaCodes.length)];
730
+ },
731
+ subscriber: () => String(Math.floor(Math.random() * 9e7) + 1e7).slice(0, 8)
732
+ }
733
+ };
734
+ function generateRandomPhone(country = "US") {
735
+ const countryCode = country.toUpperCase();
736
+ const format = COUNTRY_FORMATS[countryCode] || COUNTRY_FORMATS["US"];
737
+ for (let i = 0; i < 10; i++) {
738
+ const areaCode2 = format.areaCode();
739
+ const subscriber2 = format.subscriber();
740
+ const nationalNumber = areaCode2 + subscriber2;
741
+ try {
742
+ const phoneNumber = parsePhoneNumber(nationalNumber, countryCode);
743
+ if (phoneNumber && isValidPhoneNumber(phoneNumber.number)) {
744
+ return phoneNumber.format("E.164");
745
+ }
746
+ } catch {
747
+ }
748
+ }
749
+ const fallbackFormat = COUNTRY_FORMATS[countryCode] || COUNTRY_FORMATS["US"];
750
+ const areaCode = fallbackFormat.areaCode();
751
+ const subscriber = fallbackFormat.subscriber();
752
+ const callingCodes = {
753
+ US: "1",
754
+ GB: "44",
755
+ DE: "49",
756
+ FR: "33",
757
+ AU: "61"
758
+ };
759
+ const callingCode = callingCodes[countryCode] || "1";
760
+ return `+${callingCode}${areaCode}${subscriber}`;
761
+ }
762
+ function interpolateVariables(value, variables) {
763
+ return value.replace(/\{\{(\w+)(?::([^}]+))?\}\}/g, (match, name, param) => {
764
+ switch (name) {
765
+ case "uuid":
766
+ return crypto4.randomUUID().split("-")[0];
767
+ case "randomUsername":
768
+ return generateRandomUsername();
769
+ case "randomPhoto":
770
+ return generateRandomPhoto(param);
771
+ case "fillerText":
772
+ return generateFillerText(param);
773
+ case "randomEmail":
774
+ return generateRandomEmail(param);
775
+ case "randomPhone":
776
+ return generateRandomPhone(param);
777
+ default:
778
+ return variables.get(name) ?? match;
779
+ }
780
+ });
781
+ }
782
+
494
783
  // src/integrations/email/inbucketClient.ts
495
784
  var InbucketClient = class {
496
785
  constructor(config) {
@@ -1025,17 +1314,6 @@ async function startTrackingServer(options) {
1025
1314
 
1026
1315
  // src/executors/web/playwrightExecutor.ts
1027
1316
  var defaultScreenshotDir = path.join(process.cwd(), "artifacts", "screenshots");
1028
- function interpolateVariables(value, variables) {
1029
- return value.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
1030
- if (varName === "uuid") {
1031
- return crypto2.randomUUID().split("-")[0];
1032
- }
1033
- if (varName === "randomUsername") {
1034
- return generateRandomUsername();
1035
- }
1036
- return variables.get(varName) ?? match;
1037
- });
1038
- }
1039
1317
  var resolveUrl = (value, baseUrl) => {
1040
1318
  if (!baseUrl) return value;
1041
1319
  try {
@@ -1096,6 +1374,14 @@ var runWait = async (page, action) => {
1096
1374
  }
1097
1375
  await page.waitForTimeout(action.timeout ?? 1e3);
1098
1376
  };
1377
+ var waitForCondition = async (checkFn, timeout, errorMessage) => {
1378
+ const start = Date.now();
1379
+ while (Date.now() - start < timeout) {
1380
+ if (await checkFn()) return;
1381
+ await new Promise((r) => setTimeout(r, 100));
1382
+ }
1383
+ throw new Error(errorMessage);
1384
+ };
1099
1385
  var runScroll = async (page, action) => {
1100
1386
  if (action.target) {
1101
1387
  const handle = resolveLocator(page, action.target);
@@ -1531,6 +1817,91 @@ async function executeActionWithRetry(page, action, index, options) {
1531
1817
  await page.pause();
1532
1818
  break;
1533
1819
  }
1820
+ case "waitForSelector": {
1821
+ const wsAction = action;
1822
+ const handle = resolveLocator(page, wsAction.target);
1823
+ const timeout = wsAction.timeout ?? 3e4;
1824
+ if (debugMode) {
1825
+ console.log(`[DEBUG] Waiting for element to be ${wsAction.state}:`, wsAction.target);
1826
+ }
1827
+ switch (wsAction.state) {
1828
+ case "visible":
1829
+ case "hidden":
1830
+ case "attached":
1831
+ case "detached":
1832
+ await handle.waitFor({ state: wsAction.state, timeout });
1833
+ break;
1834
+ case "enabled":
1835
+ await waitForCondition(
1836
+ () => handle.isEnabled(),
1837
+ timeout,
1838
+ `Element did not become enabled within ${timeout}ms`
1839
+ );
1840
+ break;
1841
+ case "disabled":
1842
+ await waitForCondition(
1843
+ () => handle.isDisabled(),
1844
+ timeout,
1845
+ `Element did not become disabled within ${timeout}ms`
1846
+ );
1847
+ break;
1848
+ }
1849
+ break;
1850
+ }
1851
+ case "conditional": {
1852
+ const condAction = action;
1853
+ const handle = resolveLocator(page, condAction.condition.target);
1854
+ let conditionMet = false;
1855
+ if (debugMode) {
1856
+ console.log(`[DEBUG] Checking condition ${condAction.condition.type}:`, condAction.condition.target);
1857
+ }
1858
+ try {
1859
+ switch (condAction.condition.type) {
1860
+ case "exists":
1861
+ await handle.waitFor({ state: "attached", timeout: 500 });
1862
+ conditionMet = true;
1863
+ break;
1864
+ case "notExists":
1865
+ try {
1866
+ await handle.waitFor({ state: "detached", timeout: 500 });
1867
+ conditionMet = true;
1868
+ } catch {
1869
+ conditionMet = false;
1870
+ }
1871
+ break;
1872
+ case "visible":
1873
+ conditionMet = await handle.isVisible();
1874
+ break;
1875
+ case "hidden":
1876
+ conditionMet = !await handle.isVisible();
1877
+ break;
1878
+ }
1879
+ } catch {
1880
+ conditionMet = condAction.condition.type === "notExists";
1881
+ }
1882
+ if (debugMode) {
1883
+ console.log(`[DEBUG] Condition result: ${conditionMet}`);
1884
+ }
1885
+ const stepsToRun = conditionMet ? condAction.then : condAction.else ?? [];
1886
+ for (const [nestedIdx, nestedAction] of stepsToRun.entries()) {
1887
+ if (debugMode) {
1888
+ console.log(`[DEBUG] Executing nested step ${nestedIdx + 1}: ${nestedAction.type}`);
1889
+ }
1890
+ await executeActionWithRetry(page, nestedAction, index, {
1891
+ baseUrl,
1892
+ context,
1893
+ screenshotDir,
1894
+ debugMode,
1895
+ interactive,
1896
+ aiConfig
1897
+ });
1898
+ }
1899
+ break;
1900
+ }
1901
+ case "fail": {
1902
+ const failAction = action;
1903
+ throw new Error(failAction.message);
1904
+ }
1534
1905
  default:
1535
1906
  throw new Error(`Unsupported action type: ${action.type}`);
1536
1907
  }
@@ -1575,7 +1946,7 @@ var runWebTest = async (test, options = {}) => {
1575
1946
  const headless = !(options.headed ?? false);
1576
1947
  const screenshotDir = options.screenshotDir ?? defaultScreenshotDir;
1577
1948
  const defaultTimeout = options.defaultTimeoutMs ?? 3e4;
1578
- const sessionId = crypto2.randomUUID();
1949
+ const sessionId = crypto4.randomUUID();
1579
1950
  const trackingServer = new TrackingServer();
1580
1951
  await trackingServer.start();
1581
1952
  process.env.INTELLITESTER_SESSION_ID = sessionId;
@@ -1881,19 +2252,14 @@ var getBrowser2 = (browser) => {
1881
2252
  };
1882
2253
  function interpolateWorkflowVariables(value, currentVariables, testResults) {
1883
2254
  return value.replace(/\{\{([^}]+)\}\}/g, (match, path3) => {
1884
- if (path3.includes(".")) {
2255
+ if (path3.includes(".") && !path3.includes(":")) {
1885
2256
  const [testId, _varName] = path3.split(".", 2);
1886
2257
  testResults.find((t) => t.id === testId);
1887
2258
  console.warn(`Cross-test variable interpolation {{${path3}}} not yet fully implemented`);
1888
2259
  return match;
1889
2260
  }
1890
- if (path3 === "uuid") {
1891
- return crypto2.randomUUID().split("-")[0];
1892
- }
1893
- if (path3 === "randomUsername") {
1894
- return generateRandomUsername();
1895
- }
1896
- return currentVariables.get(path3) ?? match;
2261
+ const result = interpolateVariables(`{{${path3}}}`, currentVariables);
2262
+ return result;
1897
2263
  });
1898
2264
  }
1899
2265
  async function runTestInWorkflow(test, page, context, options, _workflowDir, workflowBaseUrl) {
@@ -1909,16 +2275,8 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
1909
2275
  return value;
1910
2276
  }
1911
2277
  };
1912
- const interpolateVariables2 = (value) => {
1913
- return value.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
1914
- if (varName === "uuid") {
1915
- return crypto2.randomUUID().split("-")[0];
1916
- }
1917
- if (varName === "randomUsername") {
1918
- return generateRandomUsername();
1919
- }
1920
- return context.variables.get(varName) ?? match;
1921
- });
2278
+ const interpolate = (value) => {
2279
+ return interpolateVariables(value, context.variables);
1922
2280
  };
1923
2281
  const resolveLocator2 = (locator) => {
1924
2282
  if (locator.testId) return page.getByTestId(locator.testId);
@@ -1941,7 +2299,7 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
1941
2299
  try {
1942
2300
  switch (action.type) {
1943
2301
  case "navigate": {
1944
- const interpolated = interpolateVariables2(action.value);
2302
+ const interpolated = interpolate(action.value);
1945
2303
  const baseUrl = test.config?.web?.baseUrl ?? workflowBaseUrl;
1946
2304
  const target = resolveUrl2(interpolated, baseUrl);
1947
2305
  if (debugMode) console.log(` [DEBUG] Navigating to: ${target}`);
@@ -1955,7 +2313,7 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
1955
2313
  break;
1956
2314
  }
1957
2315
  case "input": {
1958
- const interpolated = interpolateVariables2(action.value);
2316
+ const interpolated = interpolate(action.value);
1959
2317
  if (debugMode) console.log(` [DEBUG] Input: ${interpolated}`);
1960
2318
  const handle = resolveLocator2(action.target);
1961
2319
  await handle.fill(interpolated);
@@ -1974,7 +2332,7 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
1974
2332
  break;
1975
2333
  }
1976
2334
  case "select": {
1977
- const interpolated = interpolateVariables2(action.value);
2335
+ const interpolated = interpolate(action.value);
1978
2336
  if (debugMode) console.log(` [DEBUG] Selecting: ${interpolated}`);
1979
2337
  const handle = resolveLocator2(action.target);
1980
2338
  await handle.selectOption(interpolated);
@@ -2013,7 +2371,7 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
2013
2371
  const handle = resolveLocator2(action.target);
2014
2372
  await handle.waitFor({ state: "visible" });
2015
2373
  if (action.value) {
2016
- const interpolated = interpolateVariables2(action.value);
2374
+ const interpolated = interpolate(action.value);
2017
2375
  const text = (await handle.textContent())?.trim() ?? "";
2018
2376
  if (!text.includes(interpolated)) {
2019
2377
  throw new Error(
@@ -2054,7 +2412,7 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
2054
2412
  case "setVar": {
2055
2413
  let value;
2056
2414
  if (action.value) {
2057
- value = interpolateVariables2(action.value);
2415
+ value = interpolate(action.value);
2058
2416
  } else if (action.from === "response") {
2059
2417
  throw new Error("setVar from response not yet implemented");
2060
2418
  } else if (action.from === "element") {
@@ -2072,7 +2430,7 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
2072
2430
  if (!context.emailClient) {
2073
2431
  throw new Error("Email client not configured");
2074
2432
  }
2075
- const mailbox = interpolateVariables2(action.mailbox);
2433
+ const mailbox = interpolate(action.mailbox);
2076
2434
  context.lastEmail = await context.emailClient.waitForEmail(mailbox, {
2077
2435
  timeout: action.timeout,
2078
2436
  subjectContains: action.subjectContains
@@ -2117,7 +2475,7 @@ async function runTestInWorkflow(test, page, context, options, _workflowDir, wor
2117
2475
  if (!context.emailClient) {
2118
2476
  throw new Error("Email client not configured");
2119
2477
  }
2120
- const mailbox = interpolateVariables2(action.mailbox);
2478
+ const mailbox = interpolate(action.mailbox);
2121
2479
  await context.emailClient.clearMailbox(mailbox);
2122
2480
  break;
2123
2481
  }
@@ -2337,7 +2695,7 @@ function inferCleanupConfig(config) {
2337
2695
  async function runWorkflowWithContext(workflow, workflowFilePath, options) {
2338
2696
  const { page, executionContext, skipCleanup = false, sessionId: providedSessionId, testStartTime: providedTestStartTime } = options;
2339
2697
  const workflowDir = path.dirname(workflowFilePath);
2340
- const sessionId = providedSessionId ?? crypto2.randomUUID();
2698
+ const sessionId = providedSessionId ?? crypto4.randomUUID();
2341
2699
  const testStartTime = providedTestStartTime ?? (/* @__PURE__ */ new Date()).toISOString();
2342
2700
  console.log(`
2343
2701
  Starting workflow: ${workflow.name}`);
@@ -2356,11 +2714,7 @@ Starting workflow: ${workflow.name}`);
2356
2714
  if (workflow.variables) {
2357
2715
  for (const [key, value] of Object.entries(workflow.variables)) {
2358
2716
  if (!executionContext.variables.has(key)) {
2359
- const interpolated = value.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
2360
- if (varName === "uuid") return crypto2.randomUUID().split("-")[0];
2361
- if (varName === "randomUsername") return generateRandomUsername();
2362
- return executionContext.variables.get(varName) ?? match;
2363
- });
2717
+ const interpolated = interpolateVariables(value, executionContext.variables);
2364
2718
  executionContext.variables.set(key, interpolated);
2365
2719
  }
2366
2720
  }
@@ -2390,15 +2744,7 @@ Starting workflow: ${workflow.name}`);
2390
2744
  }
2391
2745
  if (test.variables) {
2392
2746
  for (const [key, value] of Object.entries(test.variables)) {
2393
- const interpolated = value.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
2394
- if (varName === "uuid") {
2395
- return crypto2.randomUUID().split("-")[0];
2396
- }
2397
- if (varName === "randomUsername") {
2398
- return generateRandomUsername();
2399
- }
2400
- return executionContext.variables.get(varName) ?? match;
2401
- });
2747
+ const interpolated = interpolateVariables(value, executionContext.variables);
2402
2748
  executionContext.variables.set(key, interpolated);
2403
2749
  }
2404
2750
  }
@@ -2537,7 +2883,7 @@ ${"=".repeat(60)}`);
2537
2883
  }
2538
2884
  async function runWorkflow(workflow, workflowFilePath, options = {}) {
2539
2885
  const workflowDir = path.dirname(workflowFilePath);
2540
- const sessionId = crypto2.randomUUID();
2886
+ const sessionId = crypto4.randomUUID();
2541
2887
  const testStartTime = (/* @__PURE__ */ new Date()).toISOString();
2542
2888
  let trackingServer = null;
2543
2889
  try {
@@ -2594,11 +2940,7 @@ async function runWorkflow(workflow, workflowFilePath, options = {}) {
2594
2940
  };
2595
2941
  if (workflow.variables) {
2596
2942
  for (const [key, value] of Object.entries(workflow.variables)) {
2597
- const interpolated = value.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
2598
- if (varName === "uuid") return crypto2.randomUUID().split("-")[0];
2599
- if (varName === "randomUsername") return generateRandomUsername();
2600
- return executionContext.variables.get(varName) ?? match;
2601
- });
2943
+ const interpolated = interpolateVariables(value, executionContext.variables);
2602
2944
  executionContext.variables.set(key, interpolated);
2603
2945
  }
2604
2946
  }
@@ -2717,6 +3059,6 @@ Collected ${serverResources.length} server-tracked resources`);
2717
3059
  }
2718
3060
  }
2719
3061
 
2720
- export { ActionSchema, IntellitesterConfigSchema, LocatorSchema, TestConfigSchema, TestDefinitionSchema, cleanupConfigSchema, cleanupDiscoverSchema, collectMissingEnvVars, createAIProvider, createTestContext, generateRandomUsername, isPipelineContent, isPipelineFile, isWorkflowContent, isWorkflowFile, killServer, loadIntellitesterConfig, loadPipelineDefinition, loadTestDefinition, loadWorkflowDefinition, parseIntellitesterConfig, parsePipelineDefinition, parseTestDefinition, parseWorkflowDefinition, previewConfigSchema, runWebTest, runWorkflow, runWorkflowWithContext, setupAppwriteTracking, startTrackingServer, startWebServer };
2721
- //# sourceMappingURL=chunk-LKSREGQS.js.map
2722
- //# sourceMappingURL=chunk-LKSREGQS.js.map
3062
+ 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 };
3063
+ //# sourceMappingURL=chunk-CKUSY4ZM.js.map
3064
+ //# sourceMappingURL=chunk-CKUSY4ZM.js.map