tamash-playwright 0.5.0 → 0.6.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.
- package/README.md +22 -4
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +28 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/scanActionTimeout.d.ts +17 -0
- package/dist/cli/scanActionTimeout.d.ts.map +1 -0
- package/dist/cli/scanActionTimeout.js +47 -0
- package/dist/cli/scanActionTimeout.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ Websites change often. A button gets renamed or moved, and your test can't find
|
|
|
10
10
|
|
|
11
11
|
`tamash-playwright` fixes this automatically. When a test can't find an element, it asks an AI model to find it on the current page and tries again. If it succeeds, your test keeps going. If not, it fails normally, just like before.
|
|
12
12
|
|
|
13
|
+
**Want to see it working before you set it up yourself?** Clone the sample repo — [github.com/qtpsudhakarproducts/tamash-playwright-typescript-playwright](https://github.com/qtpsudhakarproducts/tamash-playwright-typescript-playwright) — a full worked example with both a plain-locator test and a Page Object Model test, an intentionally broken selector, and step-by-step setup instructions.
|
|
14
|
+
|
|
13
15
|
Here are the detailed steps to use this package.
|
|
14
16
|
|
|
15
17
|
## Step 1: Install it
|
|
@@ -77,6 +79,21 @@ OLLAMA_API_KEY=paste_your_key_here
|
|
|
77
79
|
|
|
78
80
|
That's all you need — no other variables required.
|
|
79
81
|
|
|
82
|
+
### Important: set `actionTimeout` in your `playwright.config.ts`
|
|
83
|
+
|
|
84
|
+
By default, Playwright lets a broken locator retry silently for your *entire* test timeout before it ever throws an error — which means self-healing never gets a turn at all, since it only kicks in once an action actually fails. Set `actionTimeout` to something well below your test timeout so a broken locator fails fast, leaving real time for healing to run:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
export default defineConfig({
|
|
88
|
+
timeout: 60000, // your overall test timeout
|
|
89
|
+
use: {
|
|
90
|
+
actionTimeout: 8000, // must be comfortably less than the test timeout above
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Without this, healing attempts will show `stage=no_snapshot` in the console and never recover anything — not because healing failed, but because it never had time to run before the whole test was torn down.
|
|
96
|
+
|
|
80
97
|
## Step 3: Check your setup
|
|
81
98
|
|
|
82
99
|
Run the built-in doctor command to confirm everything's wired up correctly before you rely on it:
|
|
@@ -88,10 +105,11 @@ npx tamash-playwright doctor
|
|
|
88
105
|
It checks:
|
|
89
106
|
|
|
90
107
|
1. **AI connectivity** — confirms `HEALER_ENABLED`/`HEALER_PROVIDER` are set correctly and actually calls your configured provider to make sure the API key and model work.
|
|
91
|
-
2.
|
|
92
|
-
3. **
|
|
93
|
-
4. **
|
|
94
|
-
5. **
|
|
108
|
+
2. **`actionTimeout` configuration** — checks your `playwright.config.ts` for an `actionTimeout` set well below your test `timeout` (see above); flags it if missing or too close to the test timeout, since that silently starves self-healing of any time to run.
|
|
109
|
+
3. **Action recovery status** — whether `HEALER_ACTION_RECOVERY_ENABLED` is on (see below).
|
|
110
|
+
4. **Vision capability** — whether your configured model is expected to support the screenshot-based fallback (see below), based on its name.
|
|
111
|
+
5. **Missing `.describe()` labels** — scans your test files (`tests/` by default, or pass `--dir <path>`) for locators that don't have a `.describe('...')` label, and flags the ones most worth fixing (raw CSS/XPath selectors first).
|
|
112
|
+
6. **Locators written directly in test files** — flags any locator defined inline in a test rather than inside a Page Object class, which is a Playwright best practice regardless of self-healing: it keeps tests readable and means a UI change only needs a fix in one place.
|
|
95
113
|
|
|
96
114
|
If it finds issues, the fastest fix is to open the project in an AI coding assistant (Claude Code, Cursor, GitHub Copilot, etc.) and ask it to address what it flagged — add `.describe()` calls, or extract locators into Page Object classes. You can also add a standing rule to that assistant's instructions/skill file (e.g. `CLAUDE.md`, `.cursor/rules`, `.github/copilot-instructions.md`) so it follows both practices automatically on any new test code going forward.
|
|
97
115
|
|
package/dist/cli/doctor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAqJA,wBAAsB,SAAS,CAAC,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBlE"}
|
package/dist/cli/doctor.js
CHANGED
|
@@ -9,6 +9,7 @@ const dotenv_1 = __importDefault(require("dotenv"));
|
|
|
9
9
|
const providers_1 = require("../healer/providers");
|
|
10
10
|
const healer_1 = require("../healer");
|
|
11
11
|
const scanDescribe_1 = require("./scanDescribe");
|
|
12
|
+
const scanActionTimeout_1 = require("./scanActionTimeout");
|
|
12
13
|
dotenv_1.default.config({ path: path_1.default.resolve(process.cwd(), '.env') });
|
|
13
14
|
const CONNECTIVITY_TIMEOUT_MS = 15000;
|
|
14
15
|
const CONNECTIVITY_SNAPSHOT = '- generic "tamash-playwright doctor check":\n - button "OK"';
|
|
@@ -106,6 +107,31 @@ function checkPageObjectUsage(occurrences) {
|
|
|
106
107
|
console.log(' page.locator(...) calls). Tests then call page-object methods, not raw locators. This keeps');
|
|
107
108
|
console.log(' tests readable and means a UI change only needs a fix in one place.');
|
|
108
109
|
}
|
|
110
|
+
function checkActionTimeoutSetup() {
|
|
111
|
+
const result = (0, scanActionTimeout_1.checkActionTimeout)();
|
|
112
|
+
switch (result.status) {
|
|
113
|
+
case 'no_config':
|
|
114
|
+
console.log('[INFO] Could not find a playwright.config.(ts|js|mjs|cjs) in the current directory to check.');
|
|
115
|
+
console.log(' Make sure `actionTimeout` (inside `use: {...}`) is set well below your test `timeout` —');
|
|
116
|
+
console.log(' without it, a broken locator can retry silently for the entire test timeout, leaving no');
|
|
117
|
+
console.log(' time for self-healing to run at all.');
|
|
118
|
+
return;
|
|
119
|
+
case 'not_set':
|
|
120
|
+
console.log(`[WARN] No \`actionTimeout\` found in ${result.configFile}.`);
|
|
121
|
+
console.log(' Without it, Playwright lets a broken locator retry for your whole test timeout before');
|
|
122
|
+
console.log(' ever throwing — self-healing never gets a turn. Add this to your `use: {...}` block:');
|
|
123
|
+
console.log(' actionTimeout: 8000, // comfortably less than your test timeout');
|
|
124
|
+
return;
|
|
125
|
+
case 'too_close':
|
|
126
|
+
console.log(`[WARN] ${result.configFile} sets actionTimeout: ${result.actionTimeout} >= timeout: ${result.testTimeout}.`);
|
|
127
|
+
console.log(' actionTimeout must be well below the overall test timeout, or self-healing still won\'t');
|
|
128
|
+
console.log(' have any time left to run once an action fails.');
|
|
129
|
+
return;
|
|
130
|
+
case 'ok':
|
|
131
|
+
console.log(`[OK] ${result.configFile} sets actionTimeout: ${result.actionTimeout}ms — self-healing has room to run.`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
109
135
|
function parseTestDir(args) {
|
|
110
136
|
const flagIndex = args.indexOf('--dir');
|
|
111
137
|
const value = flagIndex !== -1 ? args[flagIndex + 1] : undefined;
|
|
@@ -115,6 +141,8 @@ async function runDoctor(args = []) {
|
|
|
115
141
|
console.log('tamash-playwright doctor\n');
|
|
116
142
|
await checkProviderConnectivity();
|
|
117
143
|
console.log('');
|
|
144
|
+
checkActionTimeoutSetup();
|
|
145
|
+
console.log('');
|
|
118
146
|
const testDir = parseTestDir(args);
|
|
119
147
|
const relativeDir = path_1.default.relative(process.cwd(), testDir) || testDir;
|
|
120
148
|
console.log(`Scanning ${relativeDir} for locators...`);
|
package/dist/cli/doctor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AACxB,oDAA4B;AAC5B,mDAAsD;AACtD,sCAAsE;AACtE,iDAA2E;
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ActionTimeoutCheck = {
|
|
2
|
+
status: 'no_config';
|
|
3
|
+
} | {
|
|
4
|
+
status: 'not_set';
|
|
5
|
+
configFile: string;
|
|
6
|
+
} | {
|
|
7
|
+
status: 'ok';
|
|
8
|
+
configFile: string;
|
|
9
|
+
actionTimeout: number;
|
|
10
|
+
} | {
|
|
11
|
+
status: 'too_close';
|
|
12
|
+
configFile: string;
|
|
13
|
+
actionTimeout: number;
|
|
14
|
+
testTimeout: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function checkActionTimeout(cwd?: string): ActionTimeoutCheck;
|
|
17
|
+
//# sourceMappingURL=scanActionTimeout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanActionTimeout.d.ts","sourceRoot":"","sources":["../../src/cli/scanActionTimeout.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAuB5F,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,kBAAkB,CAoBlF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkActionTimeout = checkActionTimeout;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const CONFIG_FILENAMES = ['playwright.config.ts', 'playwright.config.js', 'playwright.config.mjs', 'playwright.config.cjs'];
|
|
10
|
+
function findConfigFile(cwd) {
|
|
11
|
+
for (const name of CONFIG_FILENAMES) {
|
|
12
|
+
const full = path_1.default.join(cwd, name);
|
|
13
|
+
if (fs_1.default.existsSync(full))
|
|
14
|
+
return full;
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
// `\b` can't match inside "actionTimeout" right before "Timeout" (no non-word char between "n"
|
|
19
|
+
// and "T"), and the key itself is matched case-sensitively, so this can't accidentally pick up
|
|
20
|
+
// `actionTimeout: N` when scanning for the plain `timeout: N` key.
|
|
21
|
+
function extractNumber(content, key) {
|
|
22
|
+
const match = content.match(new RegExp(`\\b${key}\\s*:\\s*(\\d+)`));
|
|
23
|
+
return match ? Number(match[1]) : undefined;
|
|
24
|
+
}
|
|
25
|
+
// A plain regex scan over the config file's text, not a real parser — same "good enough for a
|
|
26
|
+
// human to review" philosophy as scanDescribe.ts. Exists to catch the single most common
|
|
27
|
+
// self-healing footgun: without an `actionTimeout` well below the test `timeout`, a broken locator
|
|
28
|
+
// can retry silently for the entire test timeout before ever throwing, leaving self-healing with
|
|
29
|
+
// no time left to run at all (see the `no_snapshot` failure stage in healer/index.ts).
|
|
30
|
+
function checkActionTimeout(cwd = process.cwd()) {
|
|
31
|
+
const configFile = findConfigFile(cwd);
|
|
32
|
+
if (!configFile) {
|
|
33
|
+
return { status: 'no_config' };
|
|
34
|
+
}
|
|
35
|
+
const content = fs_1.default.readFileSync(configFile, 'utf-8');
|
|
36
|
+
const relativeFile = path_1.default.relative(cwd, configFile);
|
|
37
|
+
const actionTimeout = extractNumber(content, 'actionTimeout');
|
|
38
|
+
if (actionTimeout === undefined) {
|
|
39
|
+
return { status: 'not_set', configFile: relativeFile };
|
|
40
|
+
}
|
|
41
|
+
const testTimeout = extractNumber(content, 'timeout');
|
|
42
|
+
if (testTimeout !== undefined && actionTimeout >= testTimeout) {
|
|
43
|
+
return { status: 'too_close', configFile: relativeFile, actionTimeout, testTimeout };
|
|
44
|
+
}
|
|
45
|
+
return { status: 'ok', configFile: relativeFile, actionTimeout };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=scanActionTimeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanActionTimeout.js","sourceRoot":"","sources":["../../src/cli/scanActionTimeout.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AAExB,MAAM,gBAAgB,GAAG,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,uBAAuB,CAAC,CAAC;AAQ5H,SAAS,cAAc,CAAC,GAAW;IACjC,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClC,IAAI,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACvC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,+FAA+F;AAC/F,+FAA+F;AAC/F,mEAAmE;AACnE,SAAS,aAAa,CAAC,OAAe,EAAE,GAAW;IACjD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9C,CAAC;AAED,8FAA8F;AAC9F,yFAAyF;AACzF,mGAAmG;AACnG,iGAAiG;AACjG,uFAAuF;AACvF,4BAAmC,GAAG,GAAW,OAAO,CAAC,GAAG,EAAE;IAC5D,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IACjC,CAAC;IAED,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,cAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAE9D,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACtD,IAAI,WAAW,KAAK,SAAS,IAAI,aAAa,IAAI,WAAW,EAAE,CAAC;QAC9D,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;IACvF,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;AACnE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamash-playwright",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Plug and Play Self-healing for Playwright and automatically recovers broken selectors using an AI model (Ollama, OpenAI, Anthropic, or Gemini).",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|