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.
- package/dist/{chunk-ICJK4WBA.js → chunk-EQJZ2E5H.js} +239 -7
- package/dist/chunk-EQJZ2E5H.js.map +1 -0
- package/dist/{chunk-JIVORCLQ.cjs → chunk-GCF2Q77Q.cjs} +239 -6
- package/dist/chunk-GCF2Q77Q.cjs.map +1 -0
- package/dist/cli/index.cjs +36 -36
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +34 -34
- package/dist/index.d.cts +903 -7
- package/dist/index.d.ts +903 -7
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-ICJK4WBA.js.map +0 -1
- package/dist/chunk-JIVORCLQ.cjs.map +0 -1
|
@@ -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
|
|
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-
|
|
2949
|
-
//# sourceMappingURL=chunk-
|
|
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
|